Bytecode Simplifier ist ein Werkzeug, um python -Skripte von Pjorionen zu deobfuscieren. Dies ist eine vollständige Umschrift meines älteren Werkzeugs Pjorion Deobfuscator
Sie müssen die folgenden Pakete vorinstalliert haben:
Beide Pakete sind pip installierbar. Stellen Sie außerdem sicher, dass die ausführbare Datei GraphViz in Ihrem Weg für pydotplus funktioniert. pydotplus ist nur zum Zeichnen von Diagramme erforderlich. Wenn Sie diese Funktion nicht möchten, können Sie die render_graph -Aufrufe in deobfuscate -Funktion in der Datei deobfuscator.py kommentieren.py
Pjorion verschleiert die Originaldatei und führt darauf ein, wobei mehrere Wrapper -Schichten darüber stehen. Der Zweck dieser Ebenen besteht einfach darin, die nächste innere Ebene (sozusagen) zu entschlüsseln und über einen EXEC_STMT -Anweisungen auszuführen. Daher können Sie dieses Tool nicht wie in einer verschleierten Datei verwenden. Zunächst müssten Sie die Wrapper -Ebenen entfernen und das tatsächliche verschleierte Codeobjekt erhalten. Anschließend können Sie den verschleierten Code zum Festplatten marschieren und dieses Tool darauf ausführen, das Ihnen hoffentlich den deobfuszierten Code zurückgeben sollte.
Weitere Informationen finden Sie in diesem Blog -Beitrag.
Bytecode Simplifier analysiert verschleierten Code unter Verwendung eines rekursiven Ansatzes für die Demontage. Die Anweisungen werden zerlegt und zu grundlegenden Blöcken kombiniert. Ein Basisblock ist eine Folge von Anweisungen mit einem einzelnen Eintrag und einem einzigen Ausgang.
Ein grundlegender Block kann mit einem Steuerflussanweisungen wie einer if -Anweisung enden. Eine if -Aussage hat zwei Zweige - wahr und falsch. Entsprechend den Basisblöcken der Zweige haben Kanten. Diese gesamte Struktur wird durch eine gerichtete Grafik dargestellt. Zu diesem Zweck verwenden wir networkx.DiGraph .
Die Knoten in der Grafik repräsentieren die Basisblöcke, während die Kanten zwischen den Knoten den Steuerfluss zwischen den Basisblöcken darstellen.
Eine bedingte Steuerungsübertragungsanweisung wie if es zwei Zweige hat - die wahre Zweigstelle, die ausgeführt wird, wenn die Bedingung gilt. Wir markieren diesen Zweig als expliziten Rand, da dieser Zweig explizit durch die if -Anweisung angegeben ist. Der andere Zweig, nämlich. Der falsche wird als implizite Rand markiert, wie er logisch abgeleitet wird.
Ein bedingungsloser Kontrollübertragungsanweis wie jump hat nur einen expliziten Vorsprung.
Sobald wir den Code in einem Diagrammformular haben, ist es einfacher, den Code zu begründen. Daher erfolgt die Vereinfachung des verschleierten Codes in dieser Grafik.
Es werden hauptsächlich zwei Vereinfachungsstrategien verwendet:
Ein Spediteur ist ein Basisblock, der aus einer einzigen bedingungslosen Kontrollflussanleitung besteht. Ein Spediteur überträgt die Ausführung auf einen anderen Grundblock, ohne nützliche Arbeiten zu erledigen.
Vorwärtsausscheidung

Das in Gelb hervorgehobene Basic blockiert ist ein Spediteurblock. Es kann beseitigt werden, um die folgende Struktur unten zu geben.
Nach der Ausscheidung des Spediteurs

Ein Spediteur kann jedoch nicht immer speziell in Fällen beseitigt werden, in denen der Spediteur impliziten Hötrungen hat. Weitere Informationen finden Sie in Simplifier.py
Ein grundlegender Block kann nur dann zu seinem Vorgänger zusammengefasst werden, wenn genau ein Vorgänger vorhanden ist und der Vorgänger diesen grundlegenden Block als einzelner Nachfolger hat.
Vor dem Zusammenführen

Die hervorgehobenen Anweisungen der Basisblöcke wurden zusammengeführt, um einen größeren Grundblock zu bilden, der unten gezeigt wurde. Die Anweisungen zur Steuerungstransfer wurden entfernt, da sie nicht mehr benötigt werden.
Nach dem Zusammenführen

