مرحبًا مجددًا. في الدرس السابق فرّقنا بين البايتات الخام وبين تفسيرها كأعداد موقعة أو غير موقعة. الآن ننتقل من بايت واحد إلى قيمة مؤلفة من عدة بايتات، وهي لحظة ستتكرر كثيرًا عند فحص الذاكرة في x64dbg، أو قراءة حقول ملف PE، أو تحليل بيانات برنامج.
ستتعلم كيف تقرأ القيم متعددة البايتات وفق ترتيب Little-endian المستخدم عادةً على أجهزة Windows ذات معالجات x86 وx64. الفكرة المركزية بسيطة: في الذاكرة، يُخزَّن البايت الأقل أهمية أولًا عند العنوان الأصغر.
القيمة ليست ترتيبها في الذاكرة
خذ العدد ذي 32 بتًا التالي:
0x12345678
يمكن تقسيمه إلى أربعة بايتات:
| البايت | موقعه داخل القيمة المكتوبة |
|---|---|
12 | البايت الأعلى أهمية، MSB |
34 | البايت التالي |
56 | البايت التالي |
78 | البايت الأدنى أهمية، LSB |
نحن نكتب العدد عادةً من الأكثر أهمية إلى الأقل أهمية، تمامًا كما نكتب العدد العشري 512 بحيث تمثل 5 مئات و2 آحادًا. لكن الذاكرة لا تخزن عددًا كاملًا في خانة واحدة؛ بل تخزن بايتات متجاورة لكل منها عنوان مستقل.
إذا بدأ هذا العدد عند العنوان الافتراضي 0x00401000، فهناك طريقتان أساسيتان لترتيب البايتات:
| العنوان | Little-endian | Big-endian |
|---|---|---|
0x00401000 | 78 | 12 |
0x00401001 | 56 | 34 |
0x00401002 | 34 | 56 |
0x00401003 | 12 | 78 |
إذن، عندما تُخزّن قيمة 0x12345678 في ذاكرة جهاز Windows المعتاد، سترى غالبًا:
78 56 34 12
لكن هذه البايتات لا تمثل العدد 0x78563412 إذا كانت الأداة تقرؤها بوصفها قيمة 32 بت Little-endian؛ إنها ما تزال تمثل:
0x12345678
الخطأ الشائع هو النظر إلى صف البايتات وقراءته من اليسار إلى اليمين كأنه رقم Hex مكتوب للبشر. صف الذاكرة يعرض العناوين بترتيب تصاعدي، لا ترتيب أهمية البايتات داخل العدد.
ما المقصود بـ “الأقل أهمية” و“الأعلى أهمية”؟
في العدد:
0x12345678
كل زوج من رموز Hex هو بايت واحد. قوة كل بايت تتحدد بموقعه:
لذلك:
0x12هو Most Significant Byte أو البايت الأعلى أهمية، لأن تغييره يؤثر كثيرًا في القيمة الكلية.0x78هو Least Significant Byte أو البايت الأدنى أهمية، لأن قيمته تمثل خانة الآحاد على مستوى البايتات.
في ترتيب Little-endian، يبدأ التخزين بالبايت ذي الوزن الأصغر، 0x78. ثم تأتي البايتات الأعلى أهمية بالتدريج.
Little-endian لا يعكس البتات داخل كل بايت.
البايت0x78يبقى0x78، ولا يصبح0x1E. الذي يتغير فقط هو ترتيب البايتات الكاملة داخل القيمة متعددة البايتات.
شاهد هذا المقطع القصير من فيديو Endianness Explained لقناة Aaron Yoo. يعرض التمييز بين القيمة المكتوبة وتمثيلها في الذاكرة، وهو أساس تجنب سوء القراءة في المحللات والمصححات.
شاهد المقطع لفهم معنى البايت الأعلى والأدنى أهمية، ولماذا لا تكفي البايتات الخام وحدها لمعرفة القيمة من دون معرفة ترتيبها.
ابدأ من أهمية البايتات لترسيخ الفرق بين موضع البايت داخل العدد وموضعه في الذاكرة. ثم شاهد القيمة والترميز؛ ركز على أن تسلسل البايتات نفسه قد يُقرأ كقيمتين مختلفتين إذا لم يكن ترتيب البايتات محددًا.
قاعدة Little-endian العملية
عند قراءة بايتات من الذاكرة في Windows، اتبع هذه القاعدة:
أصغر عنوان يحتوي البايت الأدنى أهمية.
إذا قرأت أربعة بايتات متجاورة كما يلي:
العنوان البايت
0x00401000 78
0x00401001 56
0x00401002 34
0x00401003 12
فإن القراءة الصحيحة بوصفها عددًا 32 بت Little-endian هي:
0x12345678
لإعادة تركيب العدد يدويًا، اقرأ البايتات الثنائية بترتيب معاكس لعرض الذاكرة:
Memory bytes: 78 56 34 12
Value: 12 34 56 78
والصيغة العامة، إذا كانت البايتات في الذاكرة هي ، هي:
في مثالنا:
لا تحتاج عادةً إلى إجراء هذه العملية الحسابية كاملة يدويًا؛ يكفي أن تتعلم تجميع البايتات من الأخير إلى الأول عند قراءة قيمة Little-endian. لكن فهم الصيغة يجعلك تعرف لماذا تعمل القاعدة.

