首页
社区
课程
招聘
[原创]逆向Pyinstaller打包的程序源码及保护
发表于: 2023-6-28 16:26 19218

[原创]逆向Pyinstaller打包的程序源码及保护

2023-6-28 16:26
19218

我们都知道可以使用Pyinstaller库可将.py文件编译成.exe文件运行,这篇文章我们就从将脚本编译成.exe并将.exe的源码内容反编译出源文件,再顺便谈谈如何防止被逆向。

图片描述

测试脚本.py

首先安装打包程序所使用的库pyinstaller,这里用了清华源并且指定使用了4.0版本库

找到脚本所在的文件夹,我的是C:\Users\YRJ\Desktop\a cd 到此路径下,并输入以下打包命令:

命令执行完毕后,会看到completed successfully.字段,表示.exe文件生成成功,在dist文件夹中。
图片描述

首先我们下载反编译工具pyinstxtractor.py与我们要反编译的.exe文件放入同一个工作目录下,如下图所示:
图片描述

执行完毕,看到Successfully字样,会生成测试脚本.exe_extracted文件夹,如下图所示:
图片描述
进入该文件夹,里面有许许多多后缀为.dll.pyd的文件,还有一个名为PYZ-00.pyz_extracted的文件夹,这个文件夹里放的是程序引入的依赖库,如果你引入过自己其他的.py文件,就可以用类似的方法将依赖的.py文件反编译出来,如下图所示:
图片描述
在目录中我们要找到struct和与你的.exe文件同名的文件。如下图所示:
图片描述
这两个文件是否带.pyc后缀和你使用的pyinstxtractor.py工具版本有关系。V2.0以前的版本,会生成两个不带.pyc后缀的文件,手动为它添加.pyc后缀即可。如下图所示:
图片描述
当前这个测试脚本.pyc文件是没有Magic Number的,我们需要根据Python版本自行补全,由上图可知打包此程序的Python版本为3.6,我们接下来就需要查3.6版本的Magic Number

• Python3.3 以下版本:只有Magic Number和四位时间戳
• Python3.3(包含) - Python3.7(不包含)版本:4个字节的magic num + 8个字节的时间戳,这个时间戳可以全是0。
• Python3.7(包含)版本:4个字节的magic num + 4个字节的空白数据 + 4个字节的时间戳 + 4个字节的文件长度,除了magic num,其它数据可以全是0。

方法一:
查通用对照表:

例如: Python 3.6的Magic Number,执行后可以得到0x0A0D0D33,则对应二进制码是33 0D 0D 0A
方法二(推荐):
struct.pyc文件:

struct.pyc文件使用WinHex编辑器打开,它的前4位字节就是magic num与方法一的二进制码相同。如下图所示:
图片描述
再打开测试脚本.pycstruct.pyc对比头内容确定要添加的内容,如下图所示:
图片描述

选中struct.pyc中框选的头内容,右键编辑→复制选块→十六进制数值。330D0D0A7079693001010000
图片描述
打开测试脚本.pyc,直接在前面添加,上面复制的十六进制数值330D0D0A7079693001010000,光标点击第一个字母E右键编辑→剪贴板数据→粘贴→ASCII Hex→确定,然后保存即修改完毕!如下图所示:
图片描述
图片描述
图片描述

安装.pyc.py所使用的库uncompyle6,这里用了清华源并且指定使用了3.9.0版本库

找到测试脚本.pyc所在的文件夹,cd 到此路径下,并输入以下打包命令:

命令执行完毕后,会看到successfully字段,表示.py源码文件已成功生成在同路径下。
图片描述

通过对程序本来的源码逆向得来的源码对比可知:简单的源码上基本一致,复杂些的源码上可能会有一点点瑕疵。

单就此次逆向的程序而言,比程序原本的源码就少了源码的注释,多了系统反编译时相关环境及版本的注释。
图片描述
通过命令python 测试脚本.py执行逆向得来的源码,测试通过,发现功能正常。
图片描述

首先安装加密打包程序所使用的库tinyaes,这里用了清华源并且指定使用了1.0.3版本库

