Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

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

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
Mergen — إزالة التعتيم عبر التحسين باستخدام LLVM IR وتحليل لغة التجميع. | Kitploit
أدوات/GitHubGitHub/nac-l/mergen
التحليل الثابتالتحليل الديناميكي (عزل)الهندسة العكسيةتحليل الملفات الثنائيةاستغلال الملفات الثنائية
GitHubnac-l/mergen

Mergen

إزالة التعتيم عبر التحسين باستخدام LLVM IR وتحليل لغة التجميع.

عرض المستودع
87894منذ 3 أشهرتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

نظرة عامة على المشروع:

Mergen هي أداة مصممة لتحويل كود التجميع (Assembly) إلى التمثيل الوسيط لـ LLVM (IR). هذه الأداة مصممة من أجل:

  • إزالة التعتيم أو إزالة الافتراضية (devirtualization) للكود الثنائي المعتّم
  • تحسين عملية الهندسة العكسية، وجعلها أكثر كفاءة وفعالية، خاصة للأنظمة البرمجية المعقدة.

دليل البناء والتشغيل

لبناء المشروع وتشغيله، ألقِ نظرة على docs/BUILDING.md.

بوابة خط الأساس لإعادة الكتابة

يجب أن يُبقي عمل إعادة الكتابة بوابة انحدار خط الأساس خضراء. تقوم البوابة ببناء عينات PE مركزة، وتشغيل lifter، والتحقق من مخرجات IR المرفوعة.

  • وثيقة سير العمل: docs/REWRITE_BASELINE.md
  • بوابة بأمر واحد: scripts\\rewrite\\run.cmd

الأهداف الأساسية:

  • إزالة التعتيم

  • إزالة الافتراضية

  • التحسين

كيف يعمل؟

نقوم بالتنفيذ الرمزي (أو الرفع الرمزي) للهدف، والفكرة هنا ليست رفع التعليمات الفردية، بل رفع دالة كاملة. لا نتوقع أن تتصرف تعليمة واحدة أو كتلة أساسية واحدة بنفس الطريقة في كل مرة، بل نتعامل معها كما لو أنها يمكن أن تكون ولأغراض مختلفة في كل مرة. نحاول إبقاء الـ IR المُولَّد بسيطًا وقابلًا للتحسين قدر الإمكان. لدينا أيضًا احتياجات مختلفة عن المترجم المعتاد. نستخدم التحليل لتقييم تدفق التحكم. لا يمكننا الاعتماد على LLVM في كل تحليلاتنا، لأنها أُنشئت لأهداف مختلفة وقد تكون غير مثالية لحالة استخدامنا.

image

أمثلة

هذا هو المثال العملي لتوضيح كيفية تعامل Mergen مع البرامج المُخْتَلَقة (المُعتمد على الأجهزة الافتراضية).

  1. VMProtect
  2. Branches/Jumptables
  3. Themida 3.1.6.0 LION64 (Red)

المثال الأول (VMProtect)

هذا هو برنامجنا الهدف

root@kitploit:~
struct test {
    int a;
    int b;
    int c;
};

int maths(test a, int b, int c) {
        return a.a  + b - c;
}

image

image

إعدادات VMProtect، كل شيء مغلق، نقوم باختزال (virtualize) الدالة على الإعداد الفائق. (الإصدارات المختبرة 3.4.0-3.6.0 3.8.1)

image

image

هنا، نشغّل mergen. الوسيطة الأولى هي اسم الملف والوسيطة الثانية هي عنوان الدالة. انظر كم هو بسيط التشغيل. ويمكننا تجميع المخرجات لاستكشافها باستخدام مفككنا المفضل.

image

root@kitploit:~
; ModuleID = 'my_lifting_module'
source_filename = "my_lifting_module"

; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
define i64 @main(i64 %rax, i64 %rcx, i64 %rdx, i64 %rbx, i64 %0, i64 %rbp, i64 %rsi, i64 %rdi, i64 %r8, i64 %r9, i64 %r10, i64 %r11, i64 %r12, i64 %r13, i64 %r14, i64 %r15, ptr nocapture readonly %memory) local_unnamed_addr #0 {
entry:
  %stackmemory = alloca i128, i128 13758960, align 8
  %1 = trunc i64 %r8 to i32
  %2 = trunc i64 %rdx to i32
  %GEPLoadxd-5369456437- = getelementptr i8, ptr %memory, i64 %rcx
  %3 = load i32, ptr %GEPLoadxd-5369456437-, align 4
  %adc-temp-5370242400- = sub i32 %2, %1
  %realnot-5369532059- = add i32 %adc-temp-5370242400-, %3
  %stackmemory10243.sroa.55.1375304.insert.ext10255 = zext i32 %realnot-5369532059- to i64
  ret i64 %stackmemory10243.sroa.55.1375304.insert.ext10255
}

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }

بعد التجميع:

image

image

الآن قد تلاحظ أن السجلات غير مضبوطة قليلاً. هذا لأننا لا نتبع اصطلاحات الاستدعاء، فلو اتبعنا اصطلاحات الاستدعاء، لكان توقيع الدالة بهذا الشكل:

root@kitploit:~
define i64 @main(i64 %rcx, i64 %rdx, i64 %rdx, i64 %r8, i64 %r9 ...)

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

المثال الثاني (الفروع/جداول القفز)

لنفترض أن لدينا هذا الكود. ستأخذ الأجهزة الافتراضية (VM's) الكود التالي وتحوّله إلى قفزة غير مباشرة، وهذا غير مريح بعض الشيء للمهندس العكسي.

root@kitploit:~
int maths(int a, int b, int c) {
    if (a > b)
        return a + b + c;
    else
        return a - b - c;
}
root@kitploit:~
next_handler = xxx;
if ( a-b > 0 )
  next_handler = yyy;
jump next_handler;

نحاول دائمًا تحليل القيم وتتبعها. وهذا يتيح لنا فهم تدفق التحكم. للفروع الشبيهة بجدول القفز

سيكون الناتج المُحسَّن بسيطًا:

root@kitploit:~
define i64 @main(i64 %rax, i64 %rcx, i64 %rdx, i64 %rbx, i64 %rsp, i64 %rbp, i64 %rsi, i64 %rdi, i64 %r8, i64 %r9, i64 %r10, i64 %r11, i64 %r12, i64 %r13, i64 %r14, i64 %r15, ptr nocapture readnone %TEB, ptr nocapture readnone %memory) local_unnamed_addr #0 {
fake_ret:
  %0 = lshr i64 %rcx, 62
  %common.ret.op = and i64 %0, 2
  ret i64 %common.ret.op
}

الناتج غير المُحسَّن. (تمت إزالة الكود الميت (DCE) من أجل سهولة القراءة)

root@kitploit:~
source_filename = "my_lifting_module"

define i64 @main(i64 %rax, i64 %rcx, i64 %rdx, i64 %rbx, i64 %rsp, i64 %rbp, i64 %rsi, i64 %rdi, i64 %r8, i64 %r9, i64 %r10, i64 %r11, i64 %r12, i64 %r13, i64 %r14, i64 %r15, ptr %TEB, ptr %memory) {
  %lsb = and i64 %rcx, 255
  %pf1 = mul i64 %lsb, 72340172838076673
  %pf2 = and i64 %pf1, -9205322385119247871
  %pf3 = urem i64 %pf2, 511
  %pf4 = and i64 %pf3, 1
  %pf5 = icmp eq i64 0, %pf4
  %0 = zext i1 %pf5 to i64
  %createrflag2 = shl i64 %0, 2
  %creatingrflag = or i64 2, %createrflag2
  %zeroflag = icmp eq i64 %rcx, 0
  %1 = zext i1 %zeroflag to i64
  %createrflag21 = shl i64 %1, 6
  %creatingrflag2 = or i64 %creatingrflag, %createrflag21
  %signflag = icmp slt i64 %rcx, 0
  %2 = zext i1 %signflag to i64
  %createrflag23 = shl i64 %2, 7
  %creatingrflag4 = or i64 %creatingrflag2, %createrflag23
  %GEPSTORE-5368713221- = getelementptr i8, ptr %memory, i64 1376032
  store i64 %creatingrflag4, ptr %GEPSTORE-5368713221-, align 4
  %realand-5368713229- = and i64 %creatingrflag4, 128
  %shr-lshr-5368713233- = lshr i64 %realand-5368713229-, 7
  %3 = mul i64 %shr-lshr-5368713233-, 4
  %bvalue_indexvalue = add i64 5368713249, %3
  %4 = icmp eq i64 %bvalue_indexvalue, 5368713253
  %lolb- = select i1 %4, i64 5368713264, i64 5368713257
  %GEPSTORE-5368713248- = getelementptr i8, ptr %memory, i64 1376032
  store i64 %lolb-, ptr %GEPSTORE-5368713248-, align 4
  br i1 %4, label %real_ret, label %real_ret41

real_ret:                                         ; preds = %fake_ret
  %inc-5368713273- = add i64 %shr-lshr-5368713233-, 1
  ret i64 %inc-5368713273-

real_ret41:                                       ; preds = %fake_ret
  ret i64 %shr-lshr-5368713233-
}

