السلام عليكم ورحمة الله تعالى وبركاته سنتحدث في هذه السلسلة عن لغة التجميع x86-64 ونقوم بحل تمارين عملية هذه المقالات مستخلصة من كورس MACC - FLARE Learning Hub الذي قمت بدراسته من فترة قصيرة اتمنى ان ينفعكم الله به.
1. التجميع وفك التجميع (Assembly and Disassembly)
لنبدأ بتعريف بعض المصطلحات التي ستتكرر كثيرًا في هذه الدورة:
كود التجميع (Assembly Code) — ويُشار إليه غالبًا بلغة التجميع أو اختصارًا بـ Assembly — هو التمثيل النصّي لشيفرة الآلة (Machine Code) التي ينفّذها المعالج. يُعد التجميع أعلى مستوى تمثيل للبرنامج يمكن استرجاعه بشكل موثوق دون الوصول إلى الشيفرة المصدرية الأصلية. وبينما تمتلك كل بنية حاسوبية (مثل x86 و ARM و MIPS) لغة تجميع خاصة بها، فإن المبادئ الأساسية التي ستتعلمها هنا في تحليل x86 وامتداده ذات 64-بت (x86-64) هي مبادئ عالمية.
فك التجميع (Disassembly) هو عملية ترجمة شيفرة الآلة الثنائية إلى كود تجميع. يقوم برنامج يُسمى “فاكك التجميع” (Disassembler) — مثل IDA Pro و Ghidra — بتحليل شيفرة الآلة وتوليد تعليمات التجميع المقابلة لها. تستخدم هذه التعليمات اختصارات تُسمى Mnemonic (مثل
MOVوADDوJMP) لجعل عمليات الآلة مقروءة للإنسان.فك الترجمة (Decompilation) هو عملية تحويل كود التجميع مرة أخرى إلى لغة برمجة عالية المستوى. وعلى عكس فك التجميع، فإن فك الترجمة لن يصل أبدًا إلى إعادة إنشاء الشيفرة المصدرية بشكل مثالي؛ ويعود ذلك إلى تحسينات المترجم (Compiler Optimizations) والفقدان الدائم للمعلومات الأصلية (مثل التعليقات وأسماء المتغيرات وتعريفات أنواع البيانات). وعلى الرغم من كونه تقريبًا “بأفضل جهد ممكن”، إلا أن مفكّكات الترجمة لا غنى عنها في الهندسة العكسية الحديثة لأنها تتيح للمحللين فهم سلوك البرنامج على مستوى تجريدي أعلى بكثير.
يوضّح الشكل 1.1 عمليات التجميع وفك التجميع وفك الترجمة:

الشكل 1.1: عملية التجميع وفك التجميع وفك الترجمة
- يوضّح النصف العلوي عملية التصريف (Compilation): يترجم المُصرِّف (Compiler) الشيفرة المصدرية المقروءة للإنسان إلى قائمة تجميع وسيطة (ASM File). ثم يحوّل المُجمِّع (Assembler) تلك الشيفرة الوسيطة إلى ملف كائن (Object File) يحتوي على شيفرة آلة ثنائية. وأخيرًا يحلّ الرابط (Linker) جميع المراجع الخارجية ويجمع بين عدة ملفات كائن ومكتبات في ملف تنفيذي نهائي واحد.
- يوضّح النصف السفلي عملية فك التجميع وفك الترجمة: كمهندسي عكس، نتلقى ملفًا تنفيذيًا مُصرَّفًا لتحليله. نستخدم فاكك التجميع لإنتاج قائمة تجميع من شيفرة الآلة، ثم نستفيد من مفكك الترجمة (Decompiler) لإجراء استعادة “بأفضل جهد” للشيفرة المصدرية عالية المستوى بناءً على ذلك التفكيك.
2. أنواع البيانات (Data Types)
لا تحتوي لغة التجميع على أنواع البيانات المعقدة التي قد تكون معتادًا عليها في لغات البرمجة عالية المستوى. بل تتعامل التجميع أساسًا مع: البايت (Byte) و الكلمة (Word) و الكلمة المزدوجة (Double Word) و الكلمة الرباعية (Quad Word)، ويبلغ طولها بايت واحد واثنين وأربعة وثمانية بايت على التوالي.
| نوع ويندوز | تعريف النوع في C | في التجميع (Asm) | الطول | المعنى |
|---|---|---|---|---|
BYTE | unsigned char | db | 1 | قيمة غير موقّعة بحجم 8 بت |
WORD | unsigned short | dw | 2 | قيمة غير موقّعة بحجم 16 بت |
DWORD | unsigned long | dd | 4 | قيمة غير موقّعة بحجم 32 بت |
QWORD | unsigned long long | dq | 8 | قيمة غير موقّعة بحجم 64 بت |
الجدول 1.1: أنواع البيانات الأساسية
في الجدول 1.1:
- يعرض العمود الأول الأسماء القياسية لأنواع البيانات في واجهة برمجة تطبيقات ويندوز (Windows API).
- يعرض العمود الثاني تعريف نوع البيانات المكافئ في لغة C.
- يعرض العمود الثالث الصيغة التي تستخدمها عادة قوائم لغة التجميع للدلالة على قيمة البيانات:
db— “define byte” (تعريف بايت)dw— “define word” (تعريف كلمة)dd— “define double-word” (تعريف كلمة مزدوجة)dq— “define quad-word” (تعريف كلمة رباعية)
3. سجلات x86 (x86 Registers)

الشكل 1.2: مجموعة السجلات الأساسية في x86
تمتلك بنية x86 ثمانية سجلات عامة الأغراض بحجم 32-بت: EAX و EBX و ECX و EDX و ESI و EDI و EBP و ESP. وبينما يمكن لمعظم التعليمات قبول هذه السجلات بالتبادل كمعاملات (Operands)، سنجد أن هناك اصطلاحات ضمنية تحدّد استخدامها (مثلًا: ESP مخصصة لإدارة المكدس، وغالبًا ما تُستخدم EAX لقيم إرجاع الدوال).
سجل EFLAGS هو سجل بحجم 32-بت يحتوي على مجموعة متنوعة من أعلام الحالة والتحكم. تعكس هذه الأعلام نتيجة العمليات الحسابية والمنطقية وكذلك حالة المعالج، وكل ذلك يؤثر بدوره في سلوك المعالج.
سجل EIP هو سجل بحجم 32-بت يخزّن عنوان الذاكرة للتعليمة التالية المراد تنفيذها. وعلى عكس السجلات العامة، لا يمكن تعديل EIP مباشرة؛ بل يتم تحديثه ضمنيًا بواسطة المعالج أثناء جلب التعليمات، أو صراحةً بواسطة تعليمات التحكم في التدفق.

الشكل 1.3: الوصول إلى السجلات الفرعية لـ EAX
تتيح بنية x86 للتعليمات الوصول إلى أجزاء محددة من السجلات العامة. وبأخذ EAX كمثال، يتم توزيع هذه الأجزاء كما يلي:
- كامل 32-بت:
EAX - الجزء السفلي 16-بت:
AX - 8-بت العالي/المنخفض: يُقسَّم الجزء السفلي 16-بت (
AX) إلى سجلين بحجم 8-بت:AH(البايت العالي) وAL(البايت المنخفض).
| 32-بت | 16-بت | 8-بت (عالي) | 8-بت (منخفض) |
|---|---|---|---|
EAX | AX | AH | AL |
EBX | BX | BH | BL |
ECX | CX | CH | CL |
EDX | DX | DH | DL |
ESI | SI | — | — |
EDI | DI | — | — |
EBP | BP | — | — |
ESP | SP | — | — |
الجدول 1.2: السجلات العامة الأغراض وسجلاتها الفرعية
كل هذه السجلات الفرعية تشير إلى نفس البتات الفعلية: تعديل AL يغيّر البايت الأقل أهمية في EAX. بالإضافة إلى ذلك، وكما هو مبيَّن في الجدول 1.2، وبينما تدعم جميع السجلات الثمانية العامة الوصول بحجم 16-بت، فإن السجلات الأربعة الأولى فقط (EAX و EBX و ECX و EDX) هي التي تدعم السجلات الفرعية H و L بحجم 8-بت.
4. أساسيات التعليمات (Instruction Basics)
تتكوّن التعليمة من رمز عملية (Opcode) ومعاملات (Operands) ذات صلة. ولكل تعليمة:
- الرمز (Opcode) هو تسلسل ثنائي يحدد العملية، مثل نقل البيانات أو جمع الأرقام أو استدعاء روتين فرعي. يشكّل الرمز ومعاملاته مجتمعين شيفرة الآلة (أو بايتات التعليمة).
- الاختصار (Mnemonic) هو اسم نصي مختصر للرمز، يوفر تمثيلًا مقروءًا للإنسان للتعليمة.
- المعاملات (Operands) هي وسائط التعليمات؛ فهي إما البيانات المصدر، أو وجهة النتيجة، أو كلاهما. تقبل التعليمات عددًا متغيرًا من المعاملات حسب العملية؛ فمعظمها يتطلب صفرًا أو معاملًا واحدًا أو معاملين، بينما تتطلب بعض التعليمات الحسابية ثلاثة معاملات.

الشكل 1.4: فاكك التجميع يترجم بايتات التعليمة إلى اختصار تعليمة ومعاملات
في المثال الوارد في الشكل 1.4، بايتات التعليمة هي B8 41 00 00 00، وفي التجميع تُترجم إلى التعليمة mov eax, 41h:
- البايت الأول
B8هو رمز عملية يعني “انقل قيمة ثابتة إلى سجل EAX”. - البايتات الأربعة المتبقية تُرمِّز معامل القيمة الثابتة. تخزّن x86 الأعداد الصحيحة بترتيب البايتات الصغير أولاً (Little-Endian)؛ لذلك، بالنسبة للقيمة الرباعية البايتات
00000041h، يظهر البايت41hأولًا في الذاكرة لأنه البايت الأقل أهمية.
لغة تجميع x86 لها صياغتان رئيسيتان: صياغة Intel و صياغة AT&T. يعتمد هذا المرجع على صياغة Intel التي تضع معامل الوجهة أولًا ومعامل المصدر ثانيًا.
| النوع | الوصف | أمثلة |
|---|---|---|
| فوري (Immediate) | القيمة هي المعامل نفسه | 8 ، 10h ، -123 ، 120 ، 'A' ، 'oleH' |
| سجل (Register) | القيمة مخزّنة في سجل | eax ، si ، ecx ، esp |
| ذاكرة (Memory) | المعامل إشارة إلى موقع الذاكرة الذي يحتوي على القيمة | [00020001] ، [ebp+08h] ، [eax+esi] ، [esp+ecx+50h] |
الجدول 1.3: الفئات الثلاث لمعاملات التعليمات
تنقسم معاملات التعليمات إلى ثلاث فئات: قيم فورية (ثوابت)، أو سجلات، أو معاملات ذاكرة:
- المعامل الفوري هو قيمة ثابتة تُرمَّز مباشرةً داخل التعليمة. وحسب السياق، تُفسَّر هذه القيمة كقيمة عددية موقّعة أو غير موقّعة أو كمحرف.
- معامل السجل يشير إلى محتويات سجل؛ ويقصد به عادة السجلات العامة الثمانية وسجلاتها الفرعية بحجم 16-بت أو 8-بت.
- معامل الذاكرة يشير إلى موقع محدد في الذاكرة ويُشار إليه بالأقواس المربعة
[]. وقد تحتوي الأقواس المربعة على تعبير حسابي يحدد عنوان الذاكرة النهائي (المُشار إليه بـ العنوان الفعال — Effective Address) المستخدم في العملية. وفي معظم الحالات، تكون البيانات في هذا العنوان هي المصدر أو الوجهة للتعليمة.
5. تعليمة MOV
تعليمتنا الأولى في x86 هي تعليمة MOV. تنقل MOV البيانات من معامل إلى آخر. يمكن أن يكون معامل المصدر قيمة فورية أو سجلًا أو عنوان ذاكرة، بينما يمكن أن يكون معامل الوجهة سجلًا أو عنوان ذاكرة. لكن انتبه: تعليمة MOV واحدة لا يمكنها نقل البيانات مباشرةً من عنوان ذاكرة إلى عنوان ذاكرة آخر؛ فلنقل البيانات بين موقعين في الذاكرة يجب أولًا نقل البيانات إلى سجل.
mov eax, 0FFh ; يضبط EAX = 0xFF
mov ebx, eax ; يحمّل القيمة المخزنة في EAX إلى EBX
القائمة 1.1: استخدام تعليمات MOV لتحميل البيانات في السجلات
في القائمة 1.1:
- تعليمة
MOVالأولى تنقل القيمة الفورية0xFFإلىEAX. - تعليمة
MOVالثانية تُحمّل القيمة الموجودة فيEAXإلىEBX. هذه العملية لا تعدّل القيمة فيEAX.
معظم ما تفعله البرامج هو نقل البيانات من مكان إلى آخر؛ ولهذا تُعد MOV من أكثر التعليمات شيوعًا التي ستجدها في أي برنامج x86.
اختبار سريع: MOVin’ on Up
ما قيمة السجلين
EAXوEBXبعد تنفيذ تسلسل التعليمات التالي؟
mov ebx, 0
mov eax, 42
mov ebx, eax
الحل (اضغط للعرض)
بعد التنفيذ: EAX = 42 و EBX = 42.
تُحمّل التعليمة الثانية القيمة 42 في EAX، ثم تنسخ التعليمة الثالثة قيمة EAX إلى EBX فتصبح قيمة كلٍّ من السجلين 42 (القيمة العشرية 42 = 2Ah بالنظام الست عشري).
6. تعليمة NOP
يرمز اسم التعليمة NOP إلى “لا عملية” (No Operation). عندما ينفّذ المعالج تعليمة NOP، فإنه لا يفعل شيئًا سوى تقديم مؤشر التعليمات إلى التعليمة التالية. ورغم أن تعليمة “لا تفعل شيئًا” قد تبدو عديمة الفائدة، إلا أنها تُستخدم بشكل ملائم في سيناريوهات عديدة، مثل الكتابة فوق التعليمات غير المرغوبة وإزالتها في البرنامج. تُرمَّز تعليمة NOP القياسية أحادية البايت بالقيمة 0x90، وهي رمز العملية الخاصة بـ XCHG EAX, EAX: فتبديل قيمة السجل بنفسه يعادل عمليًا عدم القيام بأي عملية.
7. اختراق التجميع باستخدام IDA (Hacking Assembly with IDA)
ملاحظة: هذا القسم عملي ويحتاج إلى بيئة IDA Pro مثبتة على جهاز افتراضي (يُنصح بـ FLARE-VM).
تبدأ جميع تمارين الاختراق (Hacking Exercises) ببرنامج blank.exe. يحتوي هذا البرنامج على منطقة كبيرة من تعليمات NOP جاهزة ليتم الكتابة فوقها بالتعليمات التي تحلّ كل تمرين.
ما لم يُذكر خلاف ذلك، ابدأ كل تمرين بتشغيل blank.i64 — وهو ملف قاعدة بيانات IDA (IDB) الخاص بـ blank.exe — ثم اضغط زر متابعة العملية (زر “التشغيل” الأخضر في الأعلى أو الاختصار F9) لبدء تنقيح البرنامج. إذا كان مسار blank.exe في جهازك الافتراضي مختلفًا عن موقعه الأصلي (C:\Users\flare\Desktop\MACC\Exercises\blank.exe)، فقد ترى رسالة خطأ تفيد بأن ملف الإدخال مفقود. إن حدث ذلك، فاضبط مساري Application و Input file ضمن Debugger ➔ Process options ليشيرا إلى موقع blank.exe.

