本文主要记录解包 PyInstaller 打包文件时遇到的问题及工具的使用方法,相当于对网上教程的一个总结,不涉及反混淆等高级逆向技术。
1. PyInstaller 解包
1.1 pyinstxtractor.py
使用方法:在终端中执行
python pyinstxtractor.py <filename>
注:执行时如果提示python版本问题,需要使用正确的python版本执行。
1.2 pyinstxtractor-ng
这个项目是 pyinstxtractor 的一个分支。
pyinstxtractor-ng 使用 xdis 库来解包 Python 字节码,因此不需要使用用于构建可执行文件的相同 Python 版本。
Pyinstxtractor-ng 还支持自动解密加密的 pyinstaller 可执行文件。
使用方法:
$ pyinstxtractor-ng <filename>
在线使用:PyInstaller Extractor WEB
1.3 pyinstaller-repacker
使用方法:
$ python pyinst-repacker.py extract <filename>
注意:①执行前请确保安装了 lxml 和 lief 依赖,可以使用pip安装
pip install lxml lief -i https://pypi.tuna.tsinghua.edu.cn/simple
②仅限 Python 3,不支持加密的 PYZ
③建议使用打包文件使用的python版本执行
另外,此项目还提供了重新打包的功能,在终端中执行:
python pyinst-repacker.py build <目录>
(可选)使用–scanpy
$ python pyinst-repacker.py build --scanpy test.exe-repacker
(可选)使用–ignore-missing
$ python pyinst-repacker.py build test.exe-repacker
2. pyc文件编译与反编译
2.1 pyc反编译
- 在线反编译网站:
-
- 在线Python pyc文件编译与反编译(3.9以下成功率较高)
-
- PyLingual(不会像pycdc那样注明哪里没有反编译成功,有时会缺失一部分代码)
- 本地反编译工具:
-
- Decompyle++(pycdc和pycdas)
-
- Pylingual(不支持windows)
-
- uncompyle6(可直接pip install,对3.9以上的支持性不好)
本地反编译pyc的操作方法大致相同:
$ uncompyle6 -o test.py test.pyc $ pycdc test.pyc > test.py $ pycdas test.pyc > test.txt #转为字节码
2.2 py编译为pyc
使用py_compile编译
$ python -m py_compile test.py 或 $ python -m compileall <指定文件或目录>
3. Pyinstaller重打包
- 如果是用pyinstxtractor-ng解包的,需要将解包目录下PYZ-00.pyz_extracted
- Pyinstaller -F -w <目录>
- pyinstaller-repacker的重打包方法见上
4.实战
4.1 第一个程序
首先使用pyinstxtractor-ng解包:
进入解包文件夹:
将PYZ.pyz_extracted文件夹里的文件全部无脑复制到上一级文件夹里
尝试直接运行main.pyc,观察是否缺少环境
运行成功!现在可以进行反编译操作了
打开PyLingual网站,将main.pyc拖入
得到反编译后的代码:
# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: main.py
# Bytecode version: 3.12.0rc2 (3531)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)
import tkinter as tk
from tkinter import messagebox
CORRECT_USERNAME = ‘test’
CORRECT_PASSWORD = ‘123456’
def login():
username = entry_username.get()
password = entry_password.get()
if username == CORRECT_USERNAME and password == CORRECT_PASSWORD:
root.destroy()
open_main_window(username)
else:
messagebox.showerror(‘登录失败’, ‘用户名或密码错误!’)
def open_main_window(username):
main_window = tk.Tk()
main_window.title(f’欢迎, {username}’)
main_window.geometry(‘400×300’)
label_welcome = tk.Label(main_window, text=f’欢迎回来, {username}!’, font=(‘Arial’, 16))
label_welcome.pack(pady=20)
label_info = tk.Label(main_window, text=’这是您的主界面’, font=(‘Arial’, 12))
label_info.pack(pady=10)
btn_exit = tk.Button(main_window, text=’退出’, command=main_window.quit, bg=’red’, fg=’white’)
btn_exit.pack(pady=20)
main_window.mainloop()
root = tk.Tk()
root.title(‘登录’)
root.geometry(‘300×200’)
label_title = tk.Label(root, text=’用户登录’, font=(‘Arial’, 14))
label_title.pack(pady=10)
label_username = tk.Label(root, text=’用户名:’)
label_username.pack()
entry_username = tk.Entry(root)
entry_username.pack()
label_password = tk.Label(root, text=’密码:’)
label_password.pack()
entry_password = tk.Entry(root, show=’*’)
entry_password.pack()
btn_login = tk.Button(root, text=’登录’, command=login, bg=’blue’, fg=’white’)
btn_login.pack(pady=20)
root.mainloop()
可以看到用户名和密码,很简单吧
重打包就不演示了
4.2 第二个程序
这个程序是我很久之前弄的了,这里就简单说下逆向过程中遇到的问题
①确定python版本
使用“安全分析工具”找到运行中的程序,快速确定具体python版本
②重打包不全
可以尝试用以下脚本打包pyinstaller main.spec
import os
import sys
block_cipher = None
script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
a = Analysis(
[‘main.py’],
pathex=[script_dir],
binaries=[],
datas=[(“tkinter”, “tkinter”)],
hiddenimports=[
#在这里添加模块,缺什么就加什么
‘tkinter’,
‘platform’,
‘inspect’
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name=’main’,
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)