নেটিভ মেশিন কোড কেন সহজেই বিচ্ছেদ করা যায় না?


16

জাভা, ভিবি.এনইটি, সি #, অ্যাকশনস্ক্রিপ্ট 3.0.০ ইত্যাদির মতো বাইটকোড-ভিত্তিক ভার্চুয়াল মেশিনের ভাষাগুলির সাথে আপনি কখনও কখনও শুনতে পান যে ইন্টারনেট থেকে কিছুটা ডিসপ্যাম্পিলার ডাউনলোড করা, এটির মাধ্যমে একটি ভাল সময় বাইটকোড চালানো কত সহজ is প্রায়শই, সেকেন্ডের ক্ষেত্রে মূল উত্স কোড থেকে খুব বেশি দূরে নয় এমন কিছু জিনিস নিয়ে আসুন। অনুমান করা যায় যে এই ধরণের ভাষা বিশেষভাবে এতে ঝুঁকিপূর্ণ।

আমি সম্প্রতি ভাবতে শুরু করেছি যে দেশীয় বাইনারি কোড সম্পর্কিত আপনি কেন এই বিষয়ে বেশি কিছু শুনছেন না, আপনি কমপক্ষে জানেন যে এটি কোন ভাষায় মূল ভাষায় লেখা হয়েছিল (এবং এইভাবে কোন ভাষায় বিভক্ত করার চেষ্টা করতে হবে)। দীর্ঘ সময়ের জন্য, আমি অনুভব করেছি এটি কেবল কারণ দেশীয় মেশিনের ভাষা সাধারণত বাইটকোডের চেয়ে অনেক বেশি ক্রেজিয়ার এবং আরও জটিল।

তবে বাইটকোড কেমন দেখাচ্ছে? দেখে মনে হচ্ছে:

1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2

এবং নেটিভ মেশিন কোডটি (হেক্সে) মতো দেখতে কেমন? এটি অবশ্যই এর মতো দেখাচ্ছে:

1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2

এবং নির্দেশাবলী কিছুটা একই মনের ফ্রেম থেকে আসে:

1000: mov EAX, 20
1001: mov EBX, loc1
1002: mul EAX, EBX
1003: push ECX

সুতরাং, কিছু দেশীয় বাইনারিগুলিকে বিভক্ত করার চেষ্টা করার জন্য ভাষাটি দেওয়া হয়েছে, সি ++ বলুন, এটি সম্পর্কে এত কঠিন কী? কেবলমাত্র দুটি ধারণা যা তাৎক্ষণিকভাবে মনে আসে তা হ'ল 1) এটি আসলে বাইটোকোডের চেয়ে অনেক বেশি জটিল বা 2) অপারেটিং সিস্টেমগুলি প্রোগ্রামগুলি পৃষ্ঠাতে ছড়িয়ে দেওয়ার এবং তাদের টুকরো টুকরো টুকরো করার প্রবণতা অনেকগুলি সমস্যার কারণ হয়ে দাঁড়ায়। যদি এই সম্ভাবনার মধ্যে একটি সঠিক হয়, দয়া করে ব্যাখ্যা করুন। তবে যেভাবেই হোক না কেন, আপনি কখনই মূলত এটি শুনেন না?

বিঃদ্রঃ

আমি একটি উত্তর গ্রহণ করতে চলেছি, তবে আমি প্রথমে কিছু উল্লেখ করতে চাই। প্রায় প্রত্যেকেই মূল বিষয়টির কোডের বিভিন্ন টুকরা একই মেশিন কোডে ম্যাপ করতে পারে এই বিষয়টি আবার উল্লেখ করছে; স্থানীয় ভেরিয়েবলের নামগুলি হারিয়ে গেছে, আপনি জানেন না মূলত কোন ধরণের লুপ ব্যবহৃত হয়েছিল ইত্যাদি etc.

তবে দু'জনের উদাহরণ যেমন সবেমাত্র উল্লেখ করা হয়েছে তা আমার দৃষ্টিতে তুচ্ছ ধরনের। উত্তরগুলির মধ্যে কিছু উত্তর দেয় যে মেশিন কোড এবং মূল উত্সের মধ্যে পার্থক্য এই তুচ্ছ কিছু থেকে মারাত্মকভাবে অনেক বেশি।

