مضى على الشبكة و يوم من العطاء.

[4] Registers - Addresses - and Data Types

BEN10

./عضو نشيط
.:: كاتب تقني ::.

السمعة:

🌴بسم الله الرحمن الرحيم الحمد لله رب العالمين 🌴 🍃والصلاة والسلام على أشرف المرسلين


دلوقتي بعد ما فهمنا معماريه الكمبيوتر والمعالج بشكل عام محتاجين نفهم شوية عناصر أساسية في التجميع قبل ما نبدأ نتعلمها زي Registers, Memory Addresses, Address Endianness, and Data Types كل عنصر من دول مهم وفهمهم صح هيساعدنا نتجنب مشاكل وساعات من تصحيح الأخطاء وhحنا بنكتب كود التجميع ونعدل عليه

Registers

زي ما قلنا قبل كده كل نواة في المعالج بتكون فيها مجموعة من السجلات والسجلات دي أسرع مكونات في أي كمبيوتر لأنها متصنعة جوا نواة المعالج لكن حجمها محدود جداً ومش قادرة تخزن غير شوية بايتات من البيانات في وقت واحد فيه كتير من السجلات في بنية x86 لكن هنركز بس على السجلات الضرورية لتعلم أساسيات التجميع واللي هتفيدنا في استغلال الثغرات في المستقبل
فيه نوعين رئيسيين من السجلات اللي هنركز عليهم
: Data Registers and Pointer Registers
Data Registers
Pointer Registers
rax
rbp
rbx
rsp
rcx
rip
rdx
r8
r9
r10


سجلات البيانات (Data Registers) :

  • بتستخدم عاده لتخزين الأوامر (instructions) أو معطيات الدوال (syscall arguments)
  • أهم سجلات البيانات هي: rax, rbx, rcx, rdx.
  • كمان في rdi و rsi اللي بيتم استخدامهم عاده كمصدر ومقصد للأوامر - (destination)
  • لو السجلات السابقة كلها مشغولة ممكن نستخدم سجلات البيانات الثانوية: r8, r9, r10
سجلات المؤشرات (Pointer Registers):

  • بتستخدم لتخزين عناوين مهمة محددة
    • rbp (Base Stack Pointer): يشير لبداية المكدس (stack)
    • rsp (Current Stack Pointer): يشير للمكان الحالي داخل المكدس (أعلى المكدس)
    • rip (Instruction Pointer): يحمل عنوان الأمر التالي


Sub-Registers


كل سجل 64-بت ممكن يتقسم لأجزاء أصغر تحتوي على بتات أقل ممكن تكون بايت واحد 8-بت أو بايتين 16-بت أو أربع بايتات 32-بت كل جزء من السجل ممكن نستخدمه وندخله على حدة يعني مش محتاجين نستخدم كل 64-بت لو البيانات اللي عندنا أصغر من كده
register parts

ممكن نaccess الsub-registers بالشكل التالي
Size in bits
Size in bytes
Name
Example
16-bit
2 bytes
base name
ax
8-bit
1 bytes
base name and/or ends with L
al
32-bit
4 bytes
base name + starts with the e prefix
eax
64-bit
8 bytes
base name + starts with the r prefix
rax


مثلا بالنسبة ل register bx ال 16-bit هي bx و ال 8-bit هي bl و ال 32-bit هي ebx و ال 64-bit هي rbx و كمان بالنسبة ل register bp ال 16-bit هي bp و ال 8-bit هي bpl و ال 32-bit هي ebp و ال 64-bit هي rbp


1728463822031.webp




Memory Addresses

زي ما قولنا قبل كده البروسيسور x86 64-bit عنده عناوين بحجم 64-bit اللي بتتراوح من 0x0 لحد 0xffffffffffffffff يعني المفروض العناوين تكون في الرينج ده لكن الـRAM مقسمة لمناطق زي الـStack والـheap وأجزاء تانية بتبقى خاصة بالبرامج أو الكيرنل وكل منطقة في الذاكرة بيبقى ليها صلاحيات معينة زي القراءة والكتابة والتنفيذ اللي بتحدد إذا كنا نقدر نقرا منها أو نكتب فيها أو ننفذ عنوان فيها ولما الـInstruction تدخل في الـInstruction Cycle عشان تتنفذ أول خطوة بتكون إننا بنجيب الـInstruction من العنوان اللي هي موجودة فيه زي ما قولنا قبل كده وفي كذا نوع لـAddress fetching أو اللي بنسميه Addressing modes في الـx86 architecture

