بسم الله الرحمن الرحيم
في هذا المقال سنتحدث عن أساسيات x64 asm.
1. سجلات x86-64 الرئيسية (Primary X86-64 Registers)
بنية x86-64 (المعروفة أيضًا باسم AMD64 و x64) هي امتداد لبنية x86. وهي تُحدّث مجموعة السجلات بالطرق التالية:
- توسّع السجلات العامة الثمانية الموجودة إلى 64-بت وتعيد تسميتها بالبادئة
R:RAXوRBXوRCXوRDXوRSIوRDIوRBPوRSP. - تُقدم ثمانية سجلات عامة جديدة بحجم 64-بت مرقمة من
R8إلىR15. - توسّع مؤشر التعليمات إلى 64-بت (
RIP) وكذلك سجل الأعلام (RFLAGS).

الشكل 8.1: مجموعة السجلات الموسعة في x86-64
تمامًا كما في وضع 32-بت، يمكنك الوصول إلى الأجزاء السفلية من السجلات الموسعة بحجم 64-بت كأجزاء بحجم 32-بت (EAX) و 16-بت (AX) و 8-بت (AL/AH). أما السجلات العامة الجديدة (R8–R15) فتستخدم لواحق للدلالة على الحجم: 32-بت (R8D)، و 16-بت (R8W)، و 8-بت (R8B). لاحظ أنه على عكس RAX (التي لها AH)، فإن السجلات الجديدة لا تمتلك سجل بايت عالي قابلًا للعنونة.
2. اصطلاح الاستدعاء في x86-64: __fastcall
أحد الفروق المهمة بين التجميع ذي 32-بت و 64-بت على ويندوز هو اصطلاح الاستدعاء. على بنية x64، يستخدم مترجم Microsoft اصطلاح الاستدعاء __fastcall، الذي يستخدم السجلات لأول أربعة وسائط و المكدس لأي وسائط إضافية. تُمرر الوسائط الصحيحة الأربعة الأولى في السجلات:
RCX: الوسيط الأولRDX: الوسيط الثانيR8: الوسيط الثالثR9: الوسيط الرابع
توضع أي وسائط إضافية على المكدس في خانات مخصصة. تبدأ وسائط المكدس هذه عند الإزاحة 0x20 من مؤشر المكدس (RSP)، مباشرةً بعد منطقة بحجم 32-بايت تُعرف باسم مساحة المنزل (Home Space) — تُناقش في القسم التالي. وبناءً عليه، يوضع الوسيط الخامس عند [RSP+0x20]، والسادس عند [RSP+0x28]، وهكذا.
| C | Assembly |
|---|---|
| |
القائمة 8.1: اصطلاح الاستدعاء fastcall يمرر الوسائط الأربعة الأولى في السجلات
يوضح المثال في القائمة 8.1 اصطلاح الاستدعاء هذا:
- تستدعي
mainالدالةaddSixIntsلجمع ستة وسائط صحيحة. - تمرر التجميع الوسائط الأربعة الأولى في
RCXوRDXوR8وR9. ثم تمرر الوسيطين الخامس والسادس على المكدس عند الإزاحتين0x20و0x28نسبةً إلىRSP.
3. اصطلاحات المكدس وأطر الدوال في x86-64
فرق رئيسي بين التجميع ذي 32-بت و 64-بت على ويندوز هو إدارة المكدس. في برامج 64-بت، يُخصص إطار المكدس بالكامل أثناء مقدمة الدالة ويبقى ثابتًا حتى خاتمة الدالة. وعلى عكس دوال 32-بت — حيث ينمو المكدس ويتقلص مع دفع الوسائط وسحبها — تخصص دوال 64-بت كل المساحة اللازمة دفعًا واحدًا.
تُجري مقدمة الدالة تعديلًا واحدًا على المكدس (sub rsp, X) لحجز مساحة من أجل:
- السجلات غير المتطايرة (Non-Volatile Registers): سجلات يتوقع المستدعي بقاء قيمها محفوظة. قد تُدفع بعض هذه السجلات إلى المكدس في بداية المقدمة تمامًا.
- المتغيرات المحلية
- الوسائط الصادرة (Outgoing Arguments): خانات مكدس كافية لاستيعاب وسائط أي دالة تستدعيها هذه الدالة. يُحسب المترجم مسبقًا الحجم الأقصى المطلوب.
- مساحة المنزل (Home Space) — وتسمى أيضًا المساحة الظلية (Shadow Space) أو المخزن الظلي (Shadow Store)
لأن حجم المكدس ثابت، يبقى مؤشر المكدس (RSP) ثابتًا أثناء تنفيذ الدالة. وعنونة RSP-النسبية تُغني عن الحاجة إلى مؤشر إطار مخصص، مما يتيح استخدام RBP كسجل عام الأغراض.
مساحة المنزل هي منطقة بحجم 32-بايت يجب على المستدعي تخصيصها لاستخدامها من قبل الدالة المستدعاة:
- تتيح مساحة المنزل للدالة المستدعاة حفظ وسائط السجلات الأربعة الأولى على المكدس. ويُشار إلى هذا أيضًا باسم سكب الوسائط (Spilling) أو توطينها (Homing). يضمن سكب الوسائط قدرة المنقّح دائمًا على إيجادها، حتى لو كتبت الدالة فوق سجلات الوسائط. وهذه ليست مشكلة في برامج 32-بت لأن المعاملات تُمرر دائمًا على المكدس.
- في البرامج المحسَّنة المبنية بنمط Release، يمكن للدوال استخدام مساحة المنزل كمساحة عامة الأغراض بدلًا من سكب السجلات.
- مساحة المنزل تكاد تكون بلا تكلفة من حيث استخدام الذاكرة والأداء، لأن تعديل المكدس يُجرى مرة واحدة في مقدمة الدالة.