তবে উদাহরণস্বরূপ, যখন এটি স্থানীয় ভেরিয়েবলের নাম এবং লুপের ধরণের মতো হয়ে আসে তখন বাইটকোডও এই তথ্যটি হারাতে পারে (কমপক্ষে অ্যাকশনস্ক্রিপ্ট 3.0.০ এর জন্য)। আমি যে একটি decompiler মাধ্যমে কাপড় ফিরে সামনে টানা করেছি, এবং আমি সত্যিই গ্রাহ্য করা হয়নি কিনা একটি পরিবর্তনশীল বলা হয় strMyLocalString:Stringবা loc1। আমি এখনও সেই ছোট, স্থানীয় স্কোপগুলিতে সন্ধান করতে পারি এবং দেখতে পারি যে এটি কোনও সমস্যা ছাড়াই কীভাবে ব্যবহৃত হচ্ছে। এবং একটি forলুপ প্রায় অনেক একই একই জিনিসwhileলুপ, আপনি যদি এটি সম্পর্কে চিন্তা। এমনকি আমি যখন আইআরএফুসেটারের মাধ্যমে উত্সটি চালিত করব (যা সিকিউরএসডাব্লুএফএফ থেকে পৃথকভাবে সদস্যের পরিবর্তনশীল এবং ফাংশন নামগুলির তুলনায় বেশি কিছু করে না) তখনও দেখে মনে হচ্ছিল যে আপনি কিছু নির্দিষ্ট ভেরিয়েবল এবং ফাংশনকে ছোট শ্রেণিতে বিচ্ছিন্ন করতে শুরু করতে পারেন, চিত্র তারা কীভাবে ব্যবহৃত হচ্ছে তা খুঁজে বার করুন, তাদের নিজের নিজের নাম দিন এবং সেখান থেকে কাজ করুন।

এটি বড় বিষয় হওয়ার জন্য, মেশিন কোডটির চেয়ে আরও অনেক বেশি তথ্য হারাতে হবে এবং উত্তরগুলির মধ্যে কিছুটি এর মধ্যে চলে go


35
হ্যামবার্গারগুলির বাইরে গরু তৈরি করা কঠিন।
কাজ ড্রাগন

4
মূল বিষয়টি হ'ল একটি নেটিভ বাইনারি প্রোগ্রাম সম্পর্কে খুব কম মেটাডেটা ধরে রাখে। এটি ক্লাস সম্পর্কে কোনও তথ্য বজায় রাখে না (সি ++ বিশেষ করে ক্ষয় করা শক্ত করে তোলে) এবং ফাংশন সম্পর্কে সর্বদা এমনকি কিছু না - এটি প্রয়োজনীয় নয় যেহেতু সিপিইউ সহজাতভাবে মোটামুটি লিনিয়ার ফ্যাশনে কোডটি কার্যকর করে, এক সময় একটি নির্দেশনা। অতিরিক্তভাবে, কোড এবং ডেটা ( লিঙ্ক ) এর মধ্যে পার্থক্য করা অসম্ভব । আরও তথ্যের জন্য, আপনি আরইএসইতে অনুসন্ধান বা পুনরায় জিজ্ঞাসা বিবেচনা করতে পারেন ।
ntoskrnl

উত্তর:


39

সংকলনের প্রতিটি ধাপে আপনি এমন তথ্য হারাবেন যা অপরিশোধনযোগ্য নয়। আসল উত্স থেকে আপনি যত বেশি তথ্য হারাবেন, তা পচন করা ততই কঠিন।

আপনি বাইট-কোডের জন্য একটি দরকারী ডি-সংকলক তৈরি করতে পারেন কারণ চূড়ান্ত টার্গেট মেশিন কোড তৈরি করার সময় মূল উত্স থেকে অনেক বেশি তথ্য সংরক্ষণ করা হয়।

সংকলকটির প্রথম পদক্ষেপটি সাধারণত একটি গাছ হিসাবে প্রতিনিধিত্বকারী মধ্যবর্তী প্রতিনিধিত্বের জন্য উত্সকে কিছুতে পরিণত করা। Treeতিহ্যগতভাবে এই গাছটিতে মন্তব্য-শ্বেত-স্থান ইত্যাদির মতো অ-শব্দার্থবিজ্ঞান সম্পর্কিত তথ্য নেই this একবার এটিকে ফেলে দেওয়া হলে আপনি সেই গাছ থেকে মূল উত্সটি পুনরুদ্ধার করতে পারবেন না।

