فهم تنسيق ملف ELF

Understanding Elf File Format



من التعليمات البرمجية المصدر إلى التعليمات البرمجية الثنائية

تبدأ البرمجة بفكرة ذكية ، وكتابة الكود المصدري بلغة برمجة من اختيارك ، على سبيل المثال C ، وحفظ الكود المصدري في ملف. بمساعدة مترجم مناسب ، على سبيل المثال GCC ، يتم ترجمة كود المصدر الخاص بك إلى كود كائن أولاً. في النهاية ، يقوم الرابط بترجمة التعليمات البرمجية الهدف إلى ملف ثنائي يربط رمز الكائن بالمكتبات المشار إليها. يحتوي هذا الملف على التعليمات الفردية كرمز للآلة الذي تفهمه وحدة المعالجة المركزية ، ويتم تنفيذه بمجرد تشغيل البرنامج المترجم.

يتبع الملف الثنائي المذكور أعلاه بنية محددة ، وأحد أكثرها شيوعًا هو ELF الذي يختصر التنسيق القابل للتنفيذ والربط. يستخدم على نطاق واسع للملفات القابلة للتنفيذ وملفات الكائنات القابلة لإعادة تحديد الموقع والمكتبات المشتركة والتفريغ الأساسي.







منذ عشرين عامًا - في عام 1999 - اختار مشروع 86open ELF كتنسيق ملف ثنائي قياسي لأنظمة Unix والأنظمة الشبيهة بـ Unix على معالجات x86. لحسن الحظ ، تم توثيق تنسيق ELF مسبقًا في كل من الواجهة الثنائية لتطبيق النظام الخامس ، ومعيار واجهة الأداة [4]. هذه الحقيقة سهلت بشكل كبير الاتفاق على التوحيد بين مختلف البائعين والمطورين لأنظمة التشغيل المستندة إلى Unix.



كان السبب وراء هذا القرار هو تصميم ELF - المرونة وقابلية التوسع والدعم عبر الأنظمة الأساسية لمختلف التنسيقات الداخلية وأحجام العناوين. لا يقتصر تصميم ELF على معالج معين أو مجموعة تعليمات أو بنية أجهزة. للحصول على مقارنة تفصيلية بين تنسيقات الملفات القابلة للتنفيذ ، ألق نظرة هنا [3].



منذ ذلك الحين ، يتم استخدام تنسيق ELF من قبل العديد من أنظمة التشغيل المختلفة. من بين أمور أخرى ، يتضمن ذلك Linux و Solaris / Illumos و Free- و Net- و OpenBSD و QNX و BeOS / Haiku و Fuchsia OS [2]. علاوة على ذلك ، ستجده على الأجهزة المحمولة التي تعمل بنظام Android أو Maemo أو Meego OS / Sailfish OS وكذلك على وحدات التحكم في الألعاب مثل PlayStation Portable و Dreamcast و Wii.





لا توضح المواصفات امتداد اسم الملف لملفات ELF. قيد الاستخدام مجموعة متنوعة من مجموعات الحروف ، مثل .axf ، .bin ، .elf ، .o ، .prx ، .puff ، .ko ، .so ، و .mod ، أو لا شيء.

هيكل ملف ELF

في محطة Linux ، يمنحك command man elf ملخصًا مفيدًا حول بنية ملف ELF:



قائمة 1: manpage لهيكل ELF

$ رجل أحد عشر

ELF (5) دليل مبرمج Linux ELF (5)

اسم
elf - تنسيق الملفات التنفيذية وربط التنسيق (ELF)

الخلاصة
#يشمل

وصف
يحدد ملف الرأس تنسيق ملف ثنائي ELF القابل للتنفيذ
الملفات. من بين هذه الملفات ملفات عادية قابلة للتنفيذ ، قابلة للنقل
ملفات الكائنات والملفات الأساسية والمكتبات المشتركة.

يتكون الملف القابل للتنفيذ باستخدام تنسيق ملف ELF من رأس ELF ،
متبوعًا بجدول رأس البرنامج أو جدول رأس القسم أو كليهما.
يكون رأس ELF دائمًا عند الإزاحة الصفرية للملف. البرنامج
جدول الرأس وإزاحة جدول رأس القسم في الملف هي
المحددة في رأس ELF. يصف الجدولان بقية
خصوصيات الملف.