لاحظ هذا الجزء:

root@kitploit:~
  %realand-5368713229- = and i64 %creatingrflag4, 128
  %shr-lshr-5368713233- = lshr i64 %realand-5368713229-, 7

نحصل على الأعلام، ثم نحصل على البتة السابعة وهي علامة الإشارة (Sign Flag)، ثم نستخدم علامة الإشارة لحساب عنوان. من خلال التحليل، نحدد أن العنوان يمكن أن يكون واحدًا من قيمتين، 5368713257 أو 5368713264، ثم نحول ذلك إلى مقارنة. إذا كان العنوان 5368713257، نسلك فرعًا، وإذا كان الآخر، نسلك فرعًا آخر. عند القيام بذلك، من المهم أيضًا تعليم الشرط بالقيمة المناسبة لأنه لاحقًا قد نحتاج إلى حساب قفزة أخرى بنفس القيمة تمامًا.

على الرغم من أننا نحل القفزات غير المباشرة، إلا أن القفزات التي تحتوي على أكثر من موقعين محتملين غير مدعومة. وذلك لأن التحليل الخاص بها غير منفَّذ بعد. هذا يتيح لنا حل الفروع بنمط VM، لكننا نواجه مشكلة مع جداول القفز الواقعية.

المثال الثالث (Themida 3.1.6.0 LION64 (Red))

برنامجنا الهدف:

image

إعدادات Themida (نهتم فقط بالأجهزة الافتراضية حاليًا):

image

image

image

بعد الاختزال (vm):

image

تشغيل Mergen:

image

الكود الناتج: اضغط هنا

إذًا، لماذا ليست نتيجتنا ناجحة بقدر رفع ثنائي محمي بواسطة vmp؟

يكتب Themida بنشاط في قسم .themida. وعلى عكس المكدس، لا يمكننا تجاهل هذه الكتابات، لأن هذه القيم قد تُقرأ بواسطة أشياء أخرى لاحقًا.

لكن لدينا حل مؤقت لذلك. قم بإزالة جميع عمليات التخزين في قسم .themida. وبما أن برنامجنا لا يكتب في الذاكرة، لقد قمت فقط بتعليق كل عمليات التخزين. الآن تبقى لدينا هذا:

root@kitploit:~
source_filename = "my_lifting_module"

define i64 @main(i64 %rax, i64 %rcx, i64 %rdx, i64 %rbx, i64 %rsp, i64 %rbp, i64 %rsi, i64 %rdi, i64 %r8, i64 %r9, i64 %r10, i64 %r11, i64 %r12, i64 %r13, i64 %r14, i64 %r15, ptr writeonly %memory) local_unnamed_addr #0 {
  %trunc = trunc i64 %r8 to i32
  %trunc1 = trunc i64 %rdx to i32
  %trunc2 = trunc i64 %rcx to i32
  %realadd-5369771371- = add i32 %trunc1, %trunc2
  %realadd-5369582686- = add i32 %realadd-5369771371-, %trunc
  %trunc457139 = zext i32 %realadd-5369582686- to i64
  ret i64 %trunc457139
}

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }

التحديات التقنية

  • الحلقات
  • الكود ذاتي التعديل (خاصة مع التعديل الشرطي)
  • الوجود في عالم لا توجد فيه تمريرات "outlining" و"unrolling".

التواصل

انضم إلى خادم Discord الخاص بـ Mergen لتبادل الأفكار أو مجرد الدردشة بشكل عام.

تنزيل الأداة