كيفية إلقاء نظرة خاطفة على الملفات الثنائية من سطر أوامر Linux

نشرت: 2022-01-29
محطة لينكس منمقة مع سطور من النص الأخضر على جهاز كمبيوتر محمول.
fatmawati achmad zaenuri / Shutterstock

هل لديك ملف غامض؟ سيخبرك أمر file Linux بسرعة بنوع الملف. إذا كان ملفًا ثنائيًا ، فيمكنك معرفة المزيد عنه. يحتوي file على مجموعة كاملة من الزملاء المستقرين التي ستساعدك على تحليله. سنوضح لك كيفية استخدام بعض هذه الأدوات.

تحديد أنواع الملفات

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

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

بعض أنظمة التشغيل ، مثل Windows ، تسترشد بالكامل بامتداد الملف. يمكنك تسميته ساذجًا أو واثقًا ، لكن Windows يفترض أن أي ملف بامتداد DOCX هو بالفعل ملف معالجة نصوص DOCX. Linux ليس كذلك ، كما سترى قريبًا. يريد إثباتًا وينظر داخل الملف للعثور عليه.

تم بالفعل تثبيت الأدوات الموضحة هنا على توزيعات Manjaro 20 و Fedora 21 و Ubuntu 20.04 التي استخدمناها للبحث في هذه المقالة. لنبدأ تحقيقنا باستخدام الأمر file .

باستخدام ملف الأوامر

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

الإعلانات

سيُظهر لنا الأمر ls ما يوجد في الدليل ، وسيُظهر لنا الخيار -hl (أحجام يمكن قراءتها من قبل الإنسان ، قائمة طويلة) حجم كل ملف:

 ls -hl 

file نحاول وضع عدد قليل من هذه ونرى ما حصلنا عليه:

 ملف build_instructions.odt
 ملف build_instructions.pdf
 ملف COBOL_Report_Apr60.djvu 

تم تحديد تنسيقات الملفات الثلاثة بشكل صحيح. حيثما أمكن ، يمنحنا file مزيدًا من المعلومات قليلاً. تم الإبلاغ عن أن ملف PDF بتنسيق الإصدار 1.5.

حتى إذا قمنا بإعادة تسمية ملف ODT ليكون له امتداد بقيمة عشوائية لـ XYZ ، فسيظل الملف محددًا بشكل صحيح ، سواء داخل مستعرض ملف Files أو في سطر الأوامر باستخدام file .

تم تحديد ملف OpenDocument بشكل صحيح داخل مستعرض الملفات Files ، على الرغم من أن امتداده هو XYZ.

في مستعرض Files الملفات ، يتم إعطاؤه الرمز الصحيح. في سطر الأوامر ، يتجاهل file الامتداد ويبحث داخل الملف لتحديد نوعه:

 ملف build_instructions.xyz 

الإعلانات

عادةً ما ينتج عن استخدام file على وسائط ، مثل ملفات الصور والموسيقى ، معلومات تتعلق بتنسيقها وتشفيرها ودقتها وما إلى ذلك:

 ملف screenshot.png
 ملف screenshot.jpg
 ملف Pachelbel_Canon_In_D.mp3 

ومن المثير للاهتمام ، أنه حتى مع ملفات النص العادي ، فإن file لا يحكم على الملف من خلال امتداده. على سبيل المثال ، إذا كان لديك ملف بامتداد ".c" ، يحتوي على نص عادي قياسي ولكن ليس رمز مصدر ، فإن file لا يخلط بينه وبين ملف شفرة مصدر C أصلي:

 وظيفة الملف + headers.h
 ملف makefile
 ملف hello.c 

يعرّف file بشكل صحيح ملف الرأس (".h") كجزء من مجموعة ملفات التعليمات البرمجية المصدر للغة C ، ويعرف أن ملف makefile هو نص برمجي.

باستخدام ملف مع الملفات الثنائية

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

على سبيل المثال ، الملفات "hello" و "wd" هي ملفات ثنائية قابلة للتنفيذ. هم برامج. الملف المسمى “wd.o” هو ملف كائن. عندما يتم تجميع التعليمات البرمجية المصدر بواسطة مترجم ، يتم إنشاء ملف كائن واحد أو أكثر. تحتوي على رمز الجهاز الذي سينفذه الكمبيوتر في النهاية عند تشغيل البرنامج النهائي ، بالإضافة إلى المعلومات الخاصة بالرابط. يتحقق الرابط من كل ملف كائن من أجل استدعاءات الوظائف للمكتبات. يربطهم بأي مكتبات يستخدمها البرنامج. نتيجة هذه العملية ملف قابل للتنفيذ.

