P01NT
0x7 07/10

تجميع x86-64 (x86-64 Assembly)

الانتقال إلى x86-64: السجلات الموسعة وfastcall ومساحة المنزل وNOP متعددة البايتات وMOVSX/MOVZX، ومعمل quizshow.

· 7 دقائق قراءة · 1473 كلمة
المحتويات

بسم الله الرحمن الرحيم

في هذا المقال سنتحدث عن أساسيات 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

الشكل 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]، وهكذا.

CAssembly
int addSixInts(int a, int b, int c,
              int d, int e, int f) {
  return a + b + c + d + e + f;
}


void main() {
  return addSixInts(1, 2, 3, 4, 5, 6);
}
main:
sub     rsp, 38h
mov     dword ptr [rsp+28h], 6
mov     dword ptr [rsp+20h], 5
mov     r9d, 4
mov     r8d, 3
mov     edx, 2
mov     ecx, 1
call    addSixInts
add     rsp, 38h
ret

القائمة 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.2 حالة المكدس مباشرةً قبل أن تُنشئ مقدمة الدالة إطار المكدس. مساحة المنزل تقع مباشرةً تحت عنوان الإرجاع، وتحت مساحة المنزل توجد الوسائط المخصصة على المكدس.

الشكل 8.3: حالة المكدس بعد مقدمة الدالة

الشكل 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 الذي يوفر بعض التسميات لبدء الاستخدام.

الأسئلة

  1. تمرر الدالة main موقع ذاكرة يحتوي على بيانات إلى sub_140001360 عند العنوان 0x1400011C5. ما نوع البيانات الموجودة في موقع الذاكرة هذا؟
  2. ادخل إلى الدالة sub_140001360. ما الدالة التي يبدو أنها تحدد ما إذا كانت إجابة سؤال المسابقة صحيحة؟
  3. كيف تسترد الدالة sub_140001360 سؤال المسابقة لطباعته إلى سطر الأوامر؟
  4. كيف تحدد الدالة sub_140001360 الترتيب الذي تُعرض به أسئلة المسابقة؟
  5. كيف يقيّم البرنامج ما إذا كانت إجابة سؤال المسابقة صحيحة؟
  6. أعد بناء البنية التي يستخدمها البرنامج لتمثيل زوج سؤال وإجابة المسابقة. تطبيق هذه البنية على جميع المواقع المناسبة في البرنامج حيث تُشار إلى البنية.

ملاحظة: الحل التفصيلي لهذا المعمل في درس حل معمل 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