الشكل 1.5: تخطيط وضع التنقيح الافتراضي في IDA
بمجرد دخول IDA إلى وضع التنقيح، سيتغير التخطيط ليشبه الشكل 1.5. ينقسم التخطيط إلى أربع مناطق رئيسية:
- فك التجميع (Disassembly): نافذة IDA View تعرض التعليمات المفكوكة. في التمارين الأولى، ستكون هذه النافذة محصورة في وضع النص (Text Mode) حيث تُدرج التعليمات خطيًا حسب عنوان الذاكرة. وعندما يكون مؤشرك داخل نطاق دالة معرّفة، يمكنك التبديل إلى وضع المخطط (Graph Mode) الذي ينظّم التعليمات في كتل أساسية (Basic Blocks) ويصوّر بصريًا تدفق التحكم بينها. هذه النافذة هي التي ستكتب فيها التعليمات لحل التمارين. يمكن فتحها من
View ➔ Open subviews ➔ Disassembly. - السجلات (Registers): نافذة General Registers تعرض الحالة الحالية لسجلات المعالج. أثناء توقف التنقيح (Paused)، يمكنك النقر بالزر الأيمن وتعديل قيمة أي سجل. يمكن فتحها من
Debugger ➔ Debugger windows ➔ General registers. - الذاكرة (Memory): نافذة Hex View تعرض الحالة الحالية للذاكرة. أثناء توقف التنقيح، يمكنك النقر بالزر الأيمن وتعديل الذاكرة. يمكن فتحها من
View ➔ Open subviews ➔ Hex dump. - المكدس (Stack): نافذة Stack View تعرض الحالة الحالية للمكدس. يمكنك تجاهل هذه النافذة في التمارين الأولى حتى نشرح المكدس بالتفصيل. يمكن فتحها من
Debugger ➔ Debugger windows ➔ Stack view.
لتجميع (كتابة) تعليمة، حدّد عنوان البداية في نافذة فك التجميع ثم انتقل إلى Edit ➔ Patch Program ➔ Assemble لإظهار نافذة المُجمِّع كما في الشكل 1.6. استخدم X86 Assembly Hacking Zine كمرجع مساعد.

