ByteCode Simplificateur est un outil pour désobfusquer les scripts Python protégés par pjorion. Ceci est une réécriture complète de mon ancien outil Pjorion Deobfuscator
Vous devez avoir les packages suivants préinstallés:
Les deux packages sont installables pip . De plus, assurez-vous que Graphviz Executable est sur votre chemin pour que pydotplus fonctionne. pydotplus est requis uniquement pour des graphiques de dessin et si vous ne souhaitez pas cette fonctionnalité, vous pouvez commenter les appels render_graph dans la fonction deobfuscate dans le fichier deobfuscator.py
Pjorion obscurcit le fichier d'origine et introduit plusieurs couches de wrapper par-dessus. Le but de ces couches est simplement de (en quelque sorte) décrypter la couche intérieure suivante et l'exécuter via une instruction EXEC_STMT . Vous ne pouvez donc pas utiliser cet outil tel quel sur un fichier obscurci. Tout d'abord, vous devrez supprimer les couches de wrapper et saisir l'objet de code obscurci réel. Ensuite, vous pouvez rassembler le code obscurci sur disque et exécuter cet outil qui devrait vous rendre, espérons-le, vous rendre le code désobfuscée.
Reportez-vous à cet article de blog pour plus de détails.
ByteCode Simplificateur analyse le code obscurci à l'aide d'une approche de démontage de traversée récursive. Les instructions sont démontées et combinées en blocs de base. Un bloc de base est une séquence d'instructions avec une seule entrée et une seule sortie.
Un bloc de base peut se terminer par une instruction de flux de contrôle tel qu'une instruction if . Une instruction if a deux branches - vrai et fausse. Correspondant aux branches Les blocs de base ont des bords entre eux. Toute cette structure est représentée par un graphique dirigé. Nous utilisons networkx.DiGraph à cet effet.
Les nœuds du graphique représentent les blocs de base tandis que les bords entre les nœuds représentent le flux de contrôle entre les blocs de base.
Une instruction de transfert de contrôle conditionnelle comme if elle a deux branches - la vraie branche qui est exécutée lorsque la condition se maintient. Nous marquons cette branche comme bord explicite car cette branche est explicitement spécifiée par l'instruction if . L'autre branche à savoir. Le faux est marqué comme un bord implicite, car il est logiquement déduit.
Une instruction de transfert de contrôle inconditionnel comme jump n'a qu'un bord explicite.
Une fois que nous avons le code sous forme graphique, il est plus facile de raisonner sur le code. Par conséquent, la simplification du code obscurci est effectuée sur ce graphique.
Deux stratégies de simplification sont principalement utilisées:
Un transfert est un bloc de base qui se compose d'une seule instruction de flux de contrôle inconditionnel. Un transfert transfère l'exécution à un autre bloc de base sans faire de travail utile.
Avant l'élimination du transmission

La base bloquée surlignée en jaune est un bloc de transmission. Il peut être éliminé pour donner la structure suivante ci-dessous.
Après l'élimination des transaires

Cependant, un transmission ne peut pas toujours être éliminé spécifiquement dans les cas où le transmission a des endges implicites. Reportez-vous à Simplifier.py pour les détails
Un bloc de base peut être fusionné sur son prédécesseur si et seulement s'il y a exactement un prédécesseur et que le prédécesseur a ce bloc de base comme successeur seul.
Avant la fusion

Les instructions en surbrillance des blocs de base ont été fusionnées pour former un bloc de base plus grand indiqué ci-dessous. Les instructions de transfert de contrôle ont été supprimées car elles ne sont plus nécessaires.
Après fusion

Une fois que le graphique a été simplifié, nous devons réunir les blocs de base en code plat. Ceci est implémenté dans le fichier assembler.py.
Le processus d'assemblage en soi se compose de sous-étapes:
JUMP_FORWARD vers JUMP_ABSOLUTE : Si le bloc de base A a une instruction de flux de contrôle relative au bloc B, le bloc B doit être situé après le bloc A dans la disposition générée. En effet, les instructions de flux de contrôle relatives sont généralement utilisées pour faire référence aux adresses situées après. Si l'instruction CF relative est JUMP_FORWARD nous pouvons changer en JUMP_ABSOLUTE .SETUP_LOOP, SETUP_EXCEPT etc., nous devons créer un nouveau bloc de transmission composé d'une instruction de saut absolue sur le bloc B et faire l'instruction de flux de contrôle relative dans le bloc A Cela fonctionne, car le bloc de transmission sera naturellement après le bloc A dans la disposition générée et les instructions relatives peuvent toujours être utilisées pour pointer des blocs situés après, c'est-à-dire une adresse plus élevée.JUMP_FORWARD & SETUP_LOOP utilisent l'opérande pour faire référence à d'autres instructions. Cette référence est un entier désignant l'adresse décalée / absolue de la cible. $ 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