P01NT
0x2 02/10

المكدس (The Stack)

بنية LIFO ومؤشر ESP وتعليمتا PUSH وPOP بأمثلة على المكدس الحي داخل التنقيح.

· 4 دقائق قراءة · 756 كلمة
المحتويات

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

في المقال السابق تحدثنا عن أساسيات x86 asm، وفي هذا الدرس سنكمل في الأساسيات وسنناقش سويًا المكدس.


1. المكدس (The Stack)

المكدس هو بنية بيانات من نوع LIFO (آخر يدخل، أولًا يخرج — Last In, First Out) تُيسّر تنفيذ البرامج. يعمل المكدس كمنطقة تخزين قصيرة المدى للدوال، حيث يدير تبادل البيانات بينها. وتشمل البيانات المخزنة على المكدس عادةً: المتغيرات المحلية للدالة، ووسائطها (Arguments)، وعنوان الإرجاع (Return Address).

يُعرِّف المكدس عمليتين أساسيتين:

  • PUSH تضع قيمة في قمة المكدس.
  • POP تزيل قيمة من قمة المكدس وتخزنها في موقع محدد (سجل أو موقع في الذاكرة).

الشكل 2.1: كومة من الأطباق

الشكل 2.1: كثيرًا ما يُقارن المكدس بكومة أطباق في بوفيه — الطريقة الوحيدة المقبولة اجتماعيًا لأخذ طبق أو وضع طبق هي من أعلى الكومة

تمتلك بنية x86 دعمًا مدمجًا للمكدسات وفق الاصطلاحات التالية:

  • ينمو المكدس صاعدًا من العناوين الموجودة في نهاية مقطع الذاكرة نحو العناوين الموجودة في بدايته (أي نحو العناوين الأقل).
  • تتتبع التعليمات المتعلقة بالمكدس قمة المكدس ضمنيًا باستخدام سجل ESP (مؤشر المكدس الممتد — Extended Stack Pointer).
  • تعليمات PUSH تُنقص ESP (محرّكة إياه إلى عنوان أقل) قبل كتابة البيانات، بينما تقرأ تعليمات POP البيانات ثم تزيد ESP (معادةً إياه إلى عنوان أعلى).

الشكل 2.2: مخطط المكدس التقليدي

الشكل 2.2: مخطط المكدس التقليدي مع نمو المكدس صاعدًا نحو العناوين الأقل

يوضّح الشكل 2.2 تخطيط المكدس. في هذا المخطط، ووفقًا للاصطلاح الشائع، توضع عناوين الذاكرة الأقل في الأعلى والعناوين الأعلى في الأسفل. وبينما ينمو المكدس نازلًا نحو العناوين الأقل، يُمثَّل بصريًا وكأنه يتمدد صاعدًا.


2. تعليمة PUSH

تنفّذ تعليمتا PUSH و POP العمليات الأساسية للمكدس. تأخذ تعليمة PUSH معاملًا واحدًا وتضعه في قمة المكدس وفق الخطوات التالية:

  1. إنقاص مؤشر المكدس (ESP) بمقدار 4 لتخصيص مساحة للعنصر الجديد.
  2. كتابة قيمة المعامل إلى موقع الذاكرة المشار إليه بـ ESP.

تعليمة PUSH X تعادل وظيفيًا التسلسل التالي:

sub esp, 4
mov [esp], X

الشكل 2.3: المكدس ومؤشر المكدس بعد دفع القيم 1 و2 و3

الشكل 2.3: حالة المكدس ومؤشر المكدس بعد دفع القيم 1 و 2 و 3

يوضّح الشكل 2.3 حالة المكدس بعد تنفيذ التسلسل التالي:

push 1
push 2
push 3

في الشكل 2.3، لاحظ ما يلي:

  • آخر قيمة دُفعت (3) هي التي في قمة المكدس.
  • يشير سجل ESP إلى أحدث قيمة دُفعت.
  • للإشارة إلى القيم التي دُفعت سابقًا، أضف إزاحات موجبة (+4 ، +8) إلى ESP.

3. تعليمة POP

تعليمة POP هي عكس تعليمة PUSH. تقبل POP معامل وجهة واحدًا، وتُحمّل قيمة من قمة المكدس إلى ذلك المعامل من خلال:

  1. قراءة القيمة الموجودة حاليًا في قمة المكدس (الموقع المشار إليه بـ ESP) إلى المعامل.
  2. زيادة ESP بمقدار 4 ليشير إلى العنصر التالي في المكدس؛ وهذا يزيل العنصر منطقيًا من المكدس.

تعليمة POP X تعادل وظيفيًا:

mov X, [esp]
add esp, 4

لنفترض أن حالة المكدس هي كما في الشكل 2.3، وننفّذ التسلسل التالي:

pop eax
pop ebx
pop ecx

سينتج عن ذلك قيم السجلات التالية:

  • EAX: 3
  • EBX: 2
  • ECX: 1

لاحظ أن القيم تُسحب من المكدس بترتيب عكسي لترتيب دفعها — وهذا هو جوهر مبدأ LIFO (آخر يدخل، أولًا يخرج).


4. تمارين اختراق

تمرين اختراق: pushpop

باستخدام تعليمات PUSH و POP فقط، اكتب ونفّذ تسلسل تعليمات من أجل:

  • تحميل القيم 1 و 2 و 3 في السجلات EAX و EBX و ECX على التوالي.
  • تبادل محتويات السجلين EAX و EBX باستخدام المكدس.

راقب تغيّر المكدس في لوحة المكدس (Stack Panel) الواقعة في الركن الأيمن السفلي من نافذة التنقيح في IDA أثناء تتبعك لبرنامجك خطوة بخطوة.

الحل (اضغط للعرض)
push 1
push 2
push 3
pop eax    ; EAX = 3
pop ebx    ; EBX = 2
pop ecx    ; ECX = 1
push eax
push ebx
pop eax    ; EAX = 2 (تم التبادل)
pop ebx    ; EBX = 3 (تم التبادل)

تمرين اختراق: stack_grab

اكتب ونفّذ تسلسل تعليمات من أجل:

  • باستخدام تعليمات PUSH، ادفع القيم 1 و 2 و 3 إلى المكدس.
  • باستخدام تعليمة MOV، انسخ القيمة 2 من المكدس إلى سجل EDX.
  • باستخدام تعليمة LEA، حمّل عنوان (مؤشر إلى) القيمة 1 على المكدس إلى سجل EBX.

نصيحة: استخدم صيغة الأقواس المربعة [ ] مع سجل ESP للوصول إلى مواقع المكدس (مثل [esp] أو [esp+4]).

الحل (اضغط للعرض)
push 1
push 2
push 3
mov edx, [esp+4]   ; EDX = 2 (القيمة الثانية من القمة)
lea ebx, [esp+8]   ; EBX = عنوان القيمة 1 على المكدس

خلاصة المقال

المفهومالنقاط الرئيسية
المكدسبنية LIFO للتخزين قصير المدى: متغيرات محلية، وسائط، عناوين إرجاع
ESPمؤشر المكدس؛ يشير دائمًا إلى قمة المكدس (أحدث قيمة)
PUSHإنقاص ESP بمقدار 4 ثم كتابة القيمة عند [esp]
POPقراءة القيمة من [esp] ثم زيادة ESP بمقدار 4
اتجاه النموالمكدس ينمو نحو العناوين الأقل، لكنه يُرسم متمددًا صاعدًا
الوصول للقيم السابقةإزاحات موجبة من ESP (مثل [esp+4] ، [esp+8])

المصدر الأصلي: Malware Analysis Crash Course — FLARE Learning Hub