الشكل 1.6: تجميع تعليمة عبر نافذة المجمّع في IDA
للتحقق من تعليماتك المجمَّعة أو تنقيحها، استخدم عمليات التنقيح التالية الموجودة في قائمة Debugger:
- الخطوة فوق (Step over) —
F8: تنفيذ التعليمة التالية ثم إيقاف التنقيح مؤقتًا. هذا مفيد لتتبع التعليمات وتحليلها واحدة تلو الأخرى. - إضافة نقطة توقف (Add breakpoint) —
F2: تفعيل/تعطيل نقطة توقف عند التعليمة الموجودة تحت المؤشر. يوقف التنقيح التنفيذ عند مصادفة نقطة توقف. لتنفيذ تسلسل من التعليمات، ضع نقطة توقف بعد آخر تعليمة في التسلسل مباشرةً ثم تابع العملية (F9). - ضبط IP (Set IP): انقر بالزر الأيمن على تعليمة واختر Set IP لإجبار مؤشر التعليمات على الانتقال إلى عنوان التعليمة المحددة. هذا مفيد لإعادة تعيين مؤشر التعليمات إلى نقطة سابقة في البرنامج.
لبدء تمرين جديد، أنهِ العملية عبر Debugger ➔ Terminate process (أو استخدم زر “الإيقاف” في شريط أدوات التنقيح)، ثم نفّذ أحد الخيارين:
- أغلق IDA (أو انتقل إلى
File ➔ Exit). اختر DON’T SAVE (عدم الحفظ) لقاعدة البيانات عند السؤال، ثم أعد فتحblank.i64. - انتقل إلى
Edit ➔ Patch program ➔ Patched bytes. تسرد هذه النافذة جميع التعديلات (Patches) التي أجريتها على قاعدة البيانات؛ حدّد جميع الإدخالات في القائمة واحذفها.
تمرين اختراق: movin_up
جمّع ونفّذ تعليمات اختبار “MOVin’ on Up” السريع السابق، وراقب تغيّر قيم السجلات بعد تنفيذ كل تعليمة.
mov ebx, 0
mov eax, 42
mov ebx, eax
8. تعليمات الحساب (Arithmetic Instructions)
| التعليمة | الوصف |
|---|---|
add <dest>, <src> | جمع <src> إلى <dest> وتخزين الناتج في <dest>. |
sub <dest>, <src> | طرح <src> من <dest> وتخزين الناتج في <dest>. |
inc <dest> | زيادة <dest> بمقدار 1. |
dec <dest> | إنقاص <dest> بمقدار 1. |
الجدول 1.4: تعليمات الحساب الأساسية
نستعرض أربع تعليمات حسابية أساسية:
- تعليمة
ADDتحسب مجموع المعاملين وتخزن الناتج في معامل الوجهة. - تعليمة
SUBتطرح المصدر من الوجهة وتخزن الناتج في معامل الوجهة. - تعليمتا
INCوDECتضيفان 1 إلى معامل الوجهة وتطرحان 1 منه على التوالي.
في كل تعليمة من هذه التعليمات، يجب أن يكون معامل الوجهة سجلًا أو موقعًا في الذاكرة.
9. تعليمات البت (Bitwise Instructions)
| التعليمة | الوصف |
|---|---|
xor <dest>, <src> | عملية XOR منطقية على البتات بين <src> و <dest> وتخزين الناتج في <dest>. |
and <dest>, <src> | عملية AND منطقية على البتات بين <src> و <dest> وتخزين الناتج في <dest>. |
or <dest>, <src> | عملية OR منطقية على البتات بين <src> و <dest> وتخزين الناتج في <dest>. |
shl <dest>, <amount> | إزاحة بتات <dest> يسارًا بمقدار <amount> بت، مع إضافة أصفار من اليمين، وتخزين الناتج في <dest>. |
shr <dest>, <amount> | إزاحة بتات <dest> يمينًا بمقدار <amount> بت، مع إضافة أصفار من اليسار، وتخزين الناتج في <dest>. |
rol <dest>, <amount> | تدوير بتات <dest> يسارًا بمقدار <amount> بت؛ البتات المفقودة من اليسار تُدرج من اليمين. |
ror <dest>, <amount> | تدوير بتات <dest> يمينًا بمقدار <amount> بت؛ البتات المفقودة من اليمين تُدرج من اليسار. |
الجدول 1.5: تعليمات البت الأساسية
تعمل تعليمات البت على البتات المفردة داخل المعامل:
- تنفّذ تعليمات
XORوANDوORعملياتها المنطقية التي تحمل أسماءها بين المعاملين وتخزن الناتج في معامل الوجهة. - تزيح تعليمات
SHLوSHRالبتات في معامل الوجهة يسارًا أو يمينًا، وتُملأ البتات الداخلة الجديدة بالأصفار. - تُدير تعليمات
ROLوRORالبتات في معامل الوجهة يسارًا أو يمينًا. وعلى عكس الإزاحة، تُلَفّ البتات التي تتجاوز الحد حول الطرف الآخر، مما يحافظ على البيانات.
تمرين اختراق: add_value
اكتب ونفّذ تسلسل تعليمات من أجل:
- تخزين القيمة
7في سجلEAX.- نسخ محتويات سجل
EAXإلىEBX.- زيادة سجل
EAXبمقدار 1 باستخدامINC.- جمع السجلين
EAXوEBXمعًا وتخزين الناتج فيEAX.
الحل (اضغط للعرض)
mov eax, 7
mov ebx, eax
inc eax
add eax, ebx ; الناتج: EAX = 15
10. الوصول إلى الذاكرة (Accessing Memory)
باستثناء تعليمة LEA (التي سنتناولها لاحقًا)، فإن أي معامل محاط بالأقواس المربعة [] يشير إلى وصول إلى الذاكرة.
عندما تصل تعليمة ما إلى الذاكرة، يجب أن يعرف المعالج حجم البيانات المطلوب قراءتها أو كتابتها. ويُحدَّد هذا الحجم بإحدى طريقتين:
- حجم مستنتَج (Inferred Size): إذا كان أحد المعاملات سجلًا، فإن حجم ذلك السجل يحدد حجم الوصول للذاكرة.
- حجم صريح (Explicit Size): إذا تعذّر استنتاج الحجم (مثلًا: المصدر قيمة ثابتة، أو أن للتعليمة معامل ذاكرة واحدًا فقط)، فستكون هناك حاجة إلى مُوجِّه حجم معامل (Operand-Size Directive).
في أدوات فك التجميع مثل IDA Pro، تتضمن مُوجِّهات حجم المعامل عادةً حجم البيانات متبوعًا بالكلمة ptr:
dword ptr: وصول بحجم كلمة مزدوجة (أربعة بايتات)word ptr: وصول بحجم كلمة (بايتان)byte ptr: وصول بحجم بايت (بايت واحد)
; انقل 4 بايتات من البيانات من العنوان 402000h إلى eax
mov eax, [402000h]
; انقل 2 بايت من البيانات من العنوان 402000h إلى ax
mov ax, [402000h]
; انقل القيمة الرباعية البايتات 0 إلى العنوان 402000h
mov dword ptr [402000h], 0
; انقل القيمة الرباعية البايتات الموجودة في ebx إلى العنوان 402000h
mov [402000h], ebx
القائمة 1.2: أمثلة على الوصول إلى الذاكرة باستخدام MOV
تعرض القائمة 1.2 تسلسلًا من أربع تعليمات MOV تصل إلى الذاكرة:
- تقرأ التعليمة الأولى أربعة بايتات من العنوان
402000hإلىEAX. فالحجم الرباعي البايتات لسجل الوجهةEAXيخبر المعالج بقراءة أربعة بايتات من402000h. - تقرأ التعليمة الثانية من العنوان نفسه، لكنها تقرأ بايتين فقط لأن معامل الوجهة سجل بحجم 16-بت (
AX). - تكتب التعليمة الثالثة الثابت
0إلى العنوان402000h. ولأن القيمة0يمكن نظريًا أن تتسع في بايت أو كلمة أو كلمة مزدوجة، فإن الحجم غامض؛ لذلك يخبر مُوجِّهdword ptrالمعالج صراحةً بكتابة قيمة رباعية البايتات (00000000h). - تكتب التعليمة الأخيرة محتويات
EBXإلى الذاكرة. لا حاجة إلى مُوجِّه لأن الحجم (أربعة بايتات) مستنتَج من سجلEBX.
تمرين اختراق: beef_inc
نصائح IDA لهذا التمرين:
- لتعديل الذاكرة في لوحة الذاكرة:
- اضغط
F2لبدء تحرير الذاكرة.- اضغط
F2مرة أخرى لتأكيد التعديلات بعد إتمامها.- لتحديد العناوين في نافذة المجمّع، ألحق حرف
hللنظام الست عشري (مثل401020h).ضع القيمة الـ 32-بت
0xDEADBEEFفي موقع الذاكرة401020h. اكتب ونفّذ تسلسل تعليمات من أجل:
- تحميل (MOV) قيمة DWORD الموجودة في العنوان
401020hإلىEAX.- زيادة (INC) القيمة في
EAXبمقدار 1.- وضع القيمة الناتجة من
EAXفي عنوان الذاكرة401020h.
الحل (اضغط للعرض)
mov eax, [401020h] ; EAX = 0xDEADBEEF
inc eax ; EAX = 0xDEADBEF0
mov [401020h], eax
تمرين اختراق: win
اكتب ونفّذ تسلسل تعليمات من أجل:
- تحميل أربعة بايتات من البيانات من عنوان الذاكرة
401020hإلى سجلEAX.- تنفيذ XOR لسجل
EAXمع القيمة0B1FEF9C7h. لإدخال أرقام تبدأ بالأحرف A-F في نافذة المجمّع، ضع0في البداية.- كتابة سجل
EAXالمعدَّل مرة أخرى إلى عنوان الذاكرة401020h.
الحل (اضغط للعرض)
mov eax, [401020h]
xor eax, 0B1FEF9C7h
mov [401020h], eax
11. معاملات الذاكرة (Memory Operands)
غالبًا ما يتضمن معامل الذاكرة عملية حسابية تُقيَّم لتعطي العنوان النهائي الذي يتم الوصول إليه. وفي مصطلحات x86، تُعرف هذه القيمة باسم العنوان الفعال (Effective Address).
يُحسب العنوان الفعال بجمع ثلاثة مكونات كحد أقصى:
- القاعدة (Base): سجل يحمل عنوان بداية.
- الفهرس والمقياس (Index & Scale): سجل فهرس مضروب في معامل قياس (1 أو 2 أو 4 أو 8).
- الإزاحة (Displacement): ثابت ثابت (Offset) يُضاف إلى المجموع؛ ويمكن أن تكون قيمته (بايت أو أربعة بايتات) موجبة أو سالبة.
يتبع القانون عمومًا هذا الهيكل:
العنوان الفعال = القاعدة + الفهرس × المقياس + الإزاحة
Effective Address = Base + Index × Scale + Displacement
; انقل 4 بايتات من البيانات من العنوان ebp+8 إلى eax
mov eax, [ebp+8]
; انقل 4 بايتات من البيانات من العنوان esp+ebx*4+8 إلى eax
mov eax, [esp+ebx*4+8]
القائمة 1.3: أمثلة على الوصول إلى الذاكرة باستخدام MOV مع حساب العنوان الفعال
توضح القائمة 1.3 نمطين شائعين للوصول إلى الذاكرة:
- تقرأ التعليمة الأولى من
[ebp+8]؛ والعنوان الفعال هو مجموع القاعدةEBPوإزاحة مقدارها 8. - تحسب التعليمة الثانية العنوان الفعال من مجموع: قاعدة
ESP، وفهرسEBXمضروب في مقياس 4، وإزاحة مقدارها 8. ويُشاهَد هذا النمط كثيرًا عند المرور على عناصر المصفوفات.
12. تعليمة LEA (Load Effective Address)
تعليمة LEA (lea <dest>, <src>) اختصار لعبارة Load Effective Address (تحميل العنوان الفعال). فهي تحسب العنوان الفعال لمعامل المصدر وتخزنه في معامل الوجهة.
تُستخدم LEA لغرضين رئيسيين:
- حسبان إزاحات الذاكرة، مثل إيجاد عنوان متغير محلي أو عنصر محدد من مصفوفة. في C/C++، هذا هو المكافئ المنطقي لمعامل “عنوان” (
&). - استخدامها من المترجمين لإجراء عمليات حسابية بسيطة بتعليمة واحدة بدلًا من تنفيذ سلسلة من التعليمات الحسابية.
على عكس MOV، فإن تعليمة LEA لا تصل إلى الذاكرة فعليًا. فعندما تصادف تعليمة LEA، يمكنك أن تتظاهر بغير وجود الأقواس المربعة و"تقوم بالحساب فقط" داخل الأقواس.
lea eax, [ebx+8] ; يضبط eax = ebx + 8
lea eax, [ebx*4+5] ; يضبط eax = ebx*4 + 5
lea eax, [ecx+ebx*4+5] ; يضبط eax = ecx + ebx*4 + 5
القائمة 1.4: حسبان العناوين الفعالة باستخدام تعليمة LEA
في كل تعليمة من تعليمات القائمة 1.4، تُحسب القيمة في سجل الوجهة بمجرد إجراء الحساب داخل الأقواس المربعة.
تمرين اختراق: beef_reader
نصائح IDA لهذا التمرين:
- لتعديل الذاكرة في لوحة الذاكرة:
- اضغط
F2لبدء تحرير الذاكرة.- اضغط
F2مرة أخرى لتأكيد التعديلات بعد إتمامها.- لتحديد العناوين في نافذة المجمّع، ألحق حرف
hللنظام الست عشري (مثل401020h).ضع القيمة الـ 32-بت
0xDEADBEEFفي موقع الذاكرة401020h. اكتب ونفّذ تسلسل تعليمات من أجل:
- تحميل عنوان الذاكرة
401020hفيEAX.- تحميل القيمة الـ 32-بت الموجودة في العنوان المخزّن في
EAXإلىEBX.- تحميل (باستخدام LEA) سجل
ECXبعنوان الذاكرةEAX + 2.- تحميل القيمة الـ 16-بت الموجودة في العنوان المخزّن في
ECXإلىDX.
الحل (اضغط للعرض)
mov eax, 401020h ; EAX يشير إلى العنوان 401020h
mov ebx, [eax] ; EBX = 0xDEADBEEF
lea ecx, [eax+2] ; ECX = 401022h
mov dx, [ecx] ; DX = 0xBEAD (الجزء السفلي 16-بت)
خلاصة المقال
في هذا الفصل تعلمنا الأساسيات التي يقوم عليها كل شيء لاحقًا في هذه الدورة:
| المفهوم | النقاط الرئيسية |
|---|---|
| التجميع وفك التجميع وفك الترجمة | التجميع أعلى تمثيل قابل للاستعادة؛ فك التجميع دقيق؛ فك الترجمة تقريبي |
| أنواع البيانات | BYTE (1) و WORD (2) و DWORD (4) و QWORD (8) |
| السجلات | 8 سجلات عامة 32-بت + EFLAGS + EIP مع سجلات فرعية (AX/AH/AL) |
| التعليمات | Opcode + Mnemonic + معاملات (فورية / سجل / ذاكرة) |
MOV | نقل البيانات؛ لا يمكن النقل مباشرة بين موقعين في الذاكرة |
NOP | لا عملية؛ يُستخدم للكتابة فوق التعليمات غير المرغوبة |
| الحساب والبت | ADD/SUB/INC/DEC و XOR/AND/OR/SHL/SHR/ROL/ROR |
| الذاكرة | الأقواس [] تعني وصول ذاكرة؛ استخدم dword ptr عند الغموض |
| العنوان الفعال | القاعدة + الفهرس × المقياس + الإزاحة |
LEA | يحسب العنوان الفعال دون الوصول للذاكرة؛ “قم بالحساب فقط” |
المصدر الأصلي: Malware Analysis Crash Course — FLARE Learning Hub