بسم الله الرحمن الرحيم ,

تكلمنا في مقالة سابقة عن مفهوم الهندسة العكسية, و تحدثنا عن بعض انواعها, و علمنا مدى أهمية هذا العلم, بأذن الله اليوم سنتعرف على المزيد من المصطلحات و سنتطرق لبعض الأدوات التي سنحتاجها لاحقا لنبدأ أول تطبيق عملي للهندسة العكسية.

الكثير من المصطلحات التقنية سيتم ذكرها في هذا المقال, فأرجو من أي شخص وجد صعوبة في أي من تلك المصطلحات, ان يترك سؤاله في تعليق على هذه الصفحة او على رابط هذا المقال على صفحة الشركة على الفيس بوك, و سيتم الرد عليه بأذن الله في أقرب وقت ممكن.

assembly_screen

قبل البدأ, أحببت أن أنوه عن بعض النقاط:

– تلك المقالة و غيرها, موجه بشكل مباشر لرفع المستوى التقني في علم الهندسة العكسية في الأمة الأسلامية, سائلا الله تعالى أن تكون خالصة لوجهه الكريم, خالية من أي شائبة, و أنا بريء من استخدامها ضد أي مسلم تحت أي حجة, اللهم قد بلغت, اللهم فأشهد.

– أي برنامج تجاري يذكر في هذا المقال أو غيره, فهو موجه للاحاطة بالعلم و كدليل تعليمي فقط ولا يهدف بأي شكل من الأشكال لالحاق الخسارة او التشهير بأي من تلك البرامج.

– كل الأدوات المستخدمة هنا مجانية, و سألحق في نهاية كل مقال روابط تنزيل البرامج بترتيب ذكرها.

– بأذن الله ستكون تلك المقالة و غيرها من المقالات القادمة مقسمة بين تطبيق عملي للهندسة العكسية بشرح مفصل لكل ما تحويه بأذن الله ,و ستتكون من 4 مقالات (غير هذا المقال و المقال السابق). سأركز في أول مقالتين على الهندسة العكسية البرمجية, و في الباقين سنتطرق الي الهندسة العكسية للدوائر الالكترونية.

– تلك المقالات ليس الهدف منها أي عائد ربحي أو تجاري, فدعوة بظهر الغيب تغني عن ملايين الاموال, أرجو أن لا تنسوني و سائر المسلمين من صالح دعائكم.

في البداية, الهندسة العكسية البرمجية هي -و كما ذكرنا في المقال السابق- فك غموض و فهم برنامج أو جزء منه, مكتوب بلغة برمجة معينة, يعمل على نظام تشغيل معين, ينفذ على معالج معين. اذا نحن نحتاج لثلاث خبرات هنا:

-خبرة في لغات البرمجة المكتوب بها البرنامج (في الغالب تكون واحدة من تلك اللغات:لغة السي C و الجافا Java و الديلفي Delphi و السي شارب C# و الـ Visual Basic ).

-خبرة في نظم التشغيل الذي يعمل عليه البرنامج المراد دراسته (سيكون هدفنا هنا نظام تشغيل ويندوز Microsoft Windows لشهرته).

-خبرة في المعالج الذي ينفذ أوامر الملف التنفيذي (سنتعامل هنا مع الأكثر شيوعا و هما Intel x86 family 32-bits بالنسبة لجزء الهندسة العكسية البرمجية, و معالجات MIPS و ARM بالنسبة لجزء الهندسة العكسية الالكترونية).

أما الخبرة في لغات البرمجة, فهنا لا أقصد اتقان اللغة في حد ذاتها (مع أهمية ذلك و يستحسن وجوده في الشخص الذي يقوم بتطبيق الهندسة العكسية), ولكن أقصد خبرته في المترجم Compiler/Interpretter الخاص بلغة البرمجة المكتوب بها البرنامج المراد دراسته.

و لكن لماذا علي الاهتمام بالمترجمات؟

هذا السؤال يطول الرد عليه, فالمترجمات عامل و جزء لا يتجزأ من عملية الهندسة العكسية و فهم آلية عمل برنامج ما.

يجب أن لا ننسي التسلسل المنطقي لتصميم برنامج ما, فالنأخذ مثال بسيط على ذلك.

نفترض أننا كتبنا برنامجا بلغة السي C و قمنا ببدأ عملية الترجمة Compilation. في البداية, سيدخل الكود الخاص بنا على برنامج ما قبل المعالجة PreProcessing و هذا البرنامج يقتصر فقط على بعض اللغات, وكل ما يقوم به أنه يحدد بعض الاجزاء من الكود التي تحذف أو تتغير حسب نظام التشغيل, فيمكن كتابة كود يعمل على نظامي تشغيل أو أكثر باستخدام معاملات ما قبل المعالج Preprocessor directives, وأيضا يمكننا من التحكم ببعض متغيرات المترجم لتغيير أمر ما في الكود في وقت الترجمة. بعد ذلك يخرج الكود و يدخل مرحلة الترجمة الفعلية Compilation, وفيها يتحول الكود من كود للغة عالية المستوي الي لغة المجمع Assembly. ثم يدخل بعد ذلك على المجمع Assembler, الذي يحول من لغة المجمع الي لغة الآلة الثنائية binary.

ثم بعد ذلك يأتي دور الرابط linker الذي يقوم بجمع الملفات التنفيذية Object files و الوحدات المترجمة translation units في ملف تنفيذي واحد, ثم في النهاية, يقوم المحمل Loader بتحميل البرنامج التنفيذي (في بعض الاحيان أجزاء فقط هي التي تحمل) لذاكرة الجهاز عند بدء تنفيذ الملف التنفيذي, و يبدأ البرنامج بالعمل.
كما لاحظنا هنا, لابد من فهم كل خطوة من تلك الخطوات, لأن كثير من الاكواد التي سنقوم بأذن الله بفك غموضها ستكون من لغة المجمع, ولغة المجمع التي سندرسها جزء كبير منها لا يمط لكود البرنامج بصلة, بل تم وضعه من قبل المترجم ليسرع عملية التنفيذ لمهمة معينة في الكود, او ليصغر حجم الملف التنفيذي في الذاكرة, فلهذا من المهم فهم تلك الأجزاء قبل الدخول في الهندسة العكسية.

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

في الحقيقة اذا كانت الهندسة العكسية تحدث على الكود الفعلي للبرنامج بشكل مباشر بدون اي تدخل او تعديل, لكان الامر في منتهى البساطة و لكانت دراسة الكود -حتى و هو في لغة المجمع- هينة للغاية, ولكن التعديلات هي التي تدخل طابع الصعوبة و التعقيد (و المتعة) للهندسة العكسية.
فكثيرا من الاحيان, ستجد ان نظام التشغيل قد قام بتعديل اجزاء كثيرة من الكود قبل تحميله في الذاكرة ليبدأ بتنفيذه, و تلك التعديلات مهمة جدا في حالات الامن.
لنفهم تلك النقطة, نحتاج لمثال بسيط.

في أي برنامج, حينما تقوم باستدعاء دالة function call, فالمتغيرات التي تحتاجها تلك الدالة تدفع الي ذاكرة المكدس stack memory, حتى الان الوضع طبيعي و بسيط. ولكن سرعان ما تم اكتشاف نوع من الثغرات الامنية التي تسمى بالطفح الزائد للمكدسات Stack Buffer Overflow, لن نتطرق لتفاصيل تلك الثغرات لانها بسيطة و مشهورة و خارج نطاق المقال (كما سنتطرق اليها بأذن الله لاحقا في احد المقالات القادمة), احدى طرق الحماية من تلك الثغرات ان لا تجعل ذاكرة المكدس جزء تنفيذي Executable, وهذا يتم من خلال نظام التشغيل. ايضا احدى الطرق الاخري هي تعديل اكواد البرنامج و بدلا من دفع فقط المتغيرات الي المكدس, يدفع ايضا متغير مستقل عن البرنامج حجمه 4 bytes, و يتم ايضا اضافة جزء من كود جديد داخل الدالة المناداة لتتأكد و تقوم ببعض المعالجة على هذا المتغير الذي دفع مؤخرا. كل تلك تعديلات يقوم بها المترجم و نظام التشغيل ليحصل المستخدم على سرعة الاداء, صغر الحجم, الحماية الرقمية اثناء عمله على البرنامج.

أخيرا, نحتاج لخبرة في المعالج الذي نعمل عليه, لان -و كما لاحظنا مسبقا- المترجم يحول الكود من لغة عالية المستوى الي لغة المجمع المتواجد بالجهاز, ثم بعد ذلك يتحول الي ملف تنفيذي باللغة الثنائية Binary. من لديه خبرة في لغة المجمع, يعلم جيدا ان كل برنامج في العالم, سواء كان يعمل على حاسب آلي, خادم مواقع, هاتف نقال, مستقبل قنوات, او حتى ثلاجة حديثة, فانه لابد ان يتكون من اللغة الثنائية binary form ليتمكن المعالج من قراءته, ولكن هل معني ذلك ان البرنامج الذي يعمل على الحاسب, يستطيع ان يعمل على الهاتف, يستطيع ان يعمل على الثلاجة؟ هذا مفهوم خاطء, فكل جهاز له لغة المجمع الخاصة بالمعالج الذي برمج به, فمعالج الحاسب له لغة مجمع مختلفة عن تلك التي بمعالج الهاتف و الاخرين, اذا كيف لأي آلة ان تفرق بين تلك الاكواد و كلمهم يقرأون كود مكتوب بنفس اللغة (binary form)؟ الحل يكمن في ان كل لغة مجمع لها شكل خاص من الاوامر يتم ترجمته و فهمه باللغة الثنائية.
فمثلا, ان كان عندنا معالجان x و y, فالامر ADD سيكون معروف للمعالج x انه (1001) و لكن على المعالج y سيكون معروف (1100). كلاهما مكتوب باللغة الثنائية, ولكن كل واحد مختلف عن الاخر في بنية الاحاد و الاصفار و ترتيبهم.

بعد أن تعرفنا على العلوم اللازمة في علم الهندسة العكسية البرمجية, هنا لابد ان نتطرق لانواع التحليلات analysis التي سنقوم بها بأذن الله في تجاربنا القادمة.

هناك نوعان لتحليل ملف تنفيذي:

– التحليل السلوكي Behavioral Analysis : هنا -و كما دل الاسم- نقوم بدراسة سولك الملف و تأثيره على البيئة المحيطة به. بمعنى اننا هنا نحاول ان نجد ماذا يحدث لنظام الملفات File System و للشبكة Network و للسجل Registery من تغييرات حينما يبدأ البرنامج المراد دراسته بالعمل. هذا النوع من التحليلات مهم جدا في تحليل الملفات المعطوبة و في التحليلات الأمنية. حيث نقوم بفصل الملف في بيئة منعزلة, ونبدأ بفتحه و ملاحظة التغييرات التي يجريها على النظام من حذف/اضافة/تعديل ملف ما, او اتصال بخادم خارجي لاستلام او ارسال ملفات او بيانات, او التعديل على بعض خواص البرامج الاخرى او خواص نظام التشغيل من خلال السجل Registery.

– التحليل البرمجي Code Analysis : هنا يقوم الدارس بفتح الملف التنفيذي للبرنامج المراد دراسته بداخل احد برامج Debugger او disassembler, وهذه البرامج تسمح لنا بتحويل اللغة الثنائية binary للغة المجمع, كما تسمح لنا برؤية حالة المعالج اثناء عمل البرنامج.
التحليل البرمجي ينقسم الى قسمين:

  1. تحليل برمجي ثابت Static Code Analysis : و هنا نقوم بفتح كود البرنامج المراد دراسته من خلال برنامج Disassembler بدون ان نقوم فعليا ببدأ أو تنفيذ البرنامج, وهنا طبعا لن نتمكن من رؤية حالة المعالج لان البرنامج غير مشغل من الاساس, نحن فقط غصنا بداخله و حاولنا قرائته بدون فتحه او تنفيذه. تلك الطريقة مفيدة, ولكنها ليس لها اي قيمة اذا كان الملف التنفيذي مشفر.
  2.  تحليل برمجي ديناميكي Dynamic Code Analysis : هنا -وعلى عكس التحليل الثابت- نقوم بفتح البرنامج المراد دراسته من خلال برنامج Debugger و يقوم بفتح و تنفيذ البرنامج و تمكين المستخدم من رؤية حالة المعالج و البايانات في الذاكرة Heap memory و ذاكرة المكدس Stack memory في أثناء عمل البرنامج. حقيقة, ستجد نفسك تبدأ بالتحليل الديناميكي في كل مرة تقوم بعمل هندسة عكسية على برنامج ما, وذلك لان حتى و ان كان الملف مشفرا, لابد من ان تفك شيفرته ساعة تنفيذه, فستستطيع من خلال التحليل الديناميكي ان ترى الكود غير مشفر.

سأكتفي بتلك المقدمة التقنية , لنبدأ بأذن الله للتحضير لاول درس عملي في الهندسة العكسية في المقال القادم.