الشكل 8.2: حالة المكدس عند بداية مقدمة الدالة
يصور الشكل 8.2 حالة المكدس مباشرةً قبل أن تُنشئ مقدمة الدالة إطار المكدس. مساحة المنزل تقع مباشرةً تحت عنوان الإرجاع، وتحت مساحة المنزل توجد الوسائط المخصصة على المكدس.

الشكل 8.3: حالة المكدس بعد مقدمة الدالة
يصور الشكل 8.3 المكدس بعد مقدمة الدالة. تحفظ مقدمة الدالة على المكدس أي سجلات غير متطايرة تُستخدم أثناء الدالة. ثم تخصص المقدمة مساحة لاستيعاب المتغيرات المحلية للدالة، والحد الأقصى لعدد الوسائط المخصصة على المكدس، ومساحة المنزل. يبقى إطار المكدس ثابتًا في هذه الحالة حتى خاتمة الدالة.
4. تعليمات NOP متعددة البايتات (Multi-byte NOPs)
تعليمات NOP متعددة البايتات هي تحسين تجميع يُصادف كثيرًا في الملفات الثنائية ذات 64-بت. تعليمات NOP متعددة البايتات هي تسلسل بايتات يؤدي “لا عملية”، مطابقًا لتعليمة NOP أحادية البايت (0x90). وبينما توجد تعليمات NOP متعددة البايتات في x86 ذات 32-بت، تستخدمها مترجمات 64-بت بشكل أكثر عدوانية لمحاذاة الشيفرة إلى حدود بحجم 16-بايت. تعظّم هذه المحاذاة كفاءة الذاكرة المخبئية (Cache) بمحاذاة أهداف القفز مع خطوط ذاكرة التعليمات المخبئية للمعالج (التي تكون عادةً مضاعفات 16-بايت).
401000 75 0E jnz short loc_401010
401002 35 EF BE AD DE xor eax, 0DEADBEEFh
401007 05 CE FA ED FE add eax, 0FEEDFACEh
40100C 0F 1F 40 00 nop dword ptr [eax+00h]
401010 loc_401010:
401010 89 C2 mov edx, eax
القائمة 8.2: تعليمة NOP رباعية البايتات تحاذي وجهة قفزة إلى حد بحجم 16-بايت
على سبيل المثال، تُظهر القائمة 8.2 أن تعليمة NOP رباعية البايتات عند 0x40100C تحاذي التعليمة التالية — وهي هدف تعليمة قفز — إلى حد بحجم 16-بايت (0x401010).
5. تعليمتا MOVSX و MOVZX
تعليمتا MOVSX و MOVZX هي تعليمات MOV مع توسيع تعزز نوع بيانات أصغر إلى نوع بيانات أكبر. وهذه التعليمات أكثر تكرارًا في التجميع ذي 64-بت منها في 32-بت، لأن شيفرة 64-بت غالبًا ما تمزج أنواع بيانات بحجم 64-بت و 32-بت.
تحافظ تعليمتا MOVSX (نقل مع توسيع الإشارة — Move with Sign-Extension) و MOVSXD (نقل مع توسيع الإشارة لكلمة مزدوجة) على قيمة موقّعة عند نقل البيانات من مصدر إلى سجل وجهة أعرض، وذلك بملء البتات العليا ببت الإشارة (البت الأكثر أهمية).
mov ax, -5 ; تضبط ax = -5 (16 بت؛ FFFB)
movsx ebx, ax ; تضبط ebx = -5 (32 بت؛ FFFFFFFB)
movsxd rdx, ebx ; تضبط rdx = -5 (64 بت؛ FFFFFFFF`FFFFFFFB)
القائمة 8.3: نقل ثابت موقّع إلى سجل أكبر باستخدام MOVSX و MOVSXD
تستخدم القائمة 8.3 تعليمتي MOVSX و MOVSXD لنقل الثابت الموقّع -5 إلى سجل RDX. تعليمة MOV عادية تنقل 0xFFFB (الممثلة لـ -5 ككلمة) إلى RDX ستؤدي إلى احتواء السجل على القيمة العشرية 65,531 (000000000000FFFB`).
تعزز تعليمة MOVZX (نقل مع توسيع الصفر — Move with Zero-Extension) المصدر إلى سجل وجهة أعرض بملء البتات العليا بالأصفار. وهذا يحافظ على قيمة الأعداد الصحيحة غير الموقّعة.
mov ax, 0FFFBh ; تضبط ax = (16 بت؛ FFFB)
movzx ebx, ax ; تضبط ebx = (32 بت؛ 0000FFFB)
movzx rdx, ax ; تضبط rdx = (64 بت؛ 00000000`0000FFFB)
القائمة 8.4: نقل ثابت غير موقّع
تستخدم القائمة 8.4 تعليمة MOVZX لنقل القيمة 0xFFFB إلى RDX. لاحظ أن تعليمة MOVZXD غير موجودة، إذ أصبحت زائدة عن الحاجة بسبب حقيقة أنه في وضع 64-بت، تعليمة MOV التي تكتب إلى سجل بحجم 32-بت تُصفّر تلقائيًا البتات الـ 32 العليا من السجل المقابل بحجم 64-بت.
6. معمل — quizshow.exe (Lab - quizshow.exe)
معلومات العينة
- اسم الملف: quizshow.exe
- MD5:
fed60db5c7afbb8b0f016e0b2de06b93
أهداف المعمل
صُمم هذا المعمل لمساعدتك على الارتياح أكثر مع التفكيك ذي 64-بت ومفاهيم فك التجميع المتوسطة التالية:
- تعليمات السلاسل النصية (REP STOS/MOVS)
- المصفوفات
- التعرف على البنيات وإنشاؤها واستخدامها
هدف هذا المعمل هو الفوز في برنامج المسابقة، الذي يتكون من ستة أسئلة في معلومات الأفلام. حلّل الملف الثنائي لمعرفة كيفية الحصول على إجابة كل سؤال. ابدأ تحليلك بملف IDB المرفق quizshow.i64 الذي يوفر بعض التسميات لبدء الاستخدام.
الأسئلة
- تمرر الدالة
mainموقع ذاكرة يحتوي على بيانات إلىsub_140001360عند العنوان0x1400011C5. ما نوع البيانات الموجودة في موقع الذاكرة هذا؟ - ادخل إلى الدالة
sub_140001360. ما الدالة التي يبدو أنها تحدد ما إذا كانت إجابة سؤال المسابقة صحيحة؟ - كيف تسترد الدالة
sub_140001360سؤال المسابقة لطباعته إلى سطر الأوامر؟ - كيف تحدد الدالة
sub_140001360الترتيب الذي تُعرض به أسئلة المسابقة؟ - كيف يقيّم البرنامج ما إذا كانت إجابة سؤال المسابقة صحيحة؟
- أعد بناء البنية التي يستخدمها البرنامج لتمثيل زوج سؤال وإجابة المسابقة. تطبيق هذه البنية على جميع المواقع المناسبة في البرنامج حيث تُشار إلى البنية.
ملاحظة: الحل التفصيلي لهذا المعمل في درس حل معمل quizshow.
خلاصة المقال
| المفهوم | النقاط الرئيسية |
|---|---|
| السجلات الموسعة | 8 سجلات 64-بت (RAX…) + 8 جديدة (R8–R15) + RIP/RFLAGS |
| السجلات الجديدة R8-R15 | لواحق الحجم: R8D (32)، R8W (16)، R8B (8)؛ لا يوجد بايت عالي |
اصطلاح __fastcall | الوسائط الأربعة الأولى في RCX/RDX/R8/R9؛ الباقي على المكدس من [RSP+0x20] |
| إطار المكدس | يُخصص كاملاً في المقدمة ويبقى ثابتاً حتى الخاتمة |
RSP ثابت | عنونة RSP-نسبية؛ RBP يصبح سجلاً عاماً |
| مساحة المنزل (Shadow Space) | 32 بايت يخصصها المستدعي؛ لسحب وسائط السجلات الأربعة |
| NOP متعددة البايتات | لمحاذاة الشيفرة إلى حدود 16-بايت لتحسين الـ Cache |
MOVSX/MOVSXD | توسيع الإشارة للقيم الموقّعة (ملء ببت الإشارة) |
MOVZX | توسيع الصفر للقيم غير الموقعة؛ لا يوجد MOVZXD (MOV إلى 32-بت يصفّر الأعلى تلقائياً) |
المصدر الأصلي: Malware Analysis Crash Course — FLARE Learning Hub