找到脚本所在的文件夹,我的是C:\Users\YRJ\Desktop\c cd 到此路径下,并输入以下打包命令:

命令执行完毕后,会看到completed successfully.字段,表示.exe文件生成成功,在dist文件夹中。
图片描述
接着就按照前面写的逆向过程执行命令python pyinstxtractor.py 测试脚本.exe,结果只有入口脚本反编译成功,被依赖的脚本均被加密,无法直接被反编译,如下图所示:
图片描述
PYZ-00.pyz_extracted非常重要,一般一个稍微大一点的项目都会分成多个py文件,甚至会依赖其他模块,这些被依赖的文件解析后都会放入PYZ-00.pyz_extracted中,可以d说这里放的是核心代码。

PYZ-00.pyz_extracted文件夹内可以看到,抽取的中间结果变成了.pyc.encrypted格式,无法直接被反编译,未加密和加密的相关对比,如下图所示:
图片描述
常规手段就无法直接反编译了。这个时候若还想反编译就需要底层的逆向分析研究或将pyinstaller的源码完整研究一遍,了解其加密处理的机制,看看有没有逆向的可能。

注意: 请勿使用此种方法来保护只有一个.py文件的python源码,因为主函数的入口脚本编译是成功的,根据逆向过程章节操作后,入口脚本一样的会被看到源码。

首先安装打包程序所使用的库nuitka,这里用了清华源并且指定使用了1.3.7版本库

找到脚本所在的文件夹,我的是C:\Users\YRJ\Desktop\a cd 到此路径下,选择输入以下你需要的打包命令:

打包过程中会提示缺少执行程序gcc,直接按照要求Yes安装,此文件比较大命令行可能下载不动或缓慢,我们可直接复制下载位置下载地址,如下图所示:
图片描述

用浏览器访问下载地址移动到下载位置的目录下并做解压即可,如下图所示:
图片描述
接下来,我们继续执行打包命令:nuitka --standalone --mingw64 测试脚本.py,打包过程中还会提示缺少的执行程序ccachedepends,此文件比较小,根据提示直接Yes安装即可,下载完成后会自动解压到路径:

图片描述
至此,用nuitka来将python代码打包为.exe的过程就结束了。
验证执行
执行打包好的.exe程序,命令行出口出现乱码问题,如下图:
图片描述
解决方案是:在主函数首行添加os.system("chcp 65001 && cls")
图片描述
再次打包并执行打包好的.exe程序,问题解决,如下图所示:
图片描述
但这又导致出现了一个bug,Python源码中的input("请输入你想要打印的内容:")是需要在命令行输入内容的,我输入英文和数字的时候打印输出时正常的,但是我输入中文的时候,就会引起异常及闪退的情况,我暂时还未有相关解决方案....
输入中文会引起异常及闪退的解决方案:

换当前使用的Python3.6.0版本到Python3.8.0及以上即可解决问题。

我使用的环境及运行测试图如下:

图片描述

之前我没了解过这方面内容,但偶然需要用到时查阅了很多的博客文章及资料,中途也出现很多当时无法解决的但幸运的是慢慢都解决了,就写下了这篇详细的总结文章记录下过程。

Python 3.6:https://www.python.org/downloads/release/python-360/
Pyinstaller库:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller==4.0
Python 3.6:https://www.python.org/downloads/release/python-360/
Pyinstaller库:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller==4.0
pyinstxtractor.py:下载地址:https://sourceforge.net/projects/pyinstallerextractor/
WinHex编辑器:下载地址:https://down.52pojie.cn/Tools/Editors/WinHex_v19.9.zip
uncompyle库:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple uncompyle6==3.9.0
pyinstxtractor.py:下载地址:https://sourceforge.net/projects/pyinstallerextractor/
WinHex编辑器:下载地址:https://down.52pojie.cn/Tools/Editors/WinHex_v19.9.zip
uncompyle库:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple uncompyle6==3.9.0
tinyaes库:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple tinyaes==1.0.3
tinyaes库:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple tinyaes==1.0.3
python -V
python -V
import datetime
 