পরবর্তী পদক্ষেপটি গাছটিকে কিছুটা মধ্যবর্তী ভাষায় রেন্ডার করা যা অপ্টিমাইজেশনকে আরও সহজ করে তোলে। এখানে বেশ কয়েকটি পছন্দ রয়েছে এবং প্রতিটি সংকলকটির অবকাঠামোটির নিজস্ব রয়েছে। সাধারণত, তবে স্থানীয় ভেরিয়েবলের নাম, বৃহত্তর নিয়ন্ত্রণ প্রবাহ কাঠামো (যেমন আপনি লুপের জন্য ব্যবহার করেছিলেন কিনা) এর তথ্য হারিয়ে যায়। কিছু গুরুত্বপূর্ণ অপ্টিমাইজেশন সাধারণত এখানে ঘটে থাকে, ধ্রুবক প্রচার, ইনভারেন্টাল কোড গতি, ফাংশন ইনলাইনিং ইত্যাদি which যার প্রতিটি প্রতিনিধিত্বকে এমন একটি উপস্থাপনে রূপান্তর করে যার সমতুল্য কার্যকারিতা রয়েছে তবে এটি দেখতে আলাদা আলাদা দেখায়।

তারপরে একটি পদক্ষেপ হ'ল প্রকৃত মেশিন নির্দেশাবলী তৈরি করা যা এতে অন্তর্ভুক্ত হতে পারে যা "পীপ-হোল" অপ্টিমাইজেশন যা সাধারণ নির্দেশের ধরণের অনুকূলিত সংস্করণ উত্পাদন করে produce

প্রতিটি পদক্ষেপে আপনি যতক্ষণ না শেষ পর্যন্ত আরও বেশি বেশি তথ্য হারাবেন, আপনি এতটা হারাবেন যে আসল কোডটির সাথে সাদৃশ্যযুক্ত কোনও কিছুই পুনরুদ্ধার করা অসম্ভব হয়ে পড়ে।

অন্যদিকে, বাইট-কোড সাধারণত লক্ষ্য মেশিন কোড তৈরি হওয়ার পরে জেআইটি পর্ব (সুনির্দিষ্ট সংকলক) অবধি আকর্ষণীয় এবং রূপান্তরকারী অপ্টিমাইজেশন সংরক্ষণ করে। বাইট-কোডে অনেকগুলি মেটা-ডেটা থাকে যেমন স্থানীয় পরিবর্তনশীল ধরণ, শ্রেণি কাঠামো, একই বাইট-কোডটিকে একাধিক লক্ষ্য মেশিন কোডে সংকলিত করার অনুমতি দেয়। এই সমস্ত তথ্য সি ++ প্রোগ্রামে প্রয়োজনীয় নয় এবং সংকলন প্রক্রিয়াতে বাতিল করা হয়েছে।

বিভিন্ন টার্গেট মেশিন কোডগুলির জন্য ডিকম্পিলার রয়েছে তবে মূল উত্সের অনেকটাই হ্রাস হওয়ায় তারা প্রায়শই কার্যকর ফলাফল (এমন কিছু যা আপনি সংশোধন করতে পারেন এবং পুনরায় সংশোধন করতে পারেন) উত্পাদন করে না। এক্সিকিউটেবলের জন্য যদি আপনার ডিবাগ তথ্য থাকে তবে আপনি আরও ভাল কাজ করতে পারেন; তবে, আপনার যদি ডিবাগের তথ্য থাকে তবে সম্ভবত আপনারও মূল উত্স রয়েছে।


5
তথ্যটি যাতে রাখা হয় যাতে জেআইটি আরও ভালভাবে কাজ করতে পারে তা হ'ল মূল বিষয়।
btilly

তখন কি সি ++ ডিএলএলগুলি সহজেই দ্রবীভূত হতে পারে?
Panzercrisis

1
এমন কোনও কিছুর মধ্যে নয় যা আমি দরকারী বলে বিবেচনা করব।
চকজ

1
মেটাডেটা "একই বাইট-কোডকে একাধিক লক্ষ্যগুলিতে সংকলিত করার অনুমতি দেওয়ার জন্য নয়", এটি প্রতিফলনের জন্য রয়েছে। Retargetable মধ্যবর্তী প্রতিনিধিত্বের যে মেটাটাটা কোন প্রয়োজন নেই।
এসকে-যুক্তি