في الصورة، لا يتغير العدد المنطقي 0A0B0C0D. الذي يتغير هو مكان كل بايت في الذاكرة. على Windows، الشكل الموجود في جهة Little-endian هو الذي ستصادفه غالبًا عند فحص int أو عنوان أو ثابت عددي متعدد البايتات.
مثالان صغيران: 16 بت و32 بت
قيمة من 16 بت
لنفترض أن نافذة الذاكرة تعرض:
34 12
إذا فُسرت كبايتين Little-endian، فالقيمة هي:
0x1234
لأن:
34في العنوان الأصغر، وهو البايت الأدنى أهمية.12في العنوان التالي، وهو البايت الأعلى أهمية.
أما لو كان التنسيق Big-endian، فكان التسلسل نفسه يعني:
0x3412
قيمة من 32 بت
إذا ظهرت البايتات التالية:
EF BE AD DE
فقراءة Little-endian تعطي:
0xDEADBEEF
وهذا نمط شائع في الأمثلة التعليمية والتحليل منخفض المستوى. لا تقرأه كـ 0xEFBEADDE لمجرد أن هذه هي البايتات الظاهرة من اليسار إلى اليمين.
قاعدة تحقق سريعة:
| بايتات متجاورة في الذاكرة | القراءة الصحيحة كـ Little-endian |
|---|---|
01 00 | 0x0001 |
FF 00 | 0x00FF |
34 12 | 0x1234 |
78 56 34 12 | 0x12345678 |
EF BE AD DE | 0xDEADBEEF |
Little-endian لا يحدد إن كانت القيمة موقعة
ترتيب البايتات يجيب عن سؤال:
ما ترتيب تجميع البايتات في قيمة واحدة؟
أما التوقيع فيجيب عن سؤال مختلف:
هل نفس نمط البتات يمثل عددًا موجبًا فقط، أم عددًا موقّعًا بالمتمم الثنائي؟
خذ البايتات التالية:
00 80
عند قراءتها كقيمة 16 بت Little-endian، نعيد ترتيب البايتات منطقيًا:
0x8000
ثم نحدد نوع التفسير:
| التفسير بعد تطبيق Little-endian | القيمة |
|---|---|
غير موقعة uint16 | 32768 |
موقعة int16 بالمتمم الثنائي | -32768 |
إذًا الترتيب المنهجي هو:
- حدد حجم القيمة: بايتان، أربعة بايتات، أو ثمانية بايتات.
- حدد ترتيب البايتات وفق المعمارية أو مواصفة التنسيق.
- اجمع البايتات للحصول على النمط العددي.
- قرر هل يُفسر النمط كموقّع أو غير موقّع بناءً على نوع الحقل والسياق.
لا تقفز مباشرة من 00 80 إلى “هذه قيمة سالبة”. هي سالبة فقط إن كان البرنامج يعاملها كعدد موقّع من 16 بت.
لماذا يهم ذلك في التحليل العكسي؟
عند استخدام محرر Hex أو مصحح أخطاء، ترى الذاكرة غالبًا على هيئة صفوف بايتات ذات عناوين تصاعدية. لذلك قد يبدو عنوان أو عداد أو ثابت عددي “معكوسًا” في البداية.
مثلًا، إذا رأيت في ذاكرة عملية Windows:
A0 40 00 00 00 00 00 00
فهذا قد يمثل قيمة 64 بت Little-endian:
0x00000000000040A0
والصفران في النهاية المرئية ليسا “نهاية” القيمة؛ إنهما البايتات الأعلى أهمية المخزنة عند عناوين أعلى.
هذا مهم لاحقًا عند:
- قراءة قيمة متغير من نافذة الذاكرة في x64dbg.
- فهم المعاملات أو العناوين المخزنة على المكدس.
- تفسير حقول رقمية في ترويسات ملفات PE.
- تحليل كود آلة يحتوي على ثوابت فورية متعددة البايتات.
- مقارنة بايتات ملف مع قيمة يعرضها Ghidra أو المصحح.
لكن لا تفترض أن كل شيء في بيئة Windows هو Little-endian. ترتيب البايتات خاص بالتنسيق أو البروتوكول أيضًا، وليس فقط بالمعالج:
- الذاكرة المعتادة لمعالجات x86 وx64 تستخدم Little-endian.
- البايت المفرد لا يملك مشكلة ترتيب أصلًا.
- النص ASCII العادي سلسلة بايتات منفصلة، فلا نعكس أحرفه.
- بعض تنسيقات الشبكات تستخدم Network Byte Order، وهو Big-endian؛ يجب اتباع مواصفة البروتوكول لا افتراض ترتيب الذاكرة المحلي.
بما أن لديك معرفة أولية بالشبكات والبروتوكولات، احتفظ بالتمييز التالي: قد يستقبل برنامج Windows حقلًا شبكيًا بترتيب Big-endian، ثم يحوله داخليًا إلى القيمة المناسبة قبل استخدامها. لا يكفي أن تقول “Windows Little-endian” عند تحليل حزمة شبكة؛ مواصفة الحقل هي المرجع.
مختبر عملي: قراءة قيم Little-endian على Windows
خصص نحو 15 إلى 20 دقيقة لهذا المختبر داخل الآلة الافتراضية. لا تحتاج إلى ملف مشبوه أو برنامج خارجي؛ سننشئ بايتات معروفة ثم نطلب من Windows تفسيرها.
1. أنشئ بايتات قيمة 32 بت
افتح PowerShell ونفذ:
$le = [byte[]](0x78, 0x56, 0x34, 0x12)
[System.IO.File]::WriteAllBytes("$PWD\endian-demo.bin", $le)
Format-Hex .\endian-demo.bin
ينبغي أن ترى:
78 56 34 12
هذا هو التخزين Little-endian للقيمة:
0x12345678
2. اطلب من Windows قراءة البايتات كعدد 32 بت
نفذ:
$value = [BitConverter]::ToInt32($le, 0)
"Decimal: $value"
"Hex: 0x{0:X8}" -f $value
النتيجة المتوقعة:
Decimal: 305419896
Hex: 0x12345678
تستخدم BitConverter ترتيب البايتات الخاص بالجهاز الحالي. على Windows x64 المعتاد، سيقرأ هذه البايتات بوصفها Little-endian.
3. بدّل ترتيب البايتات واختبر النتيجة
نفذ الآن:
$opposite = [byte[]](0x12, 0x34, 0x56, 0x78)
$wrongForLittleEndian = [BitConverter]::ToInt32($opposite, 0)
"Decimal: $wrongForLittleEndian"
"Hex: 0x{0:X8}" -f $wrongForLittleEndian
ستحصل على:
Hex: 0x78563412
هذا يثبت أن BitConverter لم “يتعرف” على نيتك الأصلية بأن القيمة هي 0x12345678. هو قرأ البايتات الخام وفق ترتيب Little-endian الخاص بالنظام.
4. افحص الصورة الذهنية في محرر Hex
إذا كان لديك HxD، افتح endian-demo.bin. ستظهر البايتات حرفيًا:
78 56 34 12
ثم اختر أول بايت وافتح Data Inspector. غيّر تفسير القيمة إلى عدد صحيح بحجم 32 بت، وتأكد من تفعيل خيار Little endian.

