كتابة محمل wasm لـ Ghidra. الجزء 1: بيان المشكلة وإعداد البيئة


في هذا الأسبوع ، قدمت وكالة الأمن القومي (NSA) فجأة هدية للبشرية ، مما فتح مصادر إطار عمل الهندسة العكسية لبرامجهم. بدأ مجتمع المهندسين العكسيين وخبراء الأمن بحماس كبير لاستكشاف لعبة جديدة. وفقًا للتعليقات ، إنها أداة رائعة حقًا ، قادرة على التنافس مع الحلول الحالية ، مثل IDA Pro و R2 و JEB. تسمى الأداة غيدرا والموارد المهنية مليئة الانطباعات من الباحثين. في الواقع ، كان لديهم سبب وجيه: ليس كل يوم المنظمات الحكومية توفر الوصول إلى أدواتها الداخلية. نفسي كمهندس عكسي المهنية ومحلل البرامج الضارة لا يمكن أن يمر بها كذلك. قررت قضاء عطلة نهاية أسبوع أو أسبوعين والحصول على الانطباع الأول للأداة. كنت قد لعبت قليلا مع التفكيك وقررت التحقق من القابلية للتوسعة للأداة. في هذه السلسلة من المقالات ، سوف أشرح تطور Ghidra الوظيفة الإضافية ، التي تقوم بتحميل التنسيق المخصص ، وتستخدم لحل مهمة CTF. نظرًا لأنه إطار كبير واخترت مهمة معقدة للغاية ، فسوف أقسم المقالة إلى عدة أجزاء.

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

لنبدأ بوصف المهمة. في العام الماضي ، استضافت شركة الأمن FireEye مسابقة CTF التي أطلق عليها اسم flare-on. خلال المسابقة ، اضطر الباحثون إلى حل 12 مهمة ، تتعلق بالهندسة العكسية. كانت إحدى المهام هي البحث في تطبيق الويب ، المصمم باستخدام WebAssembly. إنه تنسيق قابل للتنفيذ جديد نسبيًا ، وحسب علمي ، لا توجد أدوات مثالية للتعامل معه. خلال التحدي ، جربت العديد من الأدوات المختلفة في محاولة لهزيمة ذلك. كانت تلك نصوصًا بسيطة من github و decompilers المعروفة ، مثل IDA pro و JEB. من المثير للدهشة ، لقد توقفت عن استخدام chrome ، والذي يوفر أداة تفكيك ومصحح جيدة جدًا لـ WebAssembly. هدفي هو حل التحدي مع الغيدرة. سأقوم بوصف الدراسة على أكمل وجه ممكن وأقدم كل المعلومات الممكنة لإعادة إنتاج خطواتي. ربما ، كشخص لا يمتلك الكثير من الخبرة في الأداة ، قد أخوض في بعض التفاصيل غير الضرورية ، ولكن الأمر كذلك.

يمكن تنزيل المهمة التي سأستخدمها للدراسة من موقع تحدي flareon5. يوجد ملف 05_web2point0.7z: أرشيف مشفر بكلمة مخيفة مصابة . هناك ثلاثة ملفات في الأرشيف: index.html و main.js و test.wasm. دعنا نفتح ملف index.html في المستعرض ونتحقق من النتيجة:



حسنًا ، هذا ما سأعمل عليه. لنبدأ بدراسة html ، خاصةً لأنها أسهل جزء من التحدي. لا يشتمل رمز html على أي شيء باستثناء تحميل البرنامج النصي main.js.

<!DOCTYPE html> <html> <body> <span id="container"></span> <script src="./main.js"></script> </body> </html> 

البرنامج النصي لا يفعل أي شيء معقد أيضًا ، على الرغم من أنه يبدو مطوّلًا إلى حد ما. يقوم فقط بتحميل ملف test.wasm ويستخدمه لإنشاء مثيل WebAssembly. ثم يقرأ المعلمة "q" من url ويمررها إلى مطابقة الطريقة ، ويتم تصديرها بواسطة المثيل. إذا كانت السلسلة في المعلمة غير صحيحة ، يعرض البرنامج النصي الصورة التي رأيناها أعلاه ، من حيث مطوري FireEye المسمى "Pile of poo".

  let b = new Uint8Array(new TextEncoder().encode(getParameterByName("q"))); let pa = wasm_alloc(instance, 0x200); wasm_write(instance, pa, a); let pb = wasm_alloc(instance, 0x200); wasm_write(instance, pb, b); if (instance.exports.Match(pa, a.byteLength, pb, b.byteLength) == 1) { // PARTY POPPER document.getElementById("container").innerText = "🎉"; } else { // PILE OF POO document.getElementById("container").innerText = "ðŸ'"; } 

حل المهمة هو العثور على قيمة المعلمة q التي تجعل الوظيفة "مطابقة" بإرجاع "صواب". للقيام بذلك ، سأقوم بتفكيك ملف test.wasm وتحليل خوارزمية الوظيفة مطابقة.

لا توجد مفاجآت ، وسأحاول القيام بذلك في غيدرة. ولكن أولا لا بد لي من تثبيته. يمكن (وينبغي) تنزيل التثبيت من https://ghidra-sre.org/ . نظرًا لأنه مكتوب بلغة جافا ، فليس هناك أي متطلبات خاصة للتثبيت ، ولا يتطلب أي جهود خاصة للتثبيت. كل ما تحتاجه هو فك الأرشيف وتشغيل التطبيق. الشيء الوحيد المطلوب هو تحديث JDK و JRE إلى الإصدار 11.

لنقم بإنشاء مشروع غيدرة جديد ( ملف-> مشروع جديد ) ، ونطلق عليه اسم "wasm" /



ثم أضف إلى المشروع ملف test.wasm ( ملف → ملف الاستيراد ) وانظر كيف يمكن ghidra التعامل معها



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

بادئ ذي بدء ، لقد درست جميع الوثائق المتاحة. في الواقع ، يوجد مستند واحد مناسب فقط يوضح عملية تطوير الوظائف الإضافية: الشرائح GhidraAdvancedDevelopment. سوف أتبع المستند ، مع إعطاء وصف تفصيلي.

لسوء الحظ ، يتطلب تطوير الوظائف الإضافية استخدام الكسوف. كل تجربتي مع eclipse هي تطوير لعبتي gdx لنظام Android في عام 2012. لقد كان أسبوعين مليئين بالألم والمعاناة ، وبعد ذلك قمت بمسحها من ذهني. نأمل بعد 7 سنوات من التطوير أنه أفضل من السابق.

لنقم بتنزيل وتثبيت الكسوف من الموقع الرسمي.

ثم ، قم بتثبيت ملحق لتطوير ghidra:

Goto eclipse Help → تثبيت قائمة البرامج الجديدة ، انقر فوق زر " إضافة" واختر GhidraDev.zip من / Extensions / Eclipse / GhidraDev /. تثبيته وإعادة تشغيل الملحق. التمديد ، يضيف قوالب إلى قائمة المشروع الجديدة ، يسمح بتصحيح الوحدات النمطية من الكسوف ووحدة الترجمة إلى حزمة التوزيع.

كما يلي من مستندات المطورين ، يجب القيام بالخطوات التالية لإضافة وحدة نمطية لمعالجة التنسيق الثنائي الجديد:

  • إنشاء فئات ، واصفا بنيات البيانات
  • تطوير محمل. يجب أن يتم توريث Loader من الفئة AbstractLibrarySupportLoader . يقرأ جميع البيانات اللازمة من الملف ، ويتحقق من سلامة البيانات ويحول البيانات الثنائية إلى تمثيل داخلي ، ويعدها للتحليل
  • تطوير محلل. يرث محلل من فئة AbstractAnalyzer . يتطلب الأمر هياكل البيانات التي أعدها اللودر ويشرحها (لست متأكدًا حقًا ماذا يعني ذلك ، لكنني آمل أن أفهم أثناء التطوير)
  • إضافة المعالج. Ghidra لديه تجريد: المعالج. إنه مكتوب بلغة تعريفية داخلية ويصف مجموعة التعليمات وتخطيط الذاكرة والميزات المعمارية الأخرى. انا ذاهب لتغطية هذا الموضوع ، وكتابة المفكك.

الآن ، عندما يكون لدينا كل النظرية اللازمة ، حان الوقت لإنشاء مشروع الوحدة النمطية. بفضل امتداد الكسوف المثبت سابقًا GhidraDev ، لدينا قالب الوحدة النمطية في قائمة ملف-> مشروع جديد .



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



يقوم المعالج بإنشاء هيكل عظمي للمشروع مع جميع الأجزاء اللازمة: محلل فارغ في الملف WasmAnalyzer.java ، محمل فارغ في ملف WasmLoader.java ، هيكل عظمي للغة في الدليل / البيانات / اللغات.



لنبدأ مع المحمل. كما تم ذكره ، يجب أن يتم توريثه من الفصل AbstractLibrarySupportLoader ولديه ثلاث طرق ليتم تحميلها بشكل زائد:

  • getName - هذه الطريقة يجب أن الاسم الداخلي للجرافة. Ghidra يستخدمه في أماكن مختلفة ، على سبيل المثال ، لربط لودر بالمعالج
  • findSupportedLoadSpecs - رد الاتصال ، ونفذ ، عندما اختار المستخدم ملف للاستيراد. في محمل رد الاتصال هذا ، يجب أن يقرر ما إذا كان قادرًا على معالجة الملف وإرجاع مثيل الفئة LoadSpec ، وإخبار المستخدم بكيفية معالجة الملف.
  • تحميل - رد الاتصال ، نفذ ، بعد ملف تحميل المستخدم. في هذه الطريقة يوزع اللودر هيكل الملف ويحمّل في الغيدرة. سوف تصفه بمزيد من التفاصيل في المقالة التالية

الطريقة الأولى والأبسط هي getName ، حيث تقوم فقط بإرجاع اسم أداة التحميل

  public String getName() { return "WebAssembly"; } 

الطريقة الثانية للتطبيق هي findSupportedLoadSpecs. يتم استدعاؤه بواسطة الأداة أثناء استيراد الملف ويجب التحقق مما إذا كان برنامج التحميل قادرًا على معالجة الملف. إذا كانت الطريقة القادرة تُرجع كائنًا من فئة LoadSpec ، فإن إخبار ما هو الكائن المستخدم لتحميل الملف وما المعالج الذي سيفككه .

تبدأ الطريقة من التحقق من التنسيق. كما يلي من المواصفات ، يجب أن تكون البايتات الثمانية الأولى من ملف wasm توقيع "\ 0asm" والإصدار.

لتحليل الرأس ، قمت بإنشاء فئة WasmHeader ، وهي تنفذ واجهة StructConverter ، وهي واجهة أساسية لوصف البيانات المنظمة. يستقبل مُنشئ WasmHeader الكائن BinaryReader - التجريد ، المستخدم لقراءة البيانات من المصدر الثنائي الذي يتم تحليله. يستخدمه المنشئ لقراءة رأس ملف الإدخال

  private byte[] magic; private byte [] version; public WasmHeader(BinaryReader reader) throws IOException { magic = reader.readNextByteArray(WASM_MAGIC_BASE.length()); version = reader.readNextByteArray(WASM_VERSION_LENGTH); } 

يستخدم Loader هذا الكائن للتحقق من توقيع الملف. ثم ، في حالة النجاح ، يبحث عن المعالج المناسب. يستدعي استعلام أسلوب الفئة QueryOpinionService ، ويمررها اسم أداة التحميل ("Webassembly"). OpinionService تبحث عن المعالج المرتبط بهذا المحمل ويعيده مرة أخرى.

 List<QueryResult> queries = QueryOpinionService.query(getName(), MACHINE, null); 

تأكد من عدم إرجاع أي شيء ، لأن ghidra لا يعرف المعالج ، والذي يطلق عليه WebAssembly وهو بحاجة إلى تعريفه. كما قلت من قبل ، أنشأ المعالج هيكل اللغة في بيانات الدليل / اللغات.



في المرحلة الحالية ، يوجد ملفان قد يكونان مثيرين للاهتمام: Webassembly.opinion و Wbassembly.ldefs. File .opinon يعين المراسلات بين اللودر والمعالج.

 <opinions> <constraint loader="WebAssembly" compilerSpecID="default"> <constraint primary="1" processor="Webassembly" size="16" /> </constraint> </opinions> 

أنه يحتوي على XML بسيط مع بعض السمات. يجب تعيين اسم المُحمِّل في سمة "loader" واسم المعالج في سمة "processor" ، وكلاهما "Webassembly". في هذه الخطوة ، سأملأ المعلمات الأخرى بالقيم العشوائية. بمجرد أن أعرف المزيد عن هندسة معالج Webassembly ، سأقوم بتغييرها إلى تصحيح القيم.

يصف ملف .ldefs ميزات المعالج ، والتي يجب أن تنفذ التعليمات البرمجية من الملف.

 <language_definitions> <language processor="Webassembly" endian="little" size="16" variant="default" version="1.0" slafile="Webassembly.sla" processorspec="Webassembly.pspec" id="wasm:LE:16:default"> <description>Webassembly Language Module</description> <compiler name="default" spec="Webassembly.cspec" id="default"/> </language> </language_definitions> 

يجب أن تكون السمة "المعالج" هي نفسها معالج السمة من ملف .opinion. دعنا نترك الحقول الأخرى دون مساس. ولكن تذكر في المرة القادمة أنه من الممكن تعيين مرارة التسجيل (السمة "الحجم") ، وهو الملف الذي يصف بنية المعالج "processorspec" والملف ، الذي يحتوي على وصف للكود بلغة تعريفية خاصة "slafile". سوف يأتي مفيد للعمل على التفكيك.

الآن ، حان الوقت للعودة إلى اللودر وإرجاع مواصفات اللودر.

كل شيء جاهز لتشغيل الاختبار. قام البرنامج الإضافي لـ GhidraDev بإضافة خيار التشغيل " Run → Run As → Ghidra " إلى الكسوف:



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



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

رمز الوحدة متاح في مستودع جيثب .

Source: https://habr.com/ru/post/ar443318/


All Articles