P01NT
0x00 الأساسيات 01/19

المراحل التي يمر بها الكود

المراحل الأربع لتحويل كود C إلى ملف تنفيذي — Preprocessor وCompiler وAssembler وLinker — وأثر كل مرحلة على شكل الـ binary.

· 3 دقائق قراءة · 449 كلمة
المحتويات

السلام عليكم ورحمة الله وبركاته.

هذه السلسلة ستغطي أساسيات لغة C المهمة لمجال الهندسة العكسية (Reverse Engineering). لن نتوسع في كل تفاصيل اللغة، بل في ما يهم من قراءة الـ disassembly وتحليل الـ binaries.

المراحل التي يمر بها كود لغة C

أولاً يكون لدينا الكود المصدر (Source Code) وهو الملف بامتداد .c وفيه الكود الذي كتبناه. هذا الكود يمر بأربع مراحل قبل أن ينفذ، ومن المهم جداً فهمها:

1. المعالجة المسبقة (Preprocessor)

في هذه المرحلة تتم عدة خطوات من أهمها:

  • إزالة التعليقات.
  • توسيع وحدات الماكرو (#define).
  • توسيع الملفات المضمنة (#include).
  • الترجمة الشرطية (#ifdef, #ifndef, #endif) — وهي شائعة جداً في الشيفرات الحقيقية وستصادفها كثيراً أثناء التحليل.

يكون الملف الناتج بامتداد .i.

2. المترجم (Compiler)

تقوم هذه المرحلة بتحويل الكود إلى لغة التجميع (Assembly)، ويكون الملف بامتداد .s.

نقطة مهمة لمجال RE: في هذه المرحلة تحديداً تُطبَّق تحسينات المترجم (O0/O1/O2/O3). هذه التحسينات تغيّر شكل الـ disassembly الناتج كلياً — فالكود المترجم بـ O0 يختلف جذرياً عن المترجم بـ O2. من الضروري أن تعرف أي مستوى تحسين استُخدم عند تحليل أي ملف.

3. المجمع (Assembler)

بهذه المرحلة يقوم المجمع بتحويل كود لغة التجميع إلى لغة الآلة (صفار وواحدات)، ويكون الملف بامتداد .o.

ملاحظة مهمة: هذا الملف هو object file قابل للنقل (relocatable) — أي أن العناوين داخله ليست نهائية بعد، والاستدعاءات ما زالت غير محلولة. وهذا هو السبب في وجود المرحلة الرابعة.

4. الرابط (Linker)

هذه المرحلة تقوم بما يلي:

  • دمج جميع ملفات .o معاً مع المكتبات.
  • ربط استدعاءات الوظائف بتعريفاتها.
  • حلّ العناوين النهائية.

نهايةً يكون الملف قابل للتنفيذ.

ملاحظة حسب نظام التشغيل: على ويندوز يكون الناتج PE بامتداد .exe، أما على لينكس فيكون ELF بدون امتداد (مثل a.out). هذا التمييز أساسي في الهندسة العكسية وسنفصّل فيه لاحقاً.

تمرين عملي

من المهم أن تتعلم كيف تُطبّق هذه الخطوات يدوياً وتشاهد الكود وهو يتغير من مرحلة لمرحلة. على لينكس باستخدام gcc:

gcc -E program.c -o program.i    # 1. المعالجة المسبقة
gcc -S program.i -o program.s    # 2. المترجم → Assembly
gcc -c program.s -o program.o    # 3. المجمع → Object file
gcc program.o -o program         # 4. الرابط → Executable

افحص محتوى كل ملف في كل مرحلة ولاحظ الفرق.

أداة مفيدة: Compiler Explorer (godbolt)

موقع godbolt.org يريك الـ assembly الناتج مباشرة أثناء كتابة الكود، مع إمكانية اختيار مستوى التحسين (O0/O2…). أداة لا غنى عنها لربط الكود المصدري بما يُنتجه المترجم.

لماذا يهم هذا في الهندسة العكسية؟

كل مرحلة من هذه المراحل تترك أثراً مفيداً للمحلل:

المرحلةالأثر الذي يهم المحلل
المعالجة المسبقةرؤية الكود بعد توسيع الماكرو وفهم البناء الحقيقي.
المترجمفهم تأثير التحسينات على شكل الـ assembly.
المجمعقراءة لغة الآلة والأوبكود.
الرابطفهم بنية الملف القابل للتنفيذ (PE/ELF) والاستدعاءات الخارجية (imports).

باختصار: فهم هذه المراحل الأربع هو حجر الأساس لقراءة أي ثنائي، وهو ما سنبني عليه بقية السلسلة بإذن الله.