المبدأ الذي يجب ملاحظته في HxD هو أن نفس موضع الملف أو الذاكرة يمكن عرضه كـ:
UInt16أوInt16UInt32أوInt32UInt64أوInt64- قيمة Little-endian أو Big-endian
هذه الخيارات لا تغير الملف وحدها؛ إنها تغير طريقة العرض والتفسير. لا تحفظ فوق ملف إلا عندما تكون متأكدًا تمامًا من البايتات التي تريد تعديلها.
قائمة فحص قبل تفسير أي قيمة
عند رؤية تسلسل بايتات في x64dbg أو HxD أو Ghidra، استخدم قائمة الفحص التالية:
- أين تبدأ القيمة؟ دوّن عنوان أول بايت أو إزاحته في الملف.
- ما طولها؟ هل هي 2 أو 4 أو 8 بايتات؟
- ما مصدرها؟ ذاكرة عملية Windows، حقل ملف، أم حزمة شبكة؟
- ما ترتيب البايتات الذي يحدده هذا المصدر؟ لا تفترضه بلا دليل.
- ما نوعها المحتمل؟ عدد موقّع، غير موقّع، عنوان، علم، أو جزء من بنية.
- هل النتيجة منطقية في السياق؟ قيمة مثل
0x78563412قد تعني أن الحجم أو الترتيب المختار خطأ.
صياغة ملاحظة تحليل جيدة تكون مثل:
Address: 0x00401000
Raw bytes: 78 56 34 12
Width: 32 bits
Byte order: Little-endian
Unsigned interpretation: 0x12345678 (305419896)
Signed interpretation: 305419896
Confidence: high; value read from Windows process memory.
هذه العادة تمنع خلط البايتات الخام بالقيمة المستنتجة منها، وتسمح لك بمراجعة استنتاجك لاحقًا.
الخلاصة
أهم ما ينبغي تثبيته من هذا الدرس:
- ترتيب البايتات يهم فقط للقيم التي تتكون من أكثر من بايت.
- في Little-endian، يُخزن البايت الأدنى أهمية عند العنوان الأصغر.
- القيمة
0x12345678تظهر في ذاكرة Windows عادةً كبايتات78 56 34 12. - لا يجري عكس البتات ولا رموز Hex المنفردة؛ بل يُعاد ترتيب مجموعات البايتات فقط عند تجميع القيمة.
- Little-endian مستقل عن كون العدد موقّعًا أو غير موقّع؛ حدد الترتيب أولًا، ثم نوع التفسير.
- ذاكرة Windows المعتادة Little-endian، لكن مواصفات الملفات والبروتوكولات قد تستخدم ترتيبًا آخر.
في الدرس التالي ستنتقل من الأعداد إلى المحتوى النصي: كيف تميّز نصوص ASCII وUnicode عن البيانات الخام عند النظر إلى ملف أو ذاكرة داخل محرر Hex.
Can't find a good explanation? Sign up and we'll make it for you
Sign up