TO DONATE : BTC => 1D8Aq4q2jQnvGD1GaK9vbNwKgm1K5zUEWL || PM => U4089661


اهم قوانين :1- منع الردود الباهتة مثل شكرااااا و أخواتها 2- لا يسمح بالمشاحنات الطائفية باآ شكل من الأشكال 3- عدم استعمال الألفاظ التافهة و الكلام البذىء 4- عدم وضع معرفات التواصل الأجتماعى بالردود 5- الأطلاع على كامل القوانين واجب 


العودة   الحماية للأبد -Security 4 Ever > قسم البرمجـــة > أساسيات لغة الأسمبلي

أساسيات لغة الأسمبلي يهتم بلغة الآلة (التجميع) Assembly و طرق بناء بعض أجزاء التطبيقات من خلالها

 
أدوات الموضوع انواع عرض الموضوع
  #1  
قديم 18-06-2019, 08:09 AM
الصورة الرمزية zero-cool
zero-cool
:: عضو خاص ::
 
حـالة التــواجـد : zero-cool غير متواجد حالياً
تاريخ التسجيل: Apr 2016
الجــــنــــــس: ذكـر
المشاركات: 74
شكراً:56
تم شكره 256 مرة في 59 مشاركة
معدل تقييم المستوى: 0
zero-cool بدون تقييم
افتراضي فهم المكدس


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



إن شاء الله تكونوا في تمام الصحة والعافية إخواني

يحتوي المكدس (الذي سنناقشه في هذه المقالة) على بنية LIFO
هذا يعني أن العنصر الأخير الذي تم وضعه على المكدس سيكون أول عنصر يتم بروزه.
إذن ما يسمى الجزء العلوي من المكدس ، هو في النهاية أدنى عنوان للمكدس
كل مازدنا قيم في المكدس ، كل ما انخفضت العناوين

البنية LIFO هي في نهاية المطاف مفيدة للغاية. في الواقع ، عند استدعاء وظيفة ،
يتم تكديس جميع البيانات اللازمة لتنفيذ الوظيفة ، وكذلك للعودة إلى الحالة الأولية.
بمجرد اكتمال الوظيفة ، من الضروري العودة إلى السطر الذي يتبع إستدعائها
ويتم ذلك عن طريق إزالة كل ما تم تكديسه مسبقًا ، مما يجعل بقية المكدس سليم وغيرها من stack frames

ويحتفظ المسجل ESP في الذاكرة بعنوان الجزء العلوي من المكدس (وبالتالي أدنى عنوان ، فكلما زاد حجم المكدس ، انخفضت العناوين الجديدة)
يتم تحديثه في كل مرة يتم فيها تغيير المكدس (إضافة قيمة أو حذف القيمة الأخيرة)
يحتفظ السجل EBP في الذاكرة بعنوان بداية ال stack frame
وبالتالي ، فإن ال stack frame الحالي هو بين العنوان الموجود في EBP والعنوان الموجود في ESP.

ناخذ هذا البرنامج

كود PHP:
#include <stdio.h>
 
int add(int xint yint z) {
     return 
x+y+z;
}
 