2
ওটা সত্যি না. প্রতিবিম্বের জন্য বেশিরভাগ ডেটা রয়েছে তবে প্রতিবিম্বটি একমাত্র ব্যবহার নয়। উদাহরণস্বরূপ, ইন্টারফেস এবং শ্রেণীর সংজ্ঞাগুলি লক্ষ্য মেশিনে ডিফাইন ফিল্ড অফসেট তৈরি করতে, ভার্চুয়াল টেবিলগুলি তৈরি করা ইত্যাদি ব্যবহার করে লক্ষ্য মেশিনের জন্য সবচেয়ে কার্যকর উপায়ে নির্মিত হতে পারে। এই টেবিলগুলি দেশীয় কোড তৈরি করার সময় সংকলক এবং / অথবা লিঙ্কার দ্বারা নির্মিত। এটি হয়ে গেলে, তাদের তৈরির জন্য ব্যবহৃত ডেটা ফেলে দেওয়া হয়।
চকজ

11

অন্যান্য উত্তর দ্বারা চিহ্নিত হিসাবে তথ্য হ'ল একটি পয়েন্ট, কিন্তু এটি চুক্তিভঙ্গকারী নয়। সর্বোপরি, আপনি আসল প্রোগ্রামটি ফিরে প্রত্যাশা করবেন না, আপনি কেবল উচ্চ-স্তরের ভাষায় কোনও উপস্থাপনা চান । কোডটি ইনলাইন করা থাকলে আপনি কেবল এটি হতে দিতে পারেন বা স্বয়ংক্রিয়ভাবে সাধারণ গণনাগুলি তৈরি করতে পারেন। আপনি নীতিগতভাবে অনেক অপ্টিমাইজেশন পূর্বাবস্থায় ফিরে যেতে পারেন। তবে কিছু অপারেশন রয়েছে যা নীতিগতভাবে অপরিবর্তনীয় (কমপক্ষে অন্তত অসীম পরিমাণে কম্পিউটিং ছাড়াই)।

উদাহরণস্বরূপ, শাখাগুলি গণিত জাম্পে পরিণত হতে পারে। এর মতো কোড:

select (x) {
case 1:
    // foo
    break;
case 2:
    // bar
    break;
}

সংকলিত হতে পারে (দুঃখিত যে এটি আসল সমাবেশকারী নয়):

0x1000:   jump to 0x1000 + 4*x
0x1004:   // foo
0x1008:   // bar
0x1012:   // qux

এখন, আপনি যদি জানেন যে এক্সটি 1 বা 2 হতে পারে তবে আপনি লাফের দিকে তাকান এবং এটিকে সহজেই বিপরীত করতে পারেন। তবে ঠিকানা 0x1012 সম্পর্কে কী? case 3আপনারও কি এটি তৈরি করতে হবে? কোন মানগুলি অনুমোদিত তা নির্ধারণ করার জন্য আপনাকে পুরো প্রোগ্রামটি সবচেয়ে খারাপ অবস্থায় সন্ধান করতে হবে। আরও খারাপ, আপনাকে ব্যবহারকারীর সমস্ত সম্ভাব্য ইনপুটগুলি বিবেচনা করতে হতে পারে! সমস্যার মূল বিষয়টি আপনি হ'ল ডেটা এবং নির্দেশাবলী আলাদা করে বলতে পারবেন না।

এটা বলা হচ্ছে যে, আমি পুরোপুরি হতাশাবোধ করব না। আপনি উপরের 'এসেম্বলারের' ক্ষেত্রে লক্ষ্য করে থাকতে পারেন, x যদি বাইরে থেকে আসে এবং 1 বা 2 হওয়ার গ্যারান্টি না থাকে তবে আপনার মূলত একটি খারাপ ত্রুটি রয়েছে যা আপনাকে যে কোনও জায়গায় যেতে পারে। তবে যদি আপনার প্রোগ্রামটি এই ধরণের বাগ থেকে মুক্ত হয় তবে এটি সম্পর্কে তর্ক করা খুব সহজ। (এটি কোনও দুর্ঘটনা নয় যে সিএলআর আইএল বা জাভা বাইটকোডের মতো "নিরাপদ" মধ্যবর্তী ভাষাগুলি ক্ষয় করা খুব সহজ, এমনকি মেটাডেটাও আলাদা করে রেখেছিল)) সুতরাং অনুশীলনে, কিছু নির্দিষ্ট, ভাল আচরণের বিশ্লেষণ করা সম্ভব হওয়া উচিতপ্রোগ্রাম। আমি স্বতন্ত্র, কার্যকরী শৈলীর রুটিনের কথা ভাবছি, যার কোনও পার্শ্ব প্রতিক্রিয়া এবং ভাল-সংজ্ঞায়িত ইনপুট নেই। আমি মনে করি চারপাশে এমন বেশ কয়েকটি ডিসকপিলার রয়েছে যা সাধারণ ফাংশনগুলির জন্য সিউডোকোড দিতে পারে, তবে এই জাতীয় সরঞ্জামগুলির সাথে আমার খুব বেশি অভিজ্ঞতা নেই।


