Caso você precise recuperar um arquivo .py de um .pyc uma boa opção é usar o Decompyle++, que reverte os bytecodes compilados à um código python legível por humanos. 
- Instalando o Decompyle++:
1) Primeiro precisamos instalar o cmake:
$ wget http://www.cmake.org/files/v2.8/cmake-2.8.12.2.tar.gz
$ tar xzvf cmake-2.8.12.2.tar.gz
$ cd cmake-2.8.10.2
$ ./bootstrap
$ make
# make install
2) Faça o download do Decompile++ e compile:
$ git clone git@github.com:zrax/pycdc.git
$ cd pycdc
$ /usr/local/bin/cmake ../pycdc/
$ make
- Recuperando o arquivo .py original:
- Entendendo os bytecodes e opcodes:
O módulo dis inclui funções para lidar com os bytecodes. A função dis.dis() mostra a representação do código python (módulo, classe, método, função, ou objeto de código).
Por exemplo, revertendo a criação de um dicionário temos:
$ echo "dicionario={'a':1}" > dicionario.py
$ python -m dis dicionario.py
1 0 BUILD_MAP 1
3 LOAD_CONST 0 (1)
6 LOAD_CONST 1 ('a')
9 STORE_MAP
10 STORE_NAME 0 (dicionario)
13 LOAD_CONST 2 (None)
16 RETURN_VALUE
>>> opcode.opmap['BUILD_MAP']
105
>>> opcode.opmap['LOAD_CONST']
100
>>> chr(opcode.opmap['BUILD_MAP'])
'i'
* Fontes:
http://multigrad.blogspot.com.br/2014/06/fun-with-python-bytecode.html
http://turtle-philosophy.blogspot.com/2014/06/decompiling-python-bytecode-with-pycdc.html
https://pymotw.com/2/dis/
http://akaptur.com/blog/2013/08/14/python-bytecode-fun-with-dis/
http://vgel.me/posts/patching_function_bytecode_with_python/
ftp://ftp.ntua.gr/mirror/python/peps/pep-0339.html
https://docs.python.org/3/library/dis.html
Por exemplo, revertendo a criação de um dicionário temos:
$ echo "dicionario={'a':1}" > dicionario.py
$ python -m dis dicionario.py
1 0 BUILD_MAP 1
3 LOAD_CONST 0 (1)
6 LOAD_CONST 1 ('a')
9 STORE_MAP
10 STORE_NAME 0 (dicionario)
13 LOAD_CONST 2 (None)
16 RETURN_VALUE
A saída é organizada em colunas contendo a linha original, o endereço da instrução, o nome do opcode e os argumentos passados para o opcode. Nesse exemplo, o código usa 5 operações diferentes para criar, popular um dicionário e salvar os resultados em uma variável local.
Para ver o código opcode e a representação do caractere de cada operação, podemos usar o módulo opcode:
>>> import opcode>>> opcode.opmap['BUILD_MAP']
105
>>> opcode.opmap['LOAD_CONST']
100
>>> chr(opcode.opmap['BUILD_MAP'])
'i'
>>> chr(opcode.opmap['LOAD_CONST'])
'd'
>>> hex(opcode.opmap['BUILD_MAP'])
'0x69'
>>> hex(opcode.opmap['BUILD_MAP'])
'0x69'
>>> hex(opcode.opmap['LOAD_CONST'])
'0x64'
>>> import py_compile
>>> py_compile.compile('dicionario.py')
Verificando os opcodes:
$ hexdump -C dicionario.pyc 
00000000  03 f3 0d 0a 07 f0 fe 57  63 00 00 00 00 00 00 00  |.......Wc.......|
00000010  00 03 00 00 00 40 00 00  00 73 11 00 00 00 69 01  |.....@...s....i.|
00000020  00 64 00 00 64 01 00 36  5a 00 00 64 02 00 53 28  |.d..d..6Z..d..S(|
00000030  03 00 00 00 69 01 00 00  00 74 01 00 00 00 61 4e  |....i....t....aN|
00000040  28 01 00 00 00 74 0a 00  00 00 64 69 63 69 6f 6e  |(....t....dicion|
00000050  61 72 69 6f 28 00 00 00  00 28 00 00 00 00 28 00  |ario(....(....(.|
00000060  00 00 00 73 0d 00 00 00  64 69 63 69 6f 6e 61 72  |...s....dicionar|
00000070  69 6f 2e 70 79 74 08 00  00 00 3c 6d 6f 64 75 6c  |io.pyt....<modul|
00000080  65 3e 01 00 00 00 73 00  00 00 00                 |e>....s....|
0000008b
Podemos confirmar a presença dos caracteres  ascii "i" e "d" e os hexadecimais 69 01 00 64 00 00 64 01 00 36 5a 00 00 64, indicando que temos os 2 opcodes BUILD_MAP e 3 LOAD_CONST,  como vimos antes com o dis. Assim, caso precise arrumar um arquivo corrompido .pyc,  conhecer os opcodes pode facilitar a tarefa. :)
* Fontes:
http://multigrad.blogspot.com.br/2014/06/fun-with-python-bytecode.html
http://turtle-philosophy.blogspot.com/2014/06/decompiling-python-bytecode-with-pycdc.html
https://pymotw.com/2/dis/
http://akaptur.com/blog/2013/08/14/python-bytecode-fun-with-dis/
http://vgel.me/posts/patching_function_bytecode_with_python/
ftp://ftp.ntua.gr/mirror/python/peps/pep-0339.html
https://docs.python.org/3/library/dis.html
 
 
0 comentários:
Postar um comentário