
Greybox-Synthesizer, ausgerichtet auf die Deobfuskierung von Assembler-Anweisungen.
QSynthesis ist eine Python3-API zur Durchführung I/O-basierter Programmsynthese von Bitvektor-Ausdrücken. Sie zielt darauf ab, die Code-Deobfuskierung zu erleichtern. Der Algorithmus ist ein Greybox-Ansatz, der sowohl eine Blackbox-I/O-basierte Synthese als auch eine Whitebox-AST-Suche kombiniert, um Teilausdrücke zu synthetisieren (falls der Wurzelknoten nicht synthetisiert werden kann).
Dieser Algorithmus wurde ursprünglich auf dem BAR Academic Workshop beschrieben:
Der Code wurde als Teil des folgenden Black-Hat-Vortrags veröffentlicht:
Haftungsausschluss: Dieses Framework ist experimentell und darf nur zu Experimentierzwecken verwendet werden. Es zielt hauptsächlich darauf ab, die Forschung in diesem Bereich anzuregen.
Die Installation, Beispiele und die API-Dokumentation sind in der dedizierten Dokumentation verfügbar: Documentation
Die Kern-Synthese basiert auf der symbolischen Engine Triton, auf der das gesamte Framework aufbaut. Es bietet die folgenden Funktionalitäten:
Um zu funktionieren, muss zunächst Triton installiert werden: install documentation. Triton installiert sich nicht automatisch in einer virtualenv; kopieren Sie es in Ihre venv oder verwenden Sie --system-site-packages bei der Konfiguration Ihrer venv.
Dann:
$ git clone https://github.com/quarkslab/qsynthesis.git
$ cd qsynthesis
$ pip3 install '.[all]'
Das [all] installiert alle Abhängigkeiten (siehe die Dokumentation für eine leichte Installation).
Der Synthesealgorithmus erfordert die Generierung von Orakeltabellen, die aus einer Grammatik (einer
Menge von Variablen und Operatoren) abgeleitet werden. Die Qsynthesis-Installation stellt das Dienstprogramm qsynthesis-table-manager
zur Verfügung, das die Manipulation von Tabellen ermöglicht. Der folgende Befehl generiert eine Tabelle mit 3 Variablen von 64 Bit,
5 Operatoren unter Verwendung eines Vektors von 16 Eingaben. Wir begrenzen die Generierung auf 5 Millionen Einträge.
$ qsynthesis-table-manager generate -bs 64 --var-num 3 --input-num 16 --random-level 5 --ops AND,NEG,MUL,XOR,NOT --watchdog 80 --limit 5000000 my_oracle_table
Generate Table
Watchdog value: 80.0
Depth 2 (size:3) (Time:0m0.23120s)
Depth 3 (size:21) (Time:0m0.23198s)
Depth 4 (size:574) (Time:0m0.26068s)
Depth 5 (size:400858) (Time:0m21.23231s)
Threshold reached, generation interrupted
Stop required
Depth 5 (size:5000002) (Time:4m52.56009s) [RAM:9.52Gb]
Hinweis: Der Generierungsprozess ist RAM-intensiv; das --watchdog ermöglicht die Einstellung eines
Prozentsatzes des RAMs, bei dessen Überschreitung die Generierung unterbrochen wird.
Wir können dann versuchen, einen scheinbar obfuskierten Ausdruck zu vereinfachen mit:
from qsynthesis import SimpleSymExec, TopDownSynthesizer, InputOutputOracleLevelDB
blob = b'UH\x89\xe5H\x89}\xf8H\x89u\xf0H\x89U\xe8H\x89M\xe0L\x89E\xd8H\x8bE' \
b'\xe0H\xf7\xd0H\x0bE\xf8H\x89\xc2H\x8bE\xe0H\x01\xd0H\x8dH\x01H\x8b' \
b'E\xf8H+E\xe8H\x8bU\xe8H\xf7\xd2H\x0bU\xf8H\x01\xd2H)\xd0H\x83\xe8' \
b'\x02H!\xc1H\x8bE\xe0H\xf7\xd0H\x0bE\xf8H\x89\xc2H\x8bE\xe0H\x01\xd0' \
b'H\x8dp\x01H\x8bE\xf8H+E\xe8H\x8bU\xe8H\xf7\xd2H\x0bU\xf8H\x01\xd2' \
b'H)\xd0H\x83\xe8\x02H\t\xf0H)\xc1H\x89\xc8H\x83\xe8\x01]\xc3'
# Perform symbolic execution of the instructions
symexec = SimpleSymExec("x86_64")
symexec.initialize_register('rip', 0x40B160) # arbitrary address
symexec.initialize_register('rsp', 0x800000) # arbitrary stack
symexec.execute_blob(blob, 0x40B160)
rax = symexec.get_register_ast("rax") # retrieve rax register expressions
# Load lookup tables
ltm = InputOutputOracleLevelDB.load("my_oracle_table")
# Perform Synthesis of the expression
synthesizer = TopDownSynthesizer(ltm)
synt_rax, simp = synthesizer.synthesize(rax)
print(f"expression: {rax.pp_str}")
print(f"synthesized expression: {synt_rax.pp_str} [{simp}]")
Großer Dank an die Mitwirkenden dieser Forschung: