Bytecode Simplifier es una herramienta para desobfuscar los scripts de Python protegidos por Pjorion. Esta es una reescritura completa de mi herramienta más antigua Pjorion Deobfuscator
Debe tener los siguientes paquetes preinstalados:
Ambos paquetes son pip instalables. Además, asegúrese de que GraphViz Ejecutable esté en su camino para que funcione pydotplus . pydotplus solo se requiere para dibujar gráficos y, si no desea esta función, puede comentar las llamadas render_graph en la función deobfuscate en el archivo deoBfuscator.py
Pjorion ofusca el archivo original y presenta varias capas de envoltura encima. El propósito de estas capas es simplemente (más o menos) descifrar la siguiente capa interna y ejecutarla a través de una instrucción EXEC_STMT . Por lo tanto, no puede usar esta herramienta como está en un archivo ofuscado. Primero, necesitaría eliminar las capas de envoltura y obtener el objeto de código ofuscado real. Luego puede reunir el código ofuscado en el disco y ejecutar esta herramienta que, con suerte, debería devolverle el código desobfusificado.
Consulte esta publicación de blog para obtener más detalles.
Bytecode Simplifier Analiza el código ofuscado utilizando un enfoque de desmontaje transversal recursivo. Las instrucciones se desmontan y se combinan en bloques básicos. Un bloque básico es una secuencia de instrucciones con una sola entrada y una sola salida.
Un bloque básico puede terminar con una instrucción de flujo de control, como una instrucción if . Una declaración if tiene dos ramas: verdaderas y falsas. Correspondiente a las ramas Los bloques básicos tienen bordes entre ellos. Toda esta estructura está representada por un gráfico dirigido. Utilizamos networkx.DiGraph para este propósito.
Los nodos en el gráfico representan los bloques básicos, mientras que los bordes entre los nodos representan el flujo de control entre los bloques básicos.
Una instrucción de transferencia de control condicional como if tiene dos ramas: la rama verdadera que se ejecuta cuando se mantiene la condición. Etiquetamos esta rama como el borde explícito, ya que esta rama es especificada explícitamente por la instrucción if . La otra rama a saber. El falso está etiquetado como un borde implícito, ya que se deduce lógicamente.
Una instrucción de transferencia de control incondicional como jump solo tiene un borde explícito.
Una vez que tenemos el código en forma de gráfico, es más fácil razonar sobre el código. Por lo tanto, la simplificación del código ofuscado se realiza en este gráfico.
Se utilizan principalmente dos estrategias de simplificación:
Un reenviador es un bloque básico que consiste en una sola instrucción de flujo de control incondicional. Un reenviador transfiere la ejecución a algún otro bloque básico sin hacer ningún trabajo útil.
Antes de la eliminación del reenvío

El bloqueo básico resaltado en amarillo es un bloque de reenvío. Se puede eliminar para dar la siguiente estructura a continuación.
Después de la eliminación del reenvío

Sin embargo, un reenvío no siempre puede ser eliminado específicamente en los casos en que el reenvío tiene bordes implícitos. Consulte Simplifier.py para obtener los detalles
Se puede fusionar un bloque básico en su predecesor si y solo si hay exactamente un predecesor y el predecesor tiene este bloque básico como su sucesor solitario.
Antes de fusionar

Las instrucciones resaltadas de los bloques básicos se han fusionado para formar un bloque básico más grande que se muestra a continuación. Las instrucciones de transferencia de control se han eliminado ya que ya no son necesarias.
Después de fusionar

Una vez que el gráfico se ha simplificado, necesitamos ensamblar los bloques básicos nuevamente en código plano. Esto se implementa en el archivo ensamblador.py.
El proceso de ensamblaje en sí mismo consiste en sub-etapas:
JUMP_FORWARD a JUMP_ABSOLUTE : si el bloque BASIC A tiene una instrucción de flujo de control relativo para el bloque B, entonces el bloque B debe ubicarse después del bloque A en el diseño generado. Esto se debe a que las instrucciones de flujo de control relativo generalmente se usan para referirse a direcciones ubicadas después. Si la instrucción relativa de CF es JUMP_FORWARD podemos cambiar a JUMP_ABSOLUTE .SETUP_LOOP, SETUP_EXCEPT ETC, necesitamos crear un nuevo bloque de reenvío que consiste en una instrucción de salto absoluta para el bloque B, y hacer que la instrucción de flujo de control relativo en el bloque A para apuntar al bloque de reenvío. Esto funciona ya que el bloque de reenvío será naturalmente después del bloque A en el diseño generado y las instrucciones relativas siempre se pueden usar para apuntar a bloques ubicados después, es decir, tener una dirección más alta.JUMP_FORWARD & SETUP_LOOP utiliza el operando para referirse a otras instrucciones. Esta referencia es un entero que denota la dirección de desplazamiento/absoluto del objetivo. $ 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