记python逆向
近期遇到不少python逆向,小计一下
一、直接反编译
1、uncompyle6反编译
pip install uncompyle6
uncompyle6 -o test.py test.pyc
这种方法目前反编译不了python3.9级之后的版本
2、https://tool.lu/pyc/
一个在线反编译pyc文件的网站,
该网站支持包括python3.9,python3.10的多个版本的pyc文件
3、pycdc工具
安装:
git clone https://github.com/zrax/pycdc.git cd pycdc cmake . make
之后加入环境变量
使用:
pycdc ./
上面的在线反编译网站,其内核也是使用了pycdc工具
二、手撸字节码
有时候出题人不给我们.pyc文件,或者反编译工具不正确,这时候就需要我们直接读取字节码了
import dis import marshal f = open("你的pyc文件.pyc","rb").read() code = marshal.loads(f[16:]) #反序列化#python3版本的需要去除前16个字节,python2版本的需要去除前8个字节 dis.dis(code) #反编译 print(code)
三、python打包的exe/elf文件(无key)
python存在一个名叫Pyinstaller的开源工具包,使用此工具可以把.py文件打包成.exe或.elf文件
1、解包成pyc文件
我们可以使用Extractor工具或者 pyinstxtractor.py 工具进行解包
python pyinstxtractor.py xx.exe
2、修改模数
一般来说解包后的文件有一个奇怪的问题,主函数的.pyc文件的模数会被修改,我们需要根据文件夹中一定会存在的struct.pyc文件进行修改
3、反编译或直接读取字节码
之后我们就可以重复一、二、的步骤进行解决问题了
四、python打包的exe/elf文件
Pyinstaller,py文件使用的时候有一个-key参数,可以对一些pyc文件进行加密,防止被逆向
一般把加密后的pyc文件称为pyz文件
以一个名为qgdjyelf文件为例,介绍一种dump的方式(我见好多大佬解包前要dump一下,我不是很明白原理,明明不dump也能解包啊...这里记录一下)
1、dump
objcopy --dump-section pydata=unwerid.dump qgdjy
2、将得到的dump文件用Pyinstaller工具解包
注意,我们要使用相同的python进行解包,不然可能会导致.pyz文件夹丢失,切记切记
3、将解包出的.pyc文件的模数转化成struct的模数
4、反编译
pycdc ./qgdjy.pyc
我们也可以通过下载pycdas来查看字节码
命令如下
git clone https://github.com/zrax/pycdc
cd pycdc/
cmake .
sudo make install
5、解密pyz文件
dump文件解包后有一个文件夹
里面加密了一些包
加密的方法与密钥在下图pyc文件中
archive.pyc就是加密的过程,crypto_key是加密的密钥,而我们需要解密.pyz文件
以cup.pyc.encrypted文件为例
我们需要对他解密
加密代码:
import marshal, struct, sys, zlib, _thread as thread CRYPT_BLOCK_SIZE = 16 PYZ_TYPE_MODULE = 0 PYZ_TYPE_PKG = 1 PYZ_TYPE_DATA = 2 PYZ_TYPE_NSPKG = 3 ...... #关键加密代码 class Cipher(object): __doc__ = '\n This class is used only to decrypt Python modules.\n ' def __init__(self): #引入密钥 import pyimod00_crypto_key key = pyimod00_crypto_key.key if not type(key) is str: raise AssertionError elif len(key) > CRYPT_BLOCK_SIZE: self.key = key[0:CRYPT_BLOCK_SIZE] else: self.key = key.zfill(CRYPT_BLOCK_SIZE) assert len(self.key) == CRYPT_BLOCK_SIZE import tinyaes self._aesmod = tinyaes del sys.modules['tinyaes'] #利用TinyAES进行加密 def __create_cipher(self, iv): return self._aesmod.AES(self.key.encode(), iv) #提供的解密算法,原义是想让pyz文件正常解压运行,在这里可以被我们利用 def decrypt(self, data): cipher = self._Cipher__create_cipher(data[:CRYPT_BLOCK_SIZE]) return cipher.CTR_xcrypt_buffer(data[CRYPT_BLOCK_SIZE:]) ......
根据加密代码,我们可以写出解密代码(其实是抄的...)
解密代码:
import cup import tinyaes import zlib CRYPT_BLOCK_SIZE = 16 # 从crypt_key.pyc获取key,也可自行反编译获取 key = bytes('0000000000000tea', 'utf-8') inf = open('cup.pyc.encrypted', 'rb') # 打开加密文件 outf = open('cup.pyc', 'wb') # 输出文件 # 按加密块大小进行读取 iv = inf.read(CRYPT_BLOCK_SIZE) cipher = tinyaes.AES(key, iv) # 解密 plaintext = zlib.decompress(cipher.CTR_xcrypt_buffer(inf.read())) # 补pyc头(最后自己补也行) outf.write(b'\x6f\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0') # 写入解密数据 outf.write(plaintext) inf.close() outf.close()
这样就得到了解密后的pyc包文件
五、加花的pyc文件
这个暂时没有遇到,只是听过...以后补
-------------------------------------------------------------------------------------------------------------- 2023/01/13 --------------------------------------------------------------------------------------------------------------
可算让我遇到了,nnd.....
HWS冬令营遇到了这种类型的题目,讲一下思路吧
内容有点多,另写了一篇博客
参考: