P01NT
Reverse-Engineering

Flare-On 2014: حل التحدي الأول

نحل أول تحدٍّ من تحديات Flare-On (2014): برنامج .NET، فحص أولي بأداة DIE، تفكيك عبر ILSpy، وفك تشفير العلم (Flag) بكتابة سكريبت Python.

· 5 دقائق قراءة · 902 كلمة  | الترجمات:
المحتويات

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

في هذا المقال، سوف نحل التحدي الأول من تحديات Flare-On (2014). سنعتمد في هذا الحل — وفي غالبية التحديات القادمة — على منهجية التعلم في الوقت المناسب (Just-in-Time Learning) أو ما يُعرف بالتعلم بالممارسة (Learning-by-Doing).

لماذا بدأنا بتحديات Flare-On؟

لأن هذه التحديات مبنية على تقنيات واقعية من العالم الحقيقي (Real-World)، وليست مجرد تحديات CTF مصطنعة تُقدَّم عادةً في المسابقات.

ملاحظة مهمة: تحديات الـ CTF هي فقط جسرٌ بين التعلم النظري والتطبيق العملي، ولا تدل بأي شكل من الأشكال على أنك شخص قوي في المجال. الخبرة الحقيقية تُكتسب من التعامل مع البرامج الواقعية (Real-World) — سواء كانت برمجيات خبيثة (Malware) أو ألعاباً أو برامج نقوم بهندستها عكسياً.

أي اقتراح لتطوير هذه المقالات، أو أي خطأ، أو أي استفسار، فالتواصل معي متاح دائماً إن شاء الله.

إن أحسنت فمن الله، وإن أسأت فمن نفسي والشيطان.


1. تحميل التحدي والفحص الأولي

أولاً، نقوم بتحميل التحدي من الموقع الرسمي: flare-on.com

كلمة سر الملفات: إما flare أو infected.

بدايةً، نقوم بفحص البرنامج بأداة Detect It Easy (DIE) لنعرف معلومات عنه، فنحصل على المعلومات التالية:

نتيجة الفحص بأداة DIE شكل (1): معلومات الملف كما تظهرها أداة DIE

كما هو واضح، إنه برنامج بصيغة PE32 ومكتوب بلغة C#.


2. أساسيات مهمة عن برامج .NET

قبل البدء بالحل، من الضروري أن نعرف بعض المعلومات عن برامج .NET، لأنها تختلف تماماً عن برامج C/C++.

برامج C/C++

عند كتابة برامج بلغة C/C++، نستخدم مترجماً (Compiler) مثل GCC. يمر البرنامج بمرحلتين بشكل مختصر:

  1. الترجمة المباشرة (Ahead-of-Time Compilation): يأخذ المترجم الكود المصدري (Source Code) ويحوّله مباشرة إلى كود الآلة (Machine Code).
  2. الربط (Linking): يتم دمج المكتبات الخارجية مع الكود ليصبح ملفاً تنفيذياً (.exe).

برامج C# (.NET)

بينما تمر برامج C#/.NET بعملية مختلفة يمكننا تسميتها البرمجة المُدارة (Managed Code): لا تُترجم برامج .NET مباشرة إلى لغة الآلة، بل تمر بمرحلتين وتعمل داخل بيئة تشغيل تُسمى CLR - Common Language Runtime.

المرحلة الأولى: وقت الترجمة (Compile Time)

عند عمل Build لبرنامج C#، لا يتم تحويله إلى لغة آلة مباشرة، بل يحدث التالي:

  1. يقوم مترجم .NET (مثل Roslyn) بتحويل الكود إلى وسيطة تُسمى IL - Intermediate Language، وهي لغة تشبه لغة التجميع (Assembly) لكنها غير مرتبطة بمعمارية معالجة (CPU Architecture) معينة.
  2. يتم تجميع هذا الكود الوسيط مع البيانات الوصفية (Metadata) داخل ملف Assembly بامتداد .dll أو .exe.
  3. يمكن أخذ هذا الملف نفسه وتشغيله على لينكس وويندوز وماك.

المرحلة الثانية: وقت التشغيل (Runtime)

عند فتح البرنامج، يتدخل الـ CLR (محرك تشغيل .NET):

  1. يقرأ الـ CLR ملف الـ Assembly الذي يحتوي على الـ IL.
  2. يستخدم مترجماً يُسمى JIT - Just-in-Time Compiler.
  3. يقوم الـ JIT بتحويل الـ IL إلى لغة الآلة الأصلية (Native) في نفس لحظة تشغيل البرنامج، ويحوّل فقط الأجزاء التي يحتاجها البرنامج في تلك اللحظة.

3. تشغيل البرنامج وملاحظة السلوك

نقوم بتشغيل البرنامج (Run) لنلاحظ سلوكه:

الواجهة الأولى للبرنامج شكل (2): الواجهة الأولية للبرنامج

كما هو واضح في الصورة، توجد شخصية مكتوب فوقها “Let’s start with something easy!"، وأسفلها زر Decode. عند الضغط عليه، تتغير الصورة وتظهر بالشكل التالي:

الواجهة بعد الضغط على زر Decode شكل (3): الواجهة بعد الضغط على زر Decode

كما هو مبين، تظهر الفروق بوضوح في الصورة. المطلوب منا هنا هو معرفة النص المشفر الظاهر في الصورة.


4. التفكيك باستخدام ILSpy

كما أوضحنا أعلاه كيفية ترجمة برامج .NET، فإن هذا يسهل علينا الكثير من الأمور، مثل العمل على مُفكِّك (Decompiler) مع التأكد من أن الكود الذي يُخرجه هو نفسه الكود الأصلي. لذلك سنستخدم مُفكِّك ILSpy للتعامل مع هذا البرنامج.

فتح البرنامج داخل ILSpy شكل (4): فتح البرنامج داخل ILSpy

بما أن أمامنا نافذة (Form)، سنركز على الموارد (Resources) الموجودة داخلها:

الموارد الموجودة داخل البرنامج شكل (5): الموارد الموجودة داخل الـ Form

كما هو واضح، يوجد ثلاثة ملفات، وأحدها مشبوه لأنه يحمل اللاحقة .encode، وهذا شيء يتعلق بالتشفير.

الآن، ننتقل إلى المنطق الأساسي (Core Logic) الذي يحتوي على خوارزمية التشفير، ولذلك نبحث في كود الـ Form:

البحث في كود الـ Form شكل (6): استعراض كود الـ Form

يظهر لنا الكود التالي:

الكود الخاص بدالة btnDecode_Click شكل (7): الكود الذي يظهر في نافذة ILSpy

دالة btnDecode_Click: هذا النمط هو كود زر Decode (ماذا يحدث عند الضغط عليه):

  1. أولاً، تُستبدل الصورة بصورة اسمها bob_roge.
  2. يُعرّف مصفوفة بايتات اسمها dat_secret — وهي نفسها الموجودة في الـ Resources — وغالباً ما تكون هذه المصفوفة هي النص الأصلي الذي يتم تشفيره.
  3. تُطبَّق خوارزمية التشفير.

هنا نلاحظ استخدام ما يُسمى بالتمويه (Obfuscation). سنركز فقط على المتغير text والخوارزمية المرتبطة به:

خوارزمية التشفير في الكود شكل (8): الخوارزمية في الكود بعد إزالة التمويه

تتألف الخوارزمية من تبديل الأنصاف (Nipple Swap) وعملية XOR:

  • Nipple Swap: مثلاً، إذا كان لدينا البايت 0011 1100، بعد تطبيق عملية التبديل عليه يصبح 1100 0011؛ أي أنه يقوم بتبديل النصف الأيمن بالنصف الأيسر.
  • بعد التبديل، يقوم بعملية XOR مع القيمة 0x29.

وما تبقى من الكود نتجاهله.


5. كتابة سكريبت الحل (Solver)

الآن، نقوم بتصدير ملف dat_secret من الـ Resources:

تصدير ملف dat_secret شكل (9): تصدير ملف dat_secret

سنطلب من أي نموذج ذكاء اصطناعي كتابة سكريبت بايثون (Solver) لفك تشفير ملف dat_secret:

def decode_dat_secret(file_path):
    try:
        with open(file_path, 'rb') as f:
            dat_secret = f.read()
    except FileNotFoundError:
        print("لم يتم العثور على الملف. تأكد من أن ملف 'dat_secret' موجود في نفس المسار.")
        return None

    text = []
    for b in dat_secret:
        # (b >> 4) يجلب الجزء العلوي (High Nibble)
        # ((b << 4) & 0xF0) يجلب الجزء السفلي (Low Nibble) ويرفعه للأعلى
        dec_val = ((b >> 4) | ((b << 4) & 0xF0)) ^ 0x29
        if dec_val == 0x00:  # توقف عند المحرف الفارغ (Null Terminator)
            break
        text.append(chr(dec_val))

    return "".join(text)


if __name__ == "__main__":
    file_name = "dat_secret"  # ضع مسار الملف هنا
    result = decode_dat_secret(file_name)
    print("--- النص بعد فك التشفير ---")
    print(result)

يجب التأكد من أن ملف البايثون في نفس مسار ملف dat_secret.

نقوم بتشغيل سكريبت البايثون:

نتيجة تشغيل السكريبت شكل (10): النص بعد فك التشفير

وبهذا نكون قد أنهينا حل التحدي بنجاح، ونستمر إن شاء الله.