الملف “watch.exe” هو ملف ثنائي قابل للتنفيذ تم تجميعه بشكل متقاطع ليتم تشغيله على Windows:

 ملف wd
 ملف wd.o
 ملف hello
 ملف watch.exe 

الإعلانات

بأخذ الملف الأخير أولاً ، يخبرنا file أن ملف "watch.exe" هو برنامج وحدة تحكم قابل للتنفيذ PE32 + ، لعائلة معالجات x86 على Microsoft Windows. يرمز PE إلى التنسيق القابل للتنفيذ المحمول ، والذي يحتوي على إصدارات 32 بت و 64 بت. PE32 هو الإصدار 32 بت ، و PE32 + هو الإصدار 64 بت.

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

ما قد يلفت انتباهك هو أن الملفين التنفيذيين ("wd" و "hello") تم تحديدهما على أنهما كائنات مشتركة Linux Standard Base (LSB) ، وملف الكائن "wd.o" معرف على أنه LSB قابل للنقل. كلمة قابل للتنفيذ واضحة في غيابها.

يمكن إعادة تحديد موضع ملفات الكائنات ، مما يعني أنه يمكن تحميل الكود الموجود بداخلها في الذاكرة في أي مكان. يتم سرد الملفات التنفيذية ككائنات مشتركة لأنه تم إنشاؤها بواسطة الرابط من ملفات الكائنات بطريقة ترث هذه الإمكانية.

يتيح ذلك لنظام العنوان العشوائي لتخطيط مساحة العنوان (ASMR) تحميل الملفات التنفيذية في الذاكرة على العناوين التي يختارها. تحتوي الملفات التنفيذية القياسية على عنوان تحميل مشفر في رؤوسها ، والذي يحدد مكان تحميلها في الذاكرة.

ASMR هي تقنية أمنية. تحميل الملفات التنفيذية في الذاكرة في عناوين يمكن التنبؤ بها يجعلها عرضة للهجوم. هذا لأن نقاط دخولهم ومواقع وظائفهم ستكون دائمًا معروفة للمهاجمين. تتغلب العناصر التنفيذية المستقلة (PIE) الموضوعة في عنوان عشوائي على هذه الحساسية.

الإعلانات

إذا قمنا بتجميع برنامجنا باستخدام مترجم gcc وقمنا بتوفير -no-pie ، فسننشئ ملفًا تنفيذيًا تقليديًا.

يتيح لنا الخيار -o (ملف الإخراج) تقديم اسم للملف التنفيذي الخاص بنا:

 دول مجلس التعاون الخليجي -o hello-no-pie hello.c

سنستخدم file في الملف القابل للتنفيذ الجديد ونرى ما الذي تغير:

 ملف hello

حجم الملف القابل للتنفيذ هو نفسه كما كان من قبل (17 كيلو بايت):

 ls -hl مرحبًا 

يتم الآن تحديد الثنائي كملف تنفيذي قياسي. نحن نفعل هذا لأغراض العرض فقط. إذا جمعت التطبيقات بهذه الطريقة ، فستفقد جميع مزايا ASMR.

لماذا الملف القابل للتنفيذ كبير جدًا؟

برنامج hello في المثال الخاص بنا هو 17 كيلو بايت ، لذلك بالكاد يمكن تسميته كبيرة ، ولكن بعد ذلك ، كل شيء نسبي. شفرة المصدر 120 بايت:

 قطة مرحبا ج
الإعلانات

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

 ls -hl مرحبًا 

دعنا نفحص الملف الثنائي باستخدام أمر strings كخطوة أولى بسيطة لاكتشاف ما بداخله. سنقوم بتوجيهه إلى less :

 سلاسل مرحبا | أقل 

هناك العديد من السلاسل داخل النظام الثنائي ، إلى جانب "Hello، Geek world!" من شفرة المصدر لدينا. معظمها عبارة عن تسميات لمناطق داخل الثنائي ، وأسماء ومعلومات ربط الكائنات المشتركة. وتشمل هذه المكتبات ، والوظائف داخل تلك المكتبات ، والتي يعتمد عليها الثنائي.

يوضح لنا الأمر ldd تبعيات الكائن المشتركة لثنائي:

 ldd مرحبا 