1728464020122.webp


زي ما قولنا في الجدول اللي فوق كل ما القيمة تكون أقل مباشرةً كل ما كانت أبطأ في الوصول ولما بنجي نتعلم الأساسيات في الـAssembly ممكن ما يكونش السرعة هي أولويتنا لكن مهم نفهم إزاي وفين بيتحدد كل عنوان عشان الفهم ده هيساعدنا في حاجات زي استغلال الثغرات اللي بتعتمد على Buffer Overflow مثلاً والفهم ده هيبقى ليه تأثير أكبر في استغلال الثغرات المتقدمة زي ROP أو استغلال الـHeap


Address Endianness

عنوان الـEndianness هو ترتيب البايتات لما بتتخزن أو بتتسحب من الذاكرة فيه نوعين من الـEndianness اللي هما Little-Endian وBig-Endian في الـLittle-Endian الماكينة بتخزن البايت الصغير الأول من اليمين للشمال وفي الـBig-Endian البايت الكبير بيتخزن الأول من الشمال لليمين

مثال لو عندنا العنوان 0x0011223344556677 وعايزين نخزنه في الذاكرة في الـLittle-Endian الماكينة هتحط البايت 0x00 على اليمين وبعدين تحط البايت 0x11 بعده فتبقى 0x1100 وبعدين تحط البايت 0x22 فتبقى 0x221100 وهكذا لحد ما يخلصوا البايتات في الآخر بيبقى العنوان معكوس 0x7766554433221100 ولما تسحب القيمة تاني الماكينة هتجيبها بنفس الـLittle-Endian عشان ترجع لنفس القيمة الأصلية

لو شوفنا مثال تاني في الباينري مثلاً لو عندنا عدد مكون من 2 بايت اللي هو 426 بالشكل الثنائي 00000001 10101010 طريقة تخزين البايتين دول ممكن تغير قيمته تخيل لو خزناه بالعكس 10101010 00000001 قيمته هتبقى 43521

الـBig-Endian بيخزن البايتات بالشكل الطبيعي من الشمال لليمين 00000001 10101010 لكن الـLittle-Endian بيخزنها بالعكس 10101010 00000001 اليمين للشمال ولما تيجي تسحب القيمة لازم تستخدم نفس الترتيب اللي اتخزنت بيه عشان تجيب القيمة الصح

اللي محتاجين نركز عليه إن البايتات بتتخزن في الذاكرة من اليمين للشمال يعني لو عايزين ندخل عنوان أو نص بلغة الـAssembly بنحتاج ندخله بالعكس لو عايزين نخزن كلمة Hello هتدخّلها كـo بعدين l بعدين l بعدين e وأخيراً H

وده ممكن يكون غريب شوية لأننا متعودين نقرا من الشمال لليمين بس ليه فوايد في معالجة البيانات زي إنك تقدر تجيب Sub-register من غير ما تمر على الريجيستر كله أو إنك تعمل عمليات حسابية بالترتيب المظبوط من اليمين للشمال


Data Types

أخيراً بنية x86 بتدعم أنواع كتير من أحجام البيانات اللي بنستخدمها مع تعليمات مختلفة الأنواع دي هي اللي هنستخدمها غالباً مع التعليمات
1728464398931.webp

لما بنستخدم متغير بنوع بيانات معين أو بنستخدم نوع بيانات مع تعليمة لازم الاتنين يكونوا بنفس الحجم

مثال على كده لو عندنا متغير متعرف إنه byte ماينفعش نستخدمه مع rax لأن rax حجمه 8 bytes في الحالة دي لازم نستخدم al اللي حجمه نفس حجم المتغير وهو 1 byte



1728464584743.webp


 
التعديل الأخير بواسطة المشرف:
بارك الله فيك حبيبي وجزاك الله كل خير
شرح رائع وبإنتظار جديد ابداعاتك دائماً
تحياتي
 
  • Love
التفاعلات: BEN10

آخر المشاركات

عودة
أعلى