使用支持16进制编辑的文本编辑器查看一探究竟,这里我使用UltraEdit32:
分别打开正常情况下编译出的力兴和从pyinstaller提取出来的力兴文件进行对比:
可以看到前16个字节都被去掉了,其中前四个字节是魔法,这四个字节会随着系统和大蟒版本发生变化,必须一致。后四个字节包括时间戳和一些其他的信息,都可以随意填写。
我们先通过UltraEdit32向pyinstaller提取的文件添加头信息:
选择开头插入16个字节后,只需要替换前四个字节为当前环境下的魔力:
然后执行:
un编译6 auto _ organize _ GUI。exe _ extracted/auto _ organize _ GUI。pyc auto _ organize _ GUI巴拉圭执行后可以看到文件已经顺利的被反编译:
依赖性力兴文件反编译考虑再反编译导入的其他依赖文件:
先用UltraEdit32打开查看一下:
可以看到对于非入口运行的力兴文件是从12字节开始缺四个字节。
这里我们选择第13个字节再插入四个字节即可:
然后再执行:
un编译6 auto _ organize _ GUI。exe _ extracted/PYZ-00。PYZ _ extracted/auto _ organizepyc自动组织。巴拉圭然后成功的反编译出依赖的文件:
代码与原文件几乎完全一致:
批量反编译一个可执行程序的扩展名中的所有大蟒脚本如果一个可执行程序的扩展名需要被反编译的大蟒脚本只有3个以内的文件,我们都完全可以人工来操作。但是假如一个可执行程序的扩展名涉及几十个甚至上百个大蟒脚本需要反编译的时候,人工操作未免工作量过于巨大,我们考虑将以上过程用大蟒实现,从而达到批量反编译的效果。
提取可执行程序的扩展名中的pycimport操作系统
导入系统
导入pyinstextractor
exe _ file=r d:/PycharmProjects/GUI _ project/dist/auto _ organize _ GUI。 exe
sys.argv=[pyinstxtractor ,exe_file]
pyinstxtractor.main()
# 恢复当前目录位置
os.chdir( . )[*]处理d:/PycharmProjects/GUI _ project/dist/auto _ organize _ GUI。可执行程序的扩展名
[*] Pyinstaller版本:2.1
[*] Python版本:37
[*]包长度:9491710字节
[*]在归档中找到984个文件
[*]开始提取.请待命
[*]在中型档案中找到157个文件
[*]成功提取pyinstaller档案:D:/PycharmProjects/GUI _ project/dist/auto _ organize _ GUI。可执行程序的扩展名
现在,您可以对提取的目录中的力兴文件使用大蟒反编译器预处理力兴文件修护校验头定义查找主目录:
对于os.listdir(pyc_dir)中的pyc_file:
如果不是pyc_file.startswith(pyi-)和pyc_file.endswith(manifest ):
主文件=pyc文件。替换(。exe。清单,)
result=f"{ pyc _ dir }/{ main _ file } "
如果os.path。存在(结果):
返回主文件
pyc _ dir=OS。路径。basename(exe _ file) _ extracted
主文件=查找主文件读取从中型目录抽取的力兴文件的前四个字节作基准:
PYZ _ dir=f"{ pyc _ dir }/PYZ-00。PYZ _已提取"
对于os.listdir(pyz_dir)中的pyc_file:
if pyc_file.endswith( .pyc’):
file=f"{ pyz _ dir }/{ pyc _ file } "
破裂
用打开(文件,“rb”)作为女:
head=f.read(4)
list(map(hex,head))[0x42 ,0xd ,0xd ,0xa]校准入口类:
导入技能
如果os.path。存在( pycfile_tmp ):
shutil.rmtree(pycfile_tmp )
os.mkdir(pycfile_tmp )
main _ file _ result=f pyc file _ tmp/{ main _ file } .pyc
open(f{pyc_dir}/{main_file} , rb )为读取,打开(主文件结果, wb )为写:
写.写(头)
write.write(b\0*12)
write.write(read.read())校准子类:
PYZ _ dir=f"{ pyc _ dir }/PYZ-00。PYZ _已提取"
对于os.listdir(pyz_dir)中的pyc_file:
pyc _ file _ src=f " { pyz _ dir }/{ pyc _ file } "
pyc _ file _ dest=f pyc file _ tmp/{ pyc _ file }
print(pyc_file_src,pyc_file_dest)
打开(pyc_file_src, rb )为读,打开(pyc_file_dest, wb )为写:
write.write(read.read(12))
write.write(b\0*4)
write.write(read.read())开始反编译从非编译6.bin导入非编译
如果不是os.path.exists(py_result ):
os.mkdir(py_result )
对于os.listdir中的pyc _ file( pyc file _ tmp ):
sys。argv=[ un compley 6 ,-o ,
fpy_result/{pyc_file[:-1]} ,fpycfile_tmp/{pyc_file}]
uncompile.main_bin()
完整代码#!/usr/bin/env python
#编码:utf-8
# 提取可执行程序的扩展名中的力兴
导入操作系统
导入系统
导入pyinstextractor
从非编译6.bin导入非编译
导入技能
# 预处理力兴文件修护校验头
定义查找主目录:
对于os.listdir(pyc_dir)中的pyc_file:
如果不是pyc_file.startswith(pyi-)和pyc_file.endswith(manifest ):
主文件=pyc文件。替换(。exe。清单,)
result=f"{ pyc _ dir }/{ main _ file } "
如果os.path。存在(结果):
返回主文件
def un code _ exe(exe _ file,complie _ child=False):
sys.argv=[pyinstxtractor ,exe_file]
pyinstxtractor.main()
# 恢复当前目录位置
os.chdir( . )
pyc _ dir=OS。路径。basename(exe _ file) _ extracted
主文件=查找主文件
PYZ _ dir=f"{ pyc _ dir }/PYZ-00。PYZ _已提取"
对于os.listdir(pyz_dir)中的pyc_file:
if pyc_file.endswith( .pyc’):
file=f"{ pyz _ dir }/{ pyc _ file } "
破裂
否则:
打印(子文件中没有找到力兴文件,无法反编译!)
返回
用打开(文件,“rb”)作为女:
head=f.read(4)
如果os.path。存在( pycfile_tmp ):
shutil.rmtree(pycfile_tmp )
os.mkdir(pycfile_tmp )
main _ file _ result=f pyc file _ tmp/{ main _ file } .pyc
open(f{pyc_dir}/{main_file} , rb )为读取,打开(主文件结果, wb )为写:
写.写(头)
write.write(b\0*12)
write.write(read.read())
如果os.path。存在( py_result ):
shutil.rmtree(py_result )
os.mkdir(py_result )
sys。argv=[ un compley 6 ,-o ,
fpy_result/{main_file} .py ,main_file_result]
uncompile.main_bin()
如果不符合_child:
返回
对于os.listdir(pyz_dir)中的pyc_file:
如果不是pyc_file.endswith( .pyc’):
继续
pyc _ file _ src=f " { pyz _ dir }/{ pyc _ file } "
pyc _ file _ dest=f pyc file _ tmp/{ pyc _ file }
print(pyc_file_src,pyc_file_dest)
打开(pyc_file_src, rb )为读,打开(pyc_file_dest, wb )为写:
write.write(read.read(12))
write.write(b\0*4)
write.write(read.read())
os.mkdir(py_result/other )
对于os.listdir中的pyc _ file( pyc file _ tmp ):
if pyc_file==main_file .pyc :
继续
sys。argv=[ un compley 6 ,-o ,
f py _ result/other/{ pyc _ file[:-1]} ,fpycfile_tmp/{pyc_file}]
uncompile.main_bin()调用:
exe _ file=r d:/PycharmProjects/GUI _ project/dist/auto _ organize _ GUI。 exe
uncompyle_exe(exe_file,True)可以看到已经完美的反编译出可执行程序的扩展名其中的大蟒脚本:
如何防止自己打包的可执行程序的扩展名被反编译呢?只需在打包命令后面加上-钥匙命令即可,例如文章开头的命令可以更换为:
py installer-Fw-icon=h . ico auto _ organize _ GUI。py-add-data= h . ico;/ -键123456 123456是你用来加密的密钥,可以随意更换。
该加密参数依赖tinyaes,可以通过以下命令安装:
点安装锡罐打包后再次执行反编译:
exe _ file=r d:/PycharmProjects/GUI _ project/dist/auto _ organize _ GUI。 exe
uncompyle_exe(exe_file,True)结果只有入口脚本反编译成功,被依赖的脚本均被加密,无法直接被反编译:
可以看到抽取的中间结果变成了加密的格式,无法直接被反编译:
可以看到,常规手段就无法直接反编译了。这个时候还想反编译就需要底层的逆向分析研究了,或者pyinstaller的源码完整研究一遍,了解其加密处理的机制,看看有没有的可能。
原文地址:pyinstaller反编译源码,pyinstaller打包exe命令_菜鸟教程之家
本文来自网络,不代表菜鸟教程之家立场,转载请注明出处。