هناك ثلاثة إدخالات في الإخراج ، واثنان منهم يشتملان على مسار دليل (الأول لا):

  • linux-vdso.so: الكائن الافتراضي الديناميكي المشترك (VDSO) هو آلية نواة تسمح بالوصول إلى مجموعة من إجراءات مساحة kernel بواسطة ثنائي مساحة المستخدم. هذا يتجنب الحمل الزائد لمبدل السياق من وضع kernel للمستخدم. تلتزم كائنات VDSO المشتركة بالتنسيق القابل للتنفيذ والربط (ELF) ، مما يسمح لها بالربط ديناميكيًا بالثنائي في وقت التشغيل. يتم تخصيص VDSO ديناميكيًا ويستفيد من ASMR. يتم توفير إمكانية VDSO بواسطة مكتبة GNU C القياسية إذا كانت النواة تدعم مخطط ASMR.
  • libc.so.6: كائن مشترك لمكتبة جنو سي.
  • /lib64/ld-linux-x86-64.so.2: هذا هو الرابط الديناميكي الذي يريد البرنامج الثنائي استخدامه. يستجوب الرابط الديناميكي الثنائي لاكتشاف التبعيات التي يمتلكها. يطلق تلك الأشياء المشتركة في الذاكرة. يعد البرنامج الثنائي للتشغيل ويكون قادرًا على العثور على التبعيات في الذاكرة والوصول إليها. ثم يبدأ البرنامج.

رأس ELF

يمكننا فحص وفك تشفير رأس ELF باستخدام الأداة المساعدة readelf -h (رأس الملف):

 readelf -h مرحبا 

يتم تفسير الرأس بالنسبة لنا.

الإعلانات

يتم تعيين البايت الأول لجميع ثنائيات ELF على القيمة السداسية العشرية 0x7F. يتم تعيين البايت الثلاثة التالية على 0x45 و 0x4C و 0x46. البايت الأول هو علامة تعرف الملف على أنه ثنائي ELF. لتوضيح هذا الأمر تمامًا ، توضح وحدات البايت الثلاثة التالية "ELF" في ASCII:

  • الفئة: تشير إلى ما إذا كان الملف الثنائي 32 أو 64 بت قابل للتنفيذ (1 = 32 ، 2 = 64).
  • البيانات: تشير إلى مدى الاستخدام. يحدد ترميز Endian الطريقة التي يتم بها تخزين الأرقام متعددة البايت. في التشفير الكبير ، يتم تخزين الرقم بأهم بتاته أولاً. في الترميز البسيط ، يتم تخزين الرقم مع البتات الأقل أهمية أولاً.
  • الإصدار: إصدار ELF (حاليًا ، 1).
  • OS / ABI: يمثل نوع الواجهة الثنائية للتطبيق قيد الاستخدام. يحدد هذا الواجهة بين وحدتين ثنائيتين ، مثل برنامج ومكتبة مشتركة.
  • إصدار ABI: إصدار ABI.
  • النوع: نوع ثنائي ELF. القيم الشائعة هي ET_REL لإعادة تحديد الموضع (مثل ملف كائن) ، و ET_EXEC تنفيذي تم تجميعه بعلامة-no -no-pie ، و ET_DYN لـ ASMR.
  • الجهاز: بنية مجموعة التعليمات. يشير هذا إلى النظام الأساسي الهدف الذي تم إنشاء الثنائي من أجله.
  • الإصدار: التعيين دائمًا إلى 1 ، لهذا الإصدار من ELF.
  • عنوان نقطة الإدخال: عنوان الذاكرة داخل الملف الثنائي الذي يبدأ عنده التنفيذ.

الإدخالات الأخرى هي أحجام وأرقام المناطق والأقسام داخل الثنائي بحيث يمكن حساب مواقعها.

نظرة خاطفة سريعة على أول ثمانية بايت من الثنائي مع hexdump ستظهر بايت التوقيع وسلسلة "ELF" في أول أربعة بايت من الملف. يمنحنا الخيار -C (الأساسي) تمثيل ASCII للبايت جنبًا إلى جنب مع قيمها السداسية العشرية ، ويتيح لنا الخيار -n (رقم) تحديد عدد البايت الذي نريد رؤيته:

 hexdump -C -n 8 مرحبًا 

objdump والعرض الحبيبي

إذا كنت تريد رؤية التفاصيل الدقيقة ، فيمكنك استخدام الأمر objdump مع الخيار -d (تفكيك):

 objdump -d مرحبًا | أقل 

يؤدي هذا إلى تفكيك رمز الجهاز القابل للتنفيذ ويعرضه بالبايت السداسي العشري جنبًا إلى جنب مع مكافئ لغة التجميع. يتم عرض موقع عنوان الوداع الأول في كل سطر في أقصى اليسار.

هذا مفيد فقط إذا كنت تستطيع قراءة لغة التجميع ، أو إذا كنت مهتمًا بما يدور خلف الستارة. هناك الكثير من المخرجات ، لذلك قمنا بتوزيعها على less .

ترجمة وربط

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

الإعلانات

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