...

كما ترى من الوصف أعلاه ، يتكون ملف ELF من قسمين - رأس ELF وبيانات الملف. يمكن أن يتكون قسم بيانات الملف من جدول رأس البرنامج الذي يصف صفرًا أو أكثر من الأجزاء ، وجدول رأس القسم الذي يصف صفرًا أو أكثر من الأقسام ، متبوعًا بالبيانات المشار إليها بإدخالات من جدول رأس البرنامج ، وجدول رأس القسم. يحتوي كل مقطع على معلومات ضرورية لتنفيذ وقت التشغيل للملف ، بينما تحتوي الأقسام على بيانات مهمة للربط وإعادة التوطين. يوضح الشكل 1 هذا بشكل تخطيطي.

رأس ELF

يبلغ طول رأس ELF 32 بايت ، ويحدد تنسيق الملف. يبدأ بتسلسل من أربعة بايتات فريدة هي 0x7F متبوعًا بـ 0x45 و 0x4c و 0x46 والتي تُترجم إلى الأحرف الثلاثة E و L و F. من بين القيم الأخرى ، يشير الرأس أيضًا إلى ما إذا كان ملف ELF لـ 32 أو يُظهر تنسيق 64 بت ، الذي يستخدم قليلًا أو كبيرًا ، إصدار ELF بالإضافة إلى نظام التشغيل الذي تم تجميع الملف من أجله من أجل التعامل مع واجهة التطبيق الثنائية الصحيحة (ABI) ومجموعة تعليمات وحدة المعالجة المركزية.

يبدو التفريغ السداسي للمس الملف الثنائي كما يلي:

القائمة 2: التفريغ السداسي للملف الثنائي

$ hd / usr / bin / touch | الرأس -5
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | .ELF ........... |
00000010 02 00 3e 00 01 00 00 00 e3 25 40 00 00 00 00 00 | ..> ......٪ @ ..... |
00000020 40 00 00 00 00 00 00 00 28 e4 00 00 00 00 00 00 | @ ....... (....... |
00000030 00 00 00 00 40 00 38 00 09 00 40 00 1b 00 1a 00 | [بريد إلكتروني محمي] @ ..... |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 | [بريد إلكتروني محمي] |

يقدم Debian GNU / Linux الأمر readelf الذي يتم توفيره في حزمة GNU 'binutils'. مصحوبًا بالمفتاح -h (إصدار قصير لـ -file-header) يعرض بشكل جيد رأس ملف ELF. القائمة 3 توضح هذا للمس الأمر.

القائمة 3: عرض رأس ملف ELF

readelf -h / usr / bin / touch
رأس ELF:
السحر: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
الفئة: ELF64
البيانات: 2's مكمل ، صغير Endian
الإصدار: 1 (current)
OS / ABI: UNIX - النظام الخامس
إصدار ABI: 0
النوع: EXEC (ملف قابل للتنفيذ)
الجهاز: Advanced Micro Devices X86-64
الإصدار: 0x1.0
عنوان نقطة الإدخال: 0x4025e3
بداية رؤوس البرنامج: 64 (بايت في الملف)
بداية رؤوس الأقسام: 58408 (بايت في الملف)
الأعلام: 0x0
حجم هذا الرأس: 64 (بايت)
حجم رؤوس البرنامج: 56 (بايت)
عدد رؤوس البرامج: 9
حجم رؤوس الأقسام: 64 (بايت)
عدد رؤوس الأقسام: 27
فهرس جدول سلسلة عنوان القسم: 26

رأس البرنامج

يعرض عنوان البرنامج المقاطع المستخدمة في وقت التشغيل ، ويخبر النظام بكيفية إنشاء صورة عملية. يوضح العنوان من القائمة 2 أن ملف ELF يتكون من 9 رؤوس برامج يبلغ حجم كل منها 56 بايت ، ويبدأ الرأس الأول عند 64 بايت.

مرة أخرى ، يساعد الأمر readelf في استخراج المعلومات من ملف ELF. يكشف رمز التبديل -l (اختصار لـ 'رؤوس البرامج' أو 'المقاطع') عن مزيد من التفاصيل كما هو موضح في القائمة 4.

القائمة 4: عرض معلومات حول رؤوس البرامج

$ readelf -l / usr / bin / touch

نوع ملف Elf هو EXEC (ملف قابل للتنفيذ)
نقطة الدخول 0x4025e3
يوجد 9 رؤوس برامج تبدأ من 64

رؤوس البرامج:
اكتب الإزاحة VirtAddr PhysAddr
محاذاة إشارات FileSiz MemSiz
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[طلب مترجم البرنامج: /lib64/ld-linux-x86-64.so.2]
تحميل 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d494 0x000000000000d494 R E 200000
تحميل 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x0000000000000524 0x0000000000000748 RW 200000
DYNAMIC 0x000000000000de28 0x000000000060de28 0x000000000060de28
0x00000000000001d0 0x00000000000001d0 RW 8
ملاحظة 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 ص 4
GNU_EH_FRAME 0x000000000000bc40 0x000000000040bc40 0x000000000040bc40
0x00000000000003a4 0x00000000000003a4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x00000000000001f0 0x00000000000001f0 R 1

قسم لرسم الخرائط:
أقسام قطاعية ...
00
01. interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini. rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
04. ديناميكي
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got

رأس القسم

الجزء الثالث من هيكل ELF هو رأس القسم. من المفترض أن تسرد الأقسام الفردية للثنائي. يسرد مفتاح التبديل -S (اختصار لـ -section-headers أو -sections) الرؤوس المختلفة. بالنسبة لأمر اللمس ، هناك 27 رأس قسم ، والقائمة 5 تعرض الأربعة الأولى منهم بالإضافة إلى آخر واحد فقط. يغطي كل سطر حجم القسم ونوع القسم بالإضافة إلى عنوانه وإزاحة الذاكرة.

القائمة 5: تفاصيل القسم التي كشف عنها readelf

readelf -S / usr / bin / touch
يوجد 27 رأس قسم ، تبدأ عند الإزاحة 0xe428:

رؤوس الأقسام:
[Nr] الاسم نوع العنوان إزاحة
محاذاة معلومات ارتباط إشارات الحجم EntSize
[0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[1] .interp PROGBITS 0000000000400238 00000238
000000000000001c 0000000000000000 أ 0 0 1
[2] .note.ABI-tag NOTE 0000000000400254 00000254
0000000000000020 0000000000000000 أ 0 0 4
[3] .note.gnu.build-i NOTE 0000000000400274 00000274
...
...
[26] .shstrtab STRTAB 0000000000000000 0000e334
00000000000000ef 0000000000000000 0 0 1
مفتاح الأعلام:
W (كتابة) ، A (تخصيص) ، X (تنفيذ) ، M (دمج) ، S (سلاسل) ، l (كبير)
أنا (معلومات) ، L (ترتيب الارتباط) ، G (مجموعة) ، T (TLS) ، E (استبعاد) ، x (غير معروف)
O (تتطلب معالجة إضافية لنظام التشغيل) o (خاص بنظام التشغيل) ، p (خاص بالمعالج)

أدوات لتحليل ملف ELF

كما لاحظت من الأمثلة السابقة ، فإن GNU / Linux مكوّن من عدد من الأدوات المفيدة التي تساعدك على تحليل ملف ELF. المرشح الأول الذي سنلقي نظرة عليه هو أداة الملفات.

يعرض الملف المعلومات الأساسية حول ملفات ELF ، بما في ذلك بنية مجموعة التعليمات التي تم تصميم الكود الخاص بها في ملف كائن قابل للنقل أو قابل للتنفيذ أو مشترك. في القائمة 6 ، يخبرك أن / bin / touch هو ملف قابل للتنفيذ 64 بت يتبع Linux Standard Base (LSB) ، مرتبط ديناميكيًا ، ومصمم لإصدار GNU / Linux kernel 2.6.32.

القائمة 6: المعلومات الأساسية باستخدام الملف

ملف $ / بن / اللمس
/ bin / touch: ELF 64-bit LSB قابل للتنفيذ ، x86-64 ، الإصدار 1 (SYSV) ، مرتبط ديناميكيًا ، مترجم / lib64 / l ،
لـ GNU / Linux 2.6.32 ، BuildID [sha1] = ec08d609e9e8e73d4be6134541a472ad0ea34502 ، تم تجريده
$

المرشح الثاني هو readelf. يعرض معلومات مفصلة حول ملف ELF. قائمة المفاتيح طويلة نسبيًا ، وتغطي جميع جوانب تنسيق ELF. باستخدام رمز التبديل -n (اختصار لـ –notes) يعرض القائمة 7 أقسام الملاحظات الموجودة فقط في ملف اللمس - علامة إصدار ABI وسلسلة البت لمعرف البنية.

القائمة 7: عرض أقسام مختارة من ملف ELF

$ readelf -n / usr / bin / touch

عرض الملاحظات التي تم العثور عليها في إزاحة الملف 0x00000254 بطول 0x00000020:
وصف حجم بيانات المالك
GNU 0x00000010 NT_GNU_ABI_TAG (علامة إصدار ABI)
نظام التشغيل: Linux، ABI: 2.6.32

عرض الملاحظات التي تم العثور عليها في إزاحة الملف 0x00000274 بطول 0x00000024:
وصف حجم بيانات المالك
GNU 0x00000014 NT_GNU_BUILD_ID (سلسلة بت معرف الإصدار الفريد)
معرف البناء: ec08d609e9e8e73d4be6134541a472ad0ea34502

لاحظ أنه في ظل Solaris و FreeBSD ، فإن الأداة المساعدة elfdump [7] تتوافق مع readelf. اعتبارًا من عام 2019 ، لم يكن هناك إصدار أو تحديث جديد منذ عام 2003.

رقم ثلاثة هو الحزمة المسماة elfutils [6] والمتاحة تمامًا لنظام Linux. يوفر أدوات بديلة لـ GNU Binutils ، ويسمح أيضًا بالتحقق من صحة ملفات ELF. لاحظ أن جميع أسماء الأدوات المساعدة المتوفرة في الحزمة تبدأ بـ eu لـ 'elf utils'.

أخيرًا وليس آخرًا ، سنذكر objdump. تشبه هذه الأداة readelf ولكنها تركز على ملفات الكائنات. يوفر نطاقًا مشابهًا من المعلومات حول ملفات ELF وتنسيقات الكائنات الأخرى.

القائمة 8: معلومات الملف المستخرجة بواسطة objdump

objdump -f / bin / touch

/ bin / touch: تنسيق الملف elf64-x86-64
العمارة: i386: x86-64 ، الأعلام 0x00000112:
EXEC_P ، HAS_SYMS ، D_PAGED
بدء العنوان 0x00000000004025e3

$

هناك أيضًا حزمة برامج تسمى 'elfkickers' [9] والتي تحتوي على أدوات لقراءة محتويات ملف ELF بالإضافة إلى معالجته. لسوء الحظ ، عدد الإصدارات منخفض نوعًا ما ، ولهذا السبب نذكره فقط ، ولا نعرض المزيد من الأمثلة.

بصفتك مطورًا ، يمكنك إلقاء نظرة على 'pax-utils' [10،11] ، بدلاً من ذلك. توفر هذه المجموعة من الأدوات المساعدة عددًا من الأدوات التي تساعد في التحقق من صحة ملفات ELF. كمثال ، يقوم dumpelf بتحليل ملف ELF ، وإرجاع ملف رأس C يحتوي على التفاصيل - انظر الشكل 2.

استنتاج

بفضل الجمع بين التصميم الذكي والتوثيق الممتاز ، يعمل تنسيق ELF بشكل جيد للغاية ، ولا يزال قيد الاستخدام بعد 20 عامًا. تتيح لك الأدوات المساعدة الموضحة أعلاه نظرة ثاقبة لملف ELF ، وتتيح لك معرفة ما يفعله البرنامج. هذه هي الخطوات الأولى لتحليل البرامج - تسعد القرصنة!

الروابط والمراجع
شكر وتقدير

يود الكاتب أن يشكر أكسل بيكيرت على دعمه فيما يتعلق بإعداد هذا المقال.