网站首页 > 技术文章 正文
Demo代码
import time
# 这是注释
start = time.time()
number = 0
print(number)
PyInstaller打包时加密.pyc代码
Python bytecode modules can be obfuscated with AES256 by specifying an encryption key on PyInstaller’s command line. Please note that it is still very easy to extract the key and get back the original bytecode, but it should prevent most forms of “casual” tampering. See Encrypting Python Bytecode for details.
程序入口的Python文件,如demo.py不会加密,只要加密import的模块,所以不要把主要代码写在入口文件上。
pyinstaller --key 123 demo.py
即下述生成的demo.pyc没有加密,其导入的模块打包于子文件PYZ-00.pyz中,解开可以看到其是有加密的后缀.pyc.encrypted。为何入口文件没加密?
demo.pyc
pyiboot01_bootstrap.pyc
pyimod00_crypto_key.pyc
pyimod01_archive.pyc
pyimod02_importers.pyc
pyimod03_ctypes.pyc
pyimod04_pywin32.pyc
pyi_rth_subprocess.pyc
PYZ-00.pyz
struct.pyc
解密PyInstaller加密的.pyc.encrypted代码
PyInstaller use tinyaes-py to encrypt Python bytecode from 4.2, previously it used Pycrypto. https://github.com/pyinstaller/pyinstaller/pull/4652
有两个方法:一是使用 pyinstxtractor-ng 解包PyInstaller打包的bundle中的demo.exe文件时附带解密掉;二是对 pyinstxtractor 解包后的 .pyc.encrypted 手动解密。
pyinstxtractor-ng附带解密pyc.encrypted
https://github.com/pyinstxtractor/pyinstxtractor-ng 集成解密功能,看它的代码应该也不是100%解密成功。
python .\pyinstxtractor-ng.py .\dist\demo\demo.exe
手动解密pyc.encrypted代码为.pyc
import sys
class Cipher(object):
"""
This class is used only to decrypt Python modules.
"""
def __init__(self):
# At build-type the key is given to us from inside the spec file, at
# bootstrap-time, we must look for it ourselves by trying to import
# the generated 'pyi_crypto_key' module.
import pyimod00_crypto_key
key = pyimod00_crypto_key.key
assert type(key) is str
if 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
# Issue #1663: Remove the AES module from sys.modules list. Otherwise
# it interferes with using 'tinyaes' module in users' code.
del sys.modules['tinyaes']
def __create_cipher(self, iv):
# The 'AES' class is stateful, this factory method is used to
# re-initialize the block cipher class with each call to xcrypt().
return self._aesmod.AES(self.key.encode(), iv)
def decrypt(self, data):
cipher = self.__create_cipher(data[:CRYPT_BLOCK_SIZE])
return cipher.CTR_xcrypt_buffer(data[CRYPT_BLOCK_SIZE:])
if __name__ == '__main__':
import zlib
CRYPT_BLOCK_SIZE = 16
inf = open('/home/a/a.exe_extracted/PYZ-00.pyz_extracted/yamnet.pyc.encrypted', 'rb') # encrypted file input
outf = open('yamnet.pyc', 'wb') # output file
cipher = Cipher()
# Decrypt and decompress
plaintext = zlib.decompress(cipher.decrypt(inf.read()))
# Write pyc header
# get from importlib.util.MAGIC_NUMBER.hex()
outf.write(b'\x55\x0d\x0d\x0a\0\0\0\0')
# Write decrypted data
outf.write(plaintext)
inf.close()
outf.close()
解包PyInstaller打包的exe
PyInstaller Extractor is a Python script to extract the contents of a PyInstaller generated Windows executable file https://github.com/extremecoders-re/pyinstxtractor
更新:作者的新库 https://github.com/pyinstxtractor/pyinstxtractor-ng 集成反汇编xdis与解密Pyinstaller的加密代码。
反汇编disassembler
即反汇编(disassembler)字节码.pyc为用户可读的指令列表,https://github.com/rocky/python-xdis 这个库支持跨Python版本反汇编,其安装完提供一个命令行工具pydisasm.exe,pydisasm.exe .\demo.exe_extracted\demo.pyc的结果如下所示。
# pydisasm version 6.0.4
# Python bytecode 3.8.0 (3413)
# Disassembled from Python 3.8.12 (default, Oct 12 2021, 03:01:40) [MSC v.1916 64 bit (AMD64)]
# Timestamp in code: 0 (1970-01-01 08:00:00)
# Source code size mod 2**32: 0 bytes
# Method Name: <module>
# Filename: demo.py
# Argument count: 0
# Position-only argument count: 0
# Keyword-only arguments: 0
# Number of locals: 0
# Stack size: 2
# Flags: 0x00000040 (NOFREE)
# First Line: 1
# Constants:
# 0: 0
# 1: None
# Names:
# 0: time
# 1: start
# 2: number
# 3: print
1: 0 LOAD_CONST (0)
2 LOAD_CONST (None)
4 IMPORT_NAME (time)
6 STORE_NAME (time)
3: 8 LOAD_NAME (time)
10 LOAD_METHOD (time)
12 CALL_METHOD 0
14 STORE_NAME (start)
4: 16 LOAD_CONST (0)
18 STORE_NAME (number)
5: 20 LOAD_NAME (print)
22 LOAD_NAME (number)
24 CALL_FUNCTION 1
26 POP_TOP
28 LOAD_CONST (None)
30 RETURN_VALUE
反编译decompile
即反编译(decompiler)字节码.pyc为Python源代码。https://github.com/rocky/python-decompile3 目前只支持Python 3.7-3.8,Python 3.9+还不支持。所以,使用高版本的Python,字节码被反编译的概率更小,更安全。反编译结果如下所示,源代码中的注释没有了。
$ decompyle3.exe .\demo.exe_extracted\demo.pyc
# decompyle3 version 3.8.0
# Python bytecode 3.8.0 (3413)
# Decompiled from: Python 3.8.12 (default, Oct 12 2021, 03:01:40) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: demo.py
import time
start = time.time()
number = 0
print(number)
# okay decompiling .\demo.exe_extracted\demo.pyc
Use https://github.com/rocky/python-decompile3. Unlike Java, there is no pretty mature tool for Python code decompilation.
But, it may raise error: `ValueError: bad marshal data (unknown type code) sometimes.
For complete decrypt, this maybe help.
https://github.com/pyinstaller/pyinstaller/blob/253feb7e16cd3a6a6d3ea2fb80c3491d30671e39/PyInstaller/loader/pyimod02_archive.py#L265
F.Y.I
def extract(self, name):
(typ, pos, length) = self.toc.get(name, (0, None, 0))
if pos is None:
return None
with self.lib:
self.lib.seek(self.start + pos)
obj = self.lib.read(length)
try:
if self.cipher:
obj = self.cipher.decrypt(obj)
obj = zlib.decompress(obj)
if typ in (PYZ_TYPE_MODULE, PYZ_TYPE_PKG):
obj = marshal.loads(obj)
except EOFError:
raise ImportError("PYZ entry '%s' failed to unmarshal" % name)
return typ, obj
猜你喜欢
- 2024-12-25 小白必备:如何用auto-py-to-exe轻松打包 Python 脚本
- 2024-12-25 Python3基础之构建setup.py
- 2024-12-25 加密Python源码方案 PyArmor
- 2024-12-25 破解文件处理难题:用 Python 处理 .txt 文件的必学方法
- 2024-12-25 python的print命令
- 2024-12-25 探秘PyMySQL:你可能错过的宝藏Python库
- 2024-12-25 深入探秘py_compile:你可能错过的Python宝藏
- 05-25Python 3.14 t-string 要来了,它与 f-string 有何不同?
- 05-25Python基础元素语法总结
- 05-25Python中的变量是什么东西?
- 05-25新手常见的python报错及解决方案
- 05-2511-Python变量
- 05-2510个每个人都是需要知道Python问题
- 05-25Python编程:轻松掌握函数定义、类型及其参数传递方式
- 05-25Python基础语法
- 257℃Python短文,Python中的嵌套条件语句(六)
- 257℃python笔记:for循环嵌套。end=""的作用,图形打印
- 256℃PythonNet:实现Python与.Net代码相互调用!
- 251℃Python操作Sqlserver数据库(多库同时异步执行:增删改查)
- 251℃Python实现字符串小写转大写并写入文件
- 106℃原来2025是完美的平方年,一起探索六种平方的算吧
- 90℃Python 和 JavaScript 终于联姻了!PythonMonkey 要火?
- 81℃Ollama v0.4.5-v0.4.7 更新集合:Ollama Python 库改进、新模型支持
- 最近发表
- 标签列表
-
- python中类 (31)
- python 迭代 (34)
- python 小写 (35)
- python怎么输出 (33)
- python 日志 (35)
- python语音 (31)
- python 工程师 (34)
- python3 安装 (31)
- python音乐 (31)
- 安卓 python (32)
- python 小游戏 (32)
- python 安卓 (31)
- python聚类 (34)
- python向量 (31)
- python大全 (31)
- python次方 (33)
- python桌面 (32)
- python总结 (34)
- python浏览器 (32)
- python 请求 (32)
- python 前端 (32)
- python验证码 (33)
- python 题目 (32)
- python 文件写 (33)
- python中的用法 (32)