# 函数
def test():
    print("====反编译源码的测试脚本====")
    input_text = input("请输入你想要打印的内容:")
 
    # 打印格式化时间和用户输入的内容
    print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S ") + input_text)
 
if __name__ == '__main__':
    # 调用
    test()
import datetime
 
# 函数
def test():
    print("====反编译源码的测试脚本====")
    input_text = input("请输入你想要打印的内容:")
 
    # 打印格式化时间和用户输入的内容
    print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S ") + input_text)
 
if __name__ == '__main__':
    # 调用
    test()
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller==4.0
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller==4.0
Pyinstaller -F 测试脚本.py
Pyinstaller -F 测试脚本.py
python pyinstxtractor.py 测试脚本.exe
python pyinstxtractor.py 测试脚本.exe
enum PycMagic {
    MAGIC_1_0 = 0x00999902,
    MAGIC_1_1 = 0x00999903,
    MAGIC_1_3 = 0x0A0D2E89,
    MAGIC_1_4 = 0x0A0D1704,
    MAGIC_1_5 = 0x0A0D4E99,
    MAGIC_1_6 = 0x0A0DC4FC,
 
    MAGIC_2_0 = 0x0A0DC687,
    MAGIC_2_1 = 0x0A0DEB2A,
    MAGIC_2_2 = 0x0A0DED2D,
    MAGIC_2_3 = 0x0A0DF23B,
    MAGIC_2_4 = 0x0A0DF26D,
    MAGIC_2_5 = 0x0A0DF2B3,
    MAGIC_2_6 = 0x0A0DF2D1,
    MAGIC_2_7 = 0x0A0DF303,
 
    MAGIC_3_0 = 0x0A0D0C3A,
    MAGIC_3_1 = 0x0A0D0C4E,
    MAGIC_3_2 = 0x0A0D0C6C,
    MAGIC_3_3 = 0x0A0D0C9E,
    MAGIC_3_4 = 0x0A0D0CEE,
    MAGIC_3_5 = 0x0A0D0D16,
    MAGIC_3_5_3 = 0x0A0D0D17,
    MAGIC_3_6 = 0x0A0D0D33,
    MAGIC_3_7 = 0x0A0D0D42,
    MAGIC_3_8 = 0x0A0D0D55,
    MAGIC_3_9 = 0x0A0D0D61,
};
enum PycMagic {
    MAGIC_1_0 = 0x00999902,
    MAGIC_1_1 = 0x00999903,
    MAGIC_1_3 = 0x0A0D2E89,
    MAGIC_1_4 = 0x0A0D1704,
    MAGIC_1_5 = 0x0A0D4E99,
    MAGIC_1_6 = 0x0A0DC4FC,
 
    MAGIC_2_0 = 0x0A0DC687,
    MAGIC_2_1 = 0x0A0DEB2A,
    MAGIC_2_2 = 0x0A0DED2D,
    MAGIC_2_3 = 0x0A0DF23B,
    MAGIC_2_4 = 0x0A0DF26D,
    MAGIC_2_5 = 0x0A0DF2B3,

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 11
支持
分享
最新回复 (7)
雪    币: 6221
活跃值: (5660)
能力值: ( LV5,RANK:65 )
在线值:
发帖
回帖
粉丝
2
感谢分享,辛苦了!
2023-6-28 17:29
0
雪    币: 1935
活跃值: (4180)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学习,感谢分享
2023-6-28 22:37
0
雪    币: 461
活跃值: (2808)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
没做把.py文件编译的过程,还是甩给py的解析器去解析,再怎么加密都是徒劳的。
2023-6-29 08:21
1
雪    币: 3573
活跃值: (31026)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2023-6-29 09:27
0
雪    币: 12790
活跃值: (1862)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
saloyun 没做把.py文件编译的过程,还是甩给py的解析器去解析,再怎么加密都是徒劳的。
加密是徒劳?不会吧!
2023-6-29 11:22
0
雪    币: 548
活跃值: (60)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2023-7-9 09:46
0
雪    币: 271
活跃值: (196)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢分享
2023-7-9 11:09
0
游客
登录 | 注册 方可回帖
返回
//