int main() {
    
int result;
    
result add(123);

نقوم بعملية الكومبايل ونفتحه مع ال gdb ونشوفو تعليمات الأسمبلي للوضيفة main

كود PHP:

root
@kali:~/stack# gcc prog.c -o prog
root@kali:~/stack# gdb -q prog
Reading symbols from prog...(no debugging symbols found)...done.
(
gdbset disassembly-flavor intel
(gdbdisass main
Dump of assembler code 
for function main:
   
0x000011b5 <+0>:    push   ebp
   0x000011b6 
<+1>:    mov    ebp,esp
   0x000011b8 
<+3>:    sub    esp,0x10
   0x000011bb 
<+6>:    call   0x11dd <__x86.get_pc_thunk.ax>
   
0x000011c0 <+11>:    add    eax,0x2e40
   0x000011c5 
<+16>:    push   0x3
   0x000011c7 
<+18>:    push   0x2
   0x000011c9 
<+20>:    push   0x1
   0x000011cb 
<+22>:    call   0x1199 <add>
   
0x000011d0 <+27>:    add    esp,0xc
   0x000011d3 
<+30>:    mov    DWORD PTR [ebp-0x4],eax
   0x000011d6 
<+33>:    mov    eax,0x0
   0x000011db 
<+38>:    leave  
   0x000011dc 
<+39>:    ret    
End of assembler dump
.
(
gdb


أولا نلاحظ العديد من الأشياء.
نشوف إستدعاء الوظيفة add في السطر +22 على العنوان 0x000011cb بالتعليمة call
ثم نلاحظ في الثلاثة أسطر إلي قبلها إضافة ثلاثة arguments للمكدس الذي سيتم إرسالهم للوظيفة add

حين نصل إلى الوظيفة add في السطر +22 نشوفو حالة المكدس


كود PHP:
(gdb) break *0x004011cb
Breakpoint 5 at 0x4011cb
(gdbrun
Starting program
: /root/stack/prog 

Breakpoint 5
0x004011cb in main ()
(
gdbx/8wx $esp
0xbffff35c
:    0x00000001    0x00000002    0x00000003    0x004011f9
0xbffff36c
:    0x00000000    0xb7fad000    0xb7fad000    0x00000000
(gdb
لقرائة هذه المعلومات:

كود PHP:
(gdbx/8wx $esp
0xbffff35c
:    0x00000001    0x00000002    0x00000003    0x004011f9
0xbffff36c
:    0x00000000    0xb7fad000    0xb7fad000    0x00000000 
أذكرك أن المكدس يكبر باتجاه العناوين المنخفظة من الذاكرة .
المسجل esp يشير إلى أعلى المكدس يعني إلى العنوان 0xbffff35c
وبما أننا نحظر لإستدعاء الوظيفة add فإن أعلى المكدس (يشير إليه ال esp) يتكون من arguments سيتم تمريرهم للوظيفة add

نشوفوا القيم 1 و 2 و 3
فلل arguments يتم تخزينهم في المكدس وبمجرد دخول البرنامج في الوظيفة سيكون عليه أن يتذكر من أين أتى
ولهذا ، سيتعين عليه تسجيل المسجل EIP(هو المسجل الذي يحتوي في الذاكرة على عنوان التعليمات الحالية)
ومع ذلك ، لا نرى تعليمة PUSH EIP في الكود .

في الواقع التعليمة call توافق تعليمتين:

كود PHP:
call <address
توافق

كود PHP:
PUSH EIP
JMP 
<adress
ونفس الشيئ التعليمة : RETURN توافق تعليمتين

كود PHP:
RET 
توافق

كود PHP:
POP EIP
JMP EIP 
إذا واصلنا التنفيذ بتعليمة للدخول وظيفة add يتم دفع قيمة EIP إلى المكدس ، ونحصل على:

كود PHP:
(gdbstepi
0x00401199 in add 
()
(
gdbx/8x $esp
0xbffff358
:    0x004011d0    0x00000001    0x00000002    0x00000003
0xbffff368
:    0x004011f9    0x00000000    0xb7fad000    0xb7fad000
(gdb
نرى العنوان 0x004011d0 يصل إلى أعلى المكدس.
وهذا العنوان يمثل عنوان التعليمة بعد تعليمة call في ال main
عند دخول الوظيفة ، يقوم المعالج بتسجيل التعليمات التالية التي يجب اتباعها بمجرد الخروج من الوظيفة التي دخلها للتو.
هذا كل شيء ، قمنا ب jump . نحن في التعليمة الأولى للوظيفة add()

لهذا ، كل وظيفة لديها ما يسمى مقدمة وخاتمة
تسمح مقدمة بحفظ معلومات الوظيفة المستدعية وحجز المساحة على المكدس الذي ستحتاجه الوظيفة ،
في حين أن الخاتمة تجعل من الممكن استعادة هذه المعلومات المحفوظة
حتى تتمكن الوظيفة المستدعية من استئناف عملها كما لو لم يحدث شيء.

نشوف كود الوظيفة add لنرى بتفصيل كيف يحدث هذا:

كود PHP:
(gdbdisas add
Dump of assembler code 
for function add:
=> 
0x00401199 <+0>:    push   ebp
   0x0040119a 
<+1>:    mov    ebp,esp
   0x0040119c 
<+3>:    call   0x4011dd <__x86.get_pc_thunk.ax>
   
0x004011a1 <+8>:    add    eax,0x2e5f
   0x004011a6 
<+13>:    mov    edx,DWORD PTR [ebp+0x8]
   
0x004011a9 <+16>:    mov    eax,DWORD PTR [ebp+0xc]
   
0x004011ac <+19>:    add    edx,eax
   0x004011ae 
<+21>:    mov    eax,DWORD PTR [ebp+0x10]
   
0x004011b1 <+24>:    add    eax,edx
   0x004011b3 
<+26>:    pop    ebp
   0x004011b4 
<+27>:    ret    
End of assembler dump

تقع مقدمة هذه الوظيفة على السطرين +0 و +1.

نرى بالترتيب أنه يتم دفع EBP إلى المكدس باستخدام PUSH EBP ، لحفظ المسجل EBP على المكدس ، وهو المسجل الذي يشير إلى بداية stack frame السابقة.
وفي السطر +1 يتم نسخ قيمة ل esp في ال ebp وفي هذه اللحظة ebp و esp يشيران إلى نفس المكان في الذاكرة.
هذا طبيعي ، لقد بدأنا للتو ال stack frame من الوظيفة المستدعية ، و لم تضع عليه أي شيء حتى الآن. لذلك فإن البداية والنهاية متطابقان.

علاوة على ذلك ، إذا نظرنا إلى تطور سجلات EPB و ESP بالإضافة إلى المكدس أثناء تنفيذ التعليمات الأولى للوظيفة add () نحصل على هذا:

كود PHP:
(gdbdisas add
Dump of assembler code 
for function add:
=> 
0x00401199 <+0>:    push   ebp
   0x0040119a 
<+1>:    mov    ebp,esp
   0x0040119c 
<+3>:    call   0x4011dd <__x86.get_pc_thunk.ax>
   
0x004011a1 <+8>:    add    eax,0x2e5f
   0x004011a6 
<+13>:    mov    edx,DWORD PTR [ebp+0x8]
   
0x004011a9 <+16>:    mov    eax,DWORD PTR [ebp+0xc]
   
0x004011ac <+19>:    add    edx,eax
   0x004011ae 
<+21>:    mov    eax,DWORD PTR [ebp+0x10]
   
0x004011b1 <+24>:    add    eax,edx
   0x004011b3 
<+26>:    pop    ebp
   0x004011b4 
<+27>:    ret    
End of assembler dump
.
(
gdbi r $ebp $esp
ebp            0xbffff378    0xbffff378
esp            0xbffff358    0xbffff358
(gdb) continue
Continuing.

Breakpoint 60x0040119c in add ()
(
gdbdisas add
Dump of assembler code 
for function add:
   
0x00401199 <+0>:    push   ebp
   0x0040119a 
<+1>:    mov    ebp,esp
=> 0x0040119c <+3>:    call   0x4011dd <__x86.get_pc_thunk.ax>
   
0x004011a1 <+8>:    add    eax,0x2e5f
   0x004011a6 
<+13>:    mov    edx,DWORD PTR [ebp+0x8]
   
0x004011a9 <+16>:    mov    eax,DWORD PTR [ebp+0xc]
   
0x004011ac <+19>:    add    edx,eax
   0x004011ae 
<+21>:    mov    eax,DWORD PTR [ebp+0x10]
   
0x004011b1 <+24>:    add    eax,edx
   0x004011b3 
<+26>:    pop    ebp
   0x004011b4 
<+27>:    ret    
End of assembler dump
.
(
gdbx/8xw $esp
0xbffff354
:    0xbffff378    0x004011d0    0x00000001    0x00000002
0xbffff364
:    0x00000003    0x004011f9    0x00000000    0xb7fad000
(gdbi r $ebp $esp
ebp            0xbffff354    0xbffff354
esp            0xbffff354    0xbffff354 
دعنا نأخذ هذا الكود خطوة بخطوة: نحن في بداية تعليمات الوظيفة add ، ونحن على استعداد لتنفيذ عملية push ebp
نرى أن ebp يحتوي على العنوان 0xbffff378 و esp يحتوي على 0xbffff358
ثم نتحرك إلى الأمام بتعليمين. ثم ننظر إلى ebp و esp. هم متساويان ، كما هو متوقع.
لقد دفعنا قيمة ebp القديمة إلى المكدس ، والتي تحولت من أعلى المكدس بمقدار 4 بايت
أعلى المكدس يساوي لذلك 4 - 0xbffff354 = 0xbffff358
ثم نعين esp ل ebp ف esp تساوي الآن 0xbffff354 و ebp تأخذ نفس القيمة
كما تبين آخر كومند في ال gdb

ثم لدينا بعض التعليمات التي تسمح بإجراء الحساب المطلوب
ثم نأتي إلى آخر سطرين ، وهما pop ebp و ret
تسمح الأولى من استبدال مؤشر EBP في بداية ال stack frame للوظيفة المستدعية
بينما تسمح الثانية ب pop EIP (وبالتالي إرجاع القيمة المحفوضة للمسجل EIP إلى المسجل EIP)
لاستئناف مسار التعليمة التي تأتي بعد استدعاء الوظيفة.

بالتوفيق لكم
 

 

 

مايفعله الهكرز هو معرفة التكنولوجيا وتجربتها بطرق لايمكن ان يتخيلها الكثير من الناس .
ولديهم رغبة قوية في مشاركة هذه المعلومات مع الآخرين
وتوضيحها للاشخاص الذي قد تكون مؤهلاتهم الوحيدة الرغبة في التعلم.

[email protected]
رد مع اقتباس
10 أعضاء قالوا شكراً لـ zero-cool على المشاركة المفيدة:
  #2  
قديم 19-06-2019, 11:10 PM
الصورة الرمزية Sec4ever
Sec4ever
الحماية للأبد
 
حـالة التــواجـد : Sec4ever غير متواجد حالياً
تاريخ التسجيل: Oct 2009
مكـان الإقامـة : الحماية للأبد
الجــــنــــــس: ذكـر
الــهـــوايـــــة: النـــــــــوم :)
المشاركات: 3,732
شكراً:3,272
تم شكره 5,005 مرة في 909 مشاركة
معدل تقييم المستوى: 10
Sec4ever تم تعطيل التقييم
افتراضي رد: فهم المكدس

بارك الله فيك و شرح رائع .  

 

 

My Adversary completes me,
to disrespect him is to disrespect myself,
thanks to his presence.
رد مع اقتباس
الأعضاء الذين قالوا شكراً لـ Sec4ever على المشاركة المفيدة:

الكلمات الدلالية (Tags)
المكدس, فهم


الذين يشاهدون محتوى الموضوع الآن : 1 ( الأعضاء 0 والزوار 1)
 
أدوات الموضوع
انواع عرض الموضوع

تعليمات المشاركة
لا تستطيع إضافة مواضيع جديدة
لا تستطيع الرد على المواضيع
لا تستطيع إرفاق ملفات
لا تستطيع تعديل مشاركاتك

BB code is متاحة
كود [IMG] متاحة
كود HTML معطلة

الانتقال السريع


الساعة الآن 12:54 AM