Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
Mergen — Deobfuskation durch Optimierung unter Verwendung von LLVM IR und Parsen von Assembly. | Kitploit
Tools/GitHubGitHub/nac-l/mergen
Statische AnalyseDynamische Analyse (Sandboxing)Reverse EngineeringBinäranalyseBinary-Exploitation
GitHubnac-l/mergen

Mergen

Deobfuskation durch Optimierung unter Verwendung von LLVM IR und Parsen von Assembly.

Repository anzeigen
87894vor 3 MonatenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Projektübersicht:

Mergen ist ein Tool, das entwickelt wurde, um Assembler-Code in die LLVM-Zwischendarstellung (IR) zu konvertieren. Dieses Tool ist konzipiert für:

  • Die Entschleierung oder Devirtualisierung von verschleiertem Binärcode
  • Die Verbesserung des Reverse-Engineering-Prozesses, um ihn effizienter und effektiver zu gestalten, insbesondere für komplexe Softwaresysteme.

Leitfaden zum Erstellen und Ausführen

Um das Projekt zu erstellen und auszuführen, werfen Sie einen Blick auf docs/BUILDING.md.

Rewrite-Baseline-Gate

Rewrite-Arbeiten sollten das Baseline-Regressionsgate grün halten. Das Gate erstellt fokussierte PE-Beispiele, führt lifter aus und überprüft die gelifteten IR-Ausgaben.

  • Workflow-Dokument: docs/REWRITE_BASELINE.md
  • Ein-Befehl-Gate: scripts\\rewrite\\run.cmd

Kernziele:

  • Entschleierung

  • Devirtualisierung

  • Optimierung

Wie funktioniert es?

Wir führen eine symbolische Ausführung (oder symbolisches Liften) des Ziels durch. Die Idee hierbei ist, nicht einzelne Instruktionen zu liften, sondern eine gesamte Funktion. Wir erwarten nicht, dass eine einzelne Instruktion oder ein einzelner Basisblock jedes Mal gleich verhält, sondern behandeln sie so, als ob sie jedes Mal für unterschiedliche Zwecke da sein können und sind. Wir versuchen, das generierte IR so einfach und optimierbar wie möglich zu halten. Wir haben auch andere Anforderungen als ein üblicher Compiler. Wir nutzen Analysen, um den Kontrollfluss auszuwerten. Wir können uns nicht auf LLVM für alle unsere Analysen verlassen, da sie für andere Ziele erstellt wurden und für unseren Anwendungsfall suboptimal sein könnten.

image

Beispiele

Dies ist das praktische Beispiel, um zu veranschaulichen, wie Mergen gegen virtualisierte Programme vorgeht.

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

Beispiel #1 (VMProtect)

Dies ist unser Zielprogramm

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-Einstellungen, alles ist ausgeschaltet, wir virtualisieren die Funktion auf Ultra-Einstellung. (Getestete Versionen 3.4.0-3.6.0 3.8.1)

image

image

Hier führen wir mergen aus. Das erste Argument ist der Name der Datei und das zweite Argument die Adresse der Funktion. Sehen Sie, wie einfach es auszuführen ist. Und wir können die Ausgabe kompilieren, um sie mit unserem bevorzugten Decompiler zu erkunden.

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) }

Nach dem Kompilieren:

image

image

Jetzt könnte Ihnen auffallen, dass die Register etwas falsch sind. Dies liegt daran, dass wir den Aufrufkonventionen nicht folgen. Wenn wir den Aufrufkonventionen folgen würden, würde die Funktionssignatur so aussehen:

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

Also passen wir einfach die Funktionssignatur an, damit sie normal aussieht. Wenn Sie weitere Fragen zu diesem Teil haben, empfehle ich Ihnen, sich über Aufrufkonventionen und ABI zu informieren.

Beispiel #2 (Verzweigungen/Springtabellen)

Nehmen wir an, wir haben diesen Code. VMs werden den untenstehenden Code nehmen und in einen indirekten Sprung umwandeln, was für den Reverse Engineer etwas unbequemer ist.

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;

Wir versuchen stets, Werte zu analysieren und im Auge zu behalten. Das ermöglicht es uns, den Kontrollfluss zu verstehen. Für Springtabellen-ähnliche Verzweigungen Optimierte Ausgabe wäre ein einfaches

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
}

Nicht optimierte Ausgabe. (DCE zur Lesbarkeit)

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-
}

Beachten Sie diesen Teil

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

Wir holen die Flags, dann das 7. Bit, das das Vorzeichen-Flag ist, und verwenden das Vorzeichen-Flag, um eine Adresse zu berechnen. Durch Analyse bestimmen wir, dass die Adresse einer von zwei Werten sein kann, 5368713257 oder 5368713264, dann wandeln wir das in einen Vergleich um. Wenn die Adresse 5368713257 ist, nehmen Sie einen Zweig, wenn die andere, den anderen. Dabei ist es auch wichtig, den Bedingungswert entsprechend zu markieren, da wir später möglicherweise einen weiteren Sprung mit dem exakt gleichen Wert berechnen müssen.

Obwohl wir die indirekten Sprünge auflösen, werden Sprünge mit mehr als 2 möglichen Zielen nicht unterstützt. Dies liegt daran, dass die Analyse dafür noch nicht implementiert ist. Damit können wir VM-artige Verzweigungen auflösen, haben aber Probleme mit echten Springtabellen.

Beispiel #3 (Themida 3.1.6.0 LION64 (Red))

Unser Zielprogramm:

image

Themida-Einstellungen (uns interessieren derzeit nur VMs):

image

image

image

Nach der Virtualisierung:

image

Mergen ausführen:

image

Ausgabecode: hier klicken Warum ist unser Ergebnis nicht so erfolgreich wie das Liften einer Binärdatei, die durch VMP geschützt ist?

Themida schreibt aktiv in den .themida-Abschnitt. Im Gegensatz zum Stack können wir diese Schreibvorgänge nicht ignorieren, da diese Werte später von anderen Komponenten gelesen werden könnten.

Aber wir haben eine vorübergehende Lösung dafür. Entfernen Sie alle Stores in den .themida-Abschnitt. Da unser Programm nicht in den Speicher schreibt, habe ich einfach alle Stores auskommentiert. Jetzt haben wir Folgendes übrig:

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) }

Technische Herausforderungen

  • Schleifen
  • Selbstmodifizierender Code (insbesondere mit bedingter Modifikation)
  • Sich in einem Universum zu befinden, in dem 'Outlining'- und 'Unrolling'-Passes nicht existieren.

Kontaktaufnahme

Treten Sie unserem Mergen Discord Server bei, um Ideen auszutauschen oder einfach nur zu plaudern.

Tool herunterladen