9

মেশিন কোডটি মূল উত্স কোডে সহজে রূপান্তরিত হতে পারে না তার কারণ হ'ল সংকলনের সময় প্রচুর তথ্য নষ্ট হয়ে যায়। পদ্ধতি এবং অ-রফতানি ক্লাসগুলি ইনলাইন করা যায়, স্থানীয় ভেরিয়েবলের নামগুলি নষ্ট হয়ে যায়, ফাইলের নাম এবং কাঠামো সম্পূর্ণরূপে হারিয়ে যায়, সংকলকগুলি অ-স্পষ্টত অনুকূলকরণ করতে পারে ations আর একটি কারণ হ'ল একাধিক বিভিন্ন উত্স ফাইল হুবহু একই সমাবেশ তৈরি করতে পারে।

উদাহরণ স্বরূপ:

int DoSomething()
{
    return Add(5, 2);
}

int Add(int x, int y)
{
    return x + y;
}

int main()
{
    return DoSomething();
}

সংকলিত হতে পারে:

main:
mov eax, 7;
ret;

আমার সমাবেশটি বেশ মরিচাটে, তবে সংকলক যদি একটি অপ্টিমাইজেশন সঠিকভাবে করা যেতে পারে তা যাচাই করতে পারে, এটি তা করবে। এটি সংকলিত বাইনারিগুলির নামগুলি জানা প্রয়োজন নেই DoSomethingএবং Addসেইসাথে যে Addপদ্ধতিটির দুটি নামযুক্ত প্যারামিটার রয়েছে তার কারণে এটি ঘটে , সংকলকটিও জানে যে DoSomethingপদ্ধতিটি মূলত একটি ধ্রুবকটি দেয় এবং এটি পদ্ধতি কল এবং উভয় ক্ষেত্রেই ইনলাইন করতে পারে it পদ্ধতি নিজেই।

সংকলকটির উদ্দেশ্য একটি সমাবেশ তৈরি করা, উত্স ফাইলগুলি বান্ডিল করার কোনও উপায় নয়।


শেষ নির্দেশকে কেবলমাত্র পরিবর্তন করতে retএবং কেবলমাত্র আপনি সি কলিং কনভেনশনটি ধরে নিচ্ছেন বলে বিবেচনা করুন।
চকজ

3

এখানকার সাধারণ নীতিগুলি একাধিক এক ম্যাপিং এবং প্রচলিত প্রতিনিধিদের অভাব।

একাধিক টু ওয়ান প্রপঞ্চের একটি সাধারণ উদাহরণের জন্য আপনি যখন কিছু স্থানীয় ভেরিয়েবলের সাথে কোনও ফাংশন গ্রহণ করেন এবং মেশিন কোডে এটি সংকলন করেন তখন কী হয় তা সম্পর্কে আপনি ভাবতে পারেন। ভেরিয়েবল সম্পর্কে সমস্ত তথ্য হারিয়ে যায় কারণ সেগুলি কেবল মেমরির ঠিকানা হয়ে যায়। লুপগুলির জন্যও অনুরূপ কিছু ঘটে। আপনি একটি forবা whileলুপ নিতে পারেন এবং যদি সেগুলি ঠিক ঠিকঠাক করা থাকে তবে আপনি jumpনির্দেশাবলী সহ অভিন্ন মেশিন কোড পেতে পারেন ।

এটি মেশিন কোডের নির্দেশাবলীর জন্য মূল উত্স কোড থেকে আধ্যাত্মিক প্রতিনিধিদের অভাবও নিয়ে আসে। আপনি যখন লুপগুলি সংঘবদ্ধ করার চেষ্টা করবেন আপনি কীভাবে jumpনির্দেশগুলি লুপিং কনস্ট্রাক্টসে ফিরে যান? আপনি কি তাদের forলুপ বা whileলুপ তৈরি করেন?

আধুনিক সংকলকগণ বিভিন্ন ধরণের ভাঁজ এবং ইনলাইনিং সম্পাদন করে বিষয়টি আরও উদ্বেগজনক হয়। সুতরাং আপনি যখন মেশিন কোডে পৌঁছাবেন তখন নিম্ন স্তরের মেশিন কোডটি কোন উচ্চ স্তরের দ্বারা নির্ধারিত হয়েছে তা বলা খুব অসম্ভব।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.