Sobald das Diagramm vereinfacht wurde, müssen wir die Grundblöcke wieder in einen flachen Code zusammenstellen. Dies wird im Datei Assembler.py implementiert.
Der Montageprozess an sich besteht aus Unterstufen:
JUMP_FORWARD auf JUMP_ABSOLUTE : Wenn der Basisblock A einen relativen Steuerflussanweis für Block B hat, muss sich Block B nach Block A im erzeugten Layout befinden. Dies liegt daran, dass die Anweisungen zur relativen Kontrollfluss normalerweise verwendet werden, um sich auf Adressen zu beziehen, die danach gefunden wurden. Wenn die relative CF -Anweisung JUMP_FORWARD ist, können wir uns zu JUMP_ABSOLUTE ändern.SETUP_LOOP, SETUP_EXCEPT usw. müssen wir einen neuen Spediteur-Block erstellen, der aus einem absoluten Sprunganweisungen zum Block B besteht, und den relativen Steuerflussanweisungen in Block A auf den Spediteur-Block zu verweisen. Dies funktioniert, da der Forwarder -Block natürlich nach dem Block A im erzeugten Layout erfolgt, und relative Anweisungen können immer verwendet werden, um auf Blöcke zu verweisen, die danach gefunden wurden, dh eine höhere Adresse.JUMP_FORWARD & SETUP_LOOP verwendet den Operand, um sich auf andere Anweisungen zu verweisen. Diese Referenz ist eine Ganzzahl, die die Offset/absolute Adresse des Ziels bezeichnet. $ python main.py --ifile=obfuscated.pyc --ofile=deobfuscated.pyc
INFO:__main__:Opening file obfuscated.pyc
INFO:__main__:Input pyc file header matched
DEBUG:__main__:Unmarshalling file
INFO:__main__:Processing code object x0bx08x0cx19x0bx0ex03
DEBUG:deobfuscator:Code entrypoint matched PjOrion signature v1
INFO:deobfuscator:Original code entrypoint at 124
INFO:deobfuscator:Starting control flow analysis...
DEBUG:disassembler:Finding leaders...
DEBUG:disassembler:Start leader at 124
DEBUG:disassembler:End leader at 127
.
<snip>
.
DEBUG:disassembler:Found 904 leaders
DEBUG:disassembler:Constructing basic blocks...
DEBUG:disassembler:Creating basic block 0x27dc5a8 spanning from 13 to 13, both inclusive
DEBUG:disassembler:Creating basic block 0x2837800 spanning from 5369 to 5370, end exclusive
.
<snip>
.
DEBUG:disassembler:461 basic blocks created
DEBUG:disassembler:Constructing edges between basic blocks...
DEBUG:disassembler:Adding explicit edge from block 0x2a98080 to 0x2aa88a0
DEBUG:disassembler:Adding explicit edge from block 0x2aa80f8 to 0x2a9ab70
DEBUG:disassembler:Basic block 0x2aa8dc8 has xreference
.
<snip>
.
INFO:deobfuscator:Control flow analysis completed.
INFO:deobfuscator:Starting simplication of basic blocks...
DEBUG:simplifier:Eliminating forwarders...
INFO:simplifier:Adding implicit edge from block 0x2aa8058 to 0x2a9ab70
INFO:simplifier:Adding explicit edge from block 0x2b07ee0 to 0x2a9ab70
DEBUG:simplifier:Forwarder basic block 0x2aa80f8 eliminated
.
<snip>
.
INFO:
INFO:simplifier:307 basic blocks merged.
INFO:deobfuscator:Simplication of basic blocks completed.
INFO:deobfuscator:Beginning verification of simplified basic block graph...
INFO:deobfuscator:Verification succeeded.
INFO:deobfuscator:Assembling basic blocks...
DEBUG:assembler:Performing a DFS on the graph to generate the layout of the blocks.
DEBUG:assembler:Morphing some JUMP_ABSOLUTE instructions to make file decompilable.
DEBUG:assembler:Verifying generated layout...
INFO:assembler:Basic block 0x2b0e940 uses a relative control transfer instruction to access block 0x2abb3a0 located before it.
INFO:assembler:Basic block 0x2ab5300 uses a relative control transfer instruction to access block 0x2ada918 located before it.
DEBUG:assembler:Successfully verified layout.
DEBUG:assembler:Calculating addresses of basic blocks.
DEBUG:assembler:Calculating instruction operands.
DEBUG:assembler:Generating code...
INFO:deobfuscator:Successfully assembled.
INFO:__main__:Successfully deobfuscated code object main
INFO:__main__:Collecting constants for code object main
INFO:__main__:Generating new code object for main
INFO:__main__:Generating new code object for x0bx08x0cx19x0bx0ex03
INFO:__main__:Writing deobfuscated code object to disk
INFO:__main__:Success