الملفات القابلة للتنفيذ في نظام التشغيل وتمثيلها باستخدام الصيغة ELF
تعد الملفات القابلة للتنفيذ (Executable Files) مكونًا جوهريًا في أي نظام تشغيل، حيث تمثل واجهة التفاعل بين البرامج والعتاد. عند تشغيل برنامج في نظام تشغيل مثل لينكس أو يونكس، يتم تحميل ملف قابل للتنفيذ إلى الذاكرة وتنفيذه بواسطة المعالج. ومع تطور نظم التشغيل، ظهرت حاجة ماسة إلى وجود تنسيق موحد ومرن يمكن من خلاله تمثيل الملفات القابلة للتنفيذ بطريقة تسهل على النظام التعامل معها، وتدعم الخصائص المتقدمة مثل التحميل الديناميكي والمشاركة في الذاكرة. من هنا جاء تنسيق ELF أو Executable and Linkable Format.
ظهر تنسيق ELF بداية ضمن مشروع System V Release 4 (SVR4) الذي أطلقته شركة AT&T في نهاية الثمانينيات، ولاحقًا أصبح التنسيق الافتراضي على معظم أنظمة يونكس الحديثة، بما فيها لينكس، FreeBSD، وSolaris. يتميز هذا التنسيق بالمرونة والدقة، إذ يسمح بتمثيل ليس فقط الملفات القابلة للتنفيذ بل أيضًا المكتبات الديناميكية (Shared Libraries)، والملفات القابلة للربط (Relocatable Files)، وحتى ملفات نواة النظام (Kernel Object Files).
بنية الملفات القابلة للتنفيذ
قبل الخوض في تفاصيل تنسيق ELF، لا بد من استعراض البنية العامة للملفات القابلة للتنفيذ. تتكون هذه الملفات من عدة أقسام رئيسية:
-
كود البرنامج (Text Section): يحتوي على التعليمات البرمجية (Instructions) التي تُنفذ.
-
قسم البيانات (Data Section): يشمل المتغيرات المُهيئة مسبقًا (Initialized Variables).
-
قسم البيانات غير المهيأة (BSS): يحتوي على المتغيرات التي لم يتم تهيئتها (Uninitialized Variables).
-
قسم الجداول الرمزية (Symbol Tables): لتخزين أسماء الدوال والمتغيرات المستخدمة في الربط الديناميكي.
-
قسم الجداول السطرية (Line Tables): لربط عناوين الآلة مع الأسطر البرمجية المصدرية.
يهدف تنسيق ELF إلى تنظيم هذه الأقسام داخل ملف واحد بطريقة تجعل من السهل على نظام التشغيل تحميله وتنفيذه.
تعريف صيغة ELF ومكوناتها
العنوان الرئيسي (ELF Header)
يتواجد في بداية كل ملف بصيغة ELF ويحتوي على معلومات ضرورية لتفسير باقي الملف. أهم الحقول التي يتضمنها:
| الحقل | الوصف |
|---|---|
| Magic Number | بصمة تعريفية (0x7F 'E' 'L' 'F') لتمييز الملف كـ ELF |
| Class | نوع المعمارية (32-بت أو 64-بت) |
| Data | ترتيب البايتات (Little Endian أو Big Endian) |
| Entry Point | عنوان نقطة الدخول (أول تعليمة سيتم تنفيذها) |
| Program Header Off | بداية جدول رؤوس البرنامج |
| Section Header Off | بداية جدول رؤوس الأقسام |
رؤوس البرنامج (Program Header Table)
يصف كل رأس في هذا الجدول قسمًا من الملف يجب تحميله إلى الذاكرة. يعد هذا الجدول ضروريًا عند تشغيل البرنامج. يحتوي كل رأس على:
-
نوع القسم (Load, Dynamic, Interpreter)
-
عنوانه في الملف
-
العنوان المراد تحميله في الذاكرة
-
الحجم في الملف والسعة في الذاكرة
-
صلاحيات الوصول (قراءة، كتابة، تنفيذ)
رؤوس الأقسام (Section Header Table)
تُستخدم من قبل أدوات التطوير (مثل المجمّع والمربط) وتحتوي على معلومات تفصيلية حول أقسام الملف. لا تُستخدم مباشرة من قبل المحمّل (Loader)، بل من قبل أدوات مثل objdump وreadelf.
| الحقل | الوصف |
|---|---|
| اسم القسم | مؤشر إلى سلسلة نصوص تحتوي أسماء الأقسام |
| نوع القسم | نصوص، رموز، تعليمات، إلخ |
| العنوان في الملف | الموقع داخل الملف |
| العنوان في الذاكرة | موقع تحميله في الذاكرة (عند التنفيذ) |
أنواع ملفات ELF
تنسيق ELF يُستخدم لتمثيل أنواع مختلفة من الملفات، كما يلي:
-
ET_REL (Relocatable): ملفات يمكن ربطها مع أخرى لإنشاء ملف تنفيذي.
-
ET_EXEC (Executable): ملفات جاهزة للتنفيذ.
-
ET_DYN (Shared Object): مكتبات مشتركة ديناميكية يمكن تحميلها أثناء التشغيل.
-
ET_CORE (Core Dump): ملفات تحتوي على حالة عملية بعد توقفها (تُستخدم في تحليل الأعطال).
آلية تحميل ملفات ELF في النظام
عند تنفيذ أمر لتشغيل برنامج ELF (مثلاً ./program)، يقوم نظام التشغيل بما يلي:
-
قراءة العنوان الرئيسي ELF Header.
-
تفسير جدول رؤوس البرنامج Program Header Table لتحديد الأقسام الواجب تحميلها.
-
تحميل أقسام الكود والبيانات إلى الذاكرة.
-
تهيئة المكدس Stack وبيئة التشغيل.
-
القفز إلى عنوان نقطة الدخول Entry Point لبدء التنفيذ.
تتيح هذه الآلية دعمًا قويًا لخصائص متقدمة، مثل:
-
التحميل عند الطلب (Lazy Loading)
-
المشاركة في الذاكرة للمكتبات الديناميكية
-
الحماية من تنفيذ البيانات (NX Bit)
دعم الربط الديناميكي عبر ELF
يدعم تنسيق ELF نظام الربط الديناميكي الذي يُعد من أهم مزاياه. عند استخدام مكتبات ديناميكية، يتم الربط بينها وبين الملف التنفيذي أثناء التشغيل وليس وقت الإنشاء. يعتمد هذا الربط على أقسام معينة في ملف ELF مثل:
-
.dynamic: يحتوي على معلومات الربط الديناميكي.
-
.got (Global Offset Table): يُستخدم لمعالجة عناوين الرموز في وقت التنفيذ.
-
.plt (Procedure Linkage Table): يُستخدم لنقل تنفيذ الدوال إلى العنوان الصحيح في المكتبة الديناميكية.
يسمح هذا النظام بتحديث المكتبات دون الحاجة لإعادة ترجمة البرامج المرتبطة بها.
تنسيق 32-بت مقابل 64-بت
يدعم ELF كل من المعماريات 32-بت و64-بت. الفروق بينهما تشمل:
-
حجم الحقول (مثل العناوين والإزاحات)
-
محاذاة البيانات (Data Alignment)
-
إمكانية تحميل أقسام أكبر في الذاكرة
في نظام لينكس الحديث، يُستخدم تنسيق ELF64 على معظم الأنظمة، خاصة تلك المعتمدة على معمارية x86_64.
تحليل ملف ELF باستخدام أدوات النظام
هناك عدة أدوات مفيدة لفحص وتحليل ملفات ELF في بيئة لينكس، منها:
-
readelf: لعرض محتويات ملف ELF بشكل مفصل.
-
objdump: يعرض الأقسام والكود البرمجي.
-
ldd: يوضح المكتبات الديناميكية المرتبطة بالملف التنفيذي.
-
file: يُحدد نوع الملف وإذا ما كان بصيغة ELF.
مثال:
bashreadelf -h program
يعرض العنوان الرئيسي للملف program.
تمثيل ELF في بيئة التطوير
يتم إنشاء ملفات ELF في الغالب عبر عمليات التجميع (Assembly) أو الترجمة (Compilation) باستخدام أدوات مثل gcc. تمر العملية بالمراحل التالية:
-
الترجمة: يتم تحويل الكود المصدر إلى كود كائن (Object Code).
-
الربط: يتم دمج ملفات الكائن مع المكتبات اللازمة، وإنتاج ملف ELF نهائي.
-
التنفيذ: يتم تحميل الملف بواسطة المحمّل، وتنفيذه من نقطة الدخول.
مقارنة ELF بتنسيقات أخرى
قبل ظهور ELF، كانت هناك تنسيقات مثل a.out وCOFF. فيما يلي جدول يقارن بينها:
| الخاصية | a.out | COFF | ELF |
|---|---|---|---|
| التوسع | محدود | متوسط | مرن جداً |
| دعم الربط الديناميكي | غير موجود | محدود | كامل |
| تعدد الأقسام | غير مدعوم | مدعوم جزئيًا | مدعوم بالكامل |
| الدعم في الأنظمة | قديم | أنظمة خاصة | جميع أنظمة لينكس الحديثة |
أمثلة عملية على بناء ملف ELF
يمكن باستخدام أدوات مثل gcc وld وobjcopy إنشاء ملفات ELF من كود برمجي بسيط. على سبيل المثال:
c#include
int main() {
printf("Hello, ELF!\n");
return 0;
}
عند تجميعه باستخدام:
bashgcc -o hello hello.c
يتم إنشاء ملف ELF تنفيذي. يمكن تحليل تفاصيله عبر:
bashreadelf -a hello
الاستخدامات الأمنية لصيغة ELF
مع تزايد التهديدات الأمنية، أصبح تحليل ملفات ELF ضرورة في مجالات الأمن السيبراني، حيث تُستخدم لمعرفة:
-
إذا ما كان الملف قد تم تعديله أو حقنه بكود ضار.
-
أقسام مشبوهة تم إضافتها.
-
وجود رموز غريبة أو روابط ديناميكية إلى مكتبات خبيثة.
برمجيات مثل chkrootkit وrkhunter تعتمد بشكل كبير على تحليل ملفات ELF لاكتشاف Rootkits أو تهديدات مشابهة.
خاتمة تنظيمية
يُعد تنسيق ELF حجر الزاوية في تنفيذ البرامج ضمن أنظمة تشغيل يونكسية، بفضل مرونته ودعمه لمجموعة كبيرة من الميزات المتقدمة مثل التحميل الديناميكي والربط المتأخر. معرفته العميقة ضرورية لكل من يشتغل في مجال تطوير البرمجيات، أدوات التحليل، الأنظمة المضمنة، أو أمن المعلومات.
المصادر والمراجع:
-
“Linkers and Loaders” by John R. Levine
-
The Linux Documentation Project – ELF File Format Guide (https://tldp.org)

