@[TOC]python程序加密
加密方法对比
加密手段 | 优点 | 缺点 |
---|---|---|
发行 .pyc 文件 | 简单方便,提高了一点源码破解门槛。平台兼容性好,.py 能在哪里运行,.pyc 就能在哪里运行 | 解释器兼容性差,.pyc 只能在特定版本的解释器上运行。有现成的反编译工具,破解成本低 |
代码混淆 | 简单方便,提高了一点源码破解门槛。兼容性好,只要源码逻辑能做到兼容,混淆代码亦能 | 只能对单个文件混淆,无法做到多个互相有联系的源码文件的联动混淆。代码结构未发生变化,也能获取字节码 |
使用 py2exe | 能够直接打包成 exe,方便分发和执行。破解门槛比 .pyc 更高一些 | 兼容性差,只能运行在 Windows 系统上。生成的可执行文件内的布局是明确、公开的,可以找到源码对应的 .pyc 文件,进而反编译出源码 |
使用 Cpython | 生成的二进制 .so 或 .pyd 文件难以破解。同时带来了性能提升 | 兼容性稍差,对于不同版本的操作系统,可能需要重新编译。虽然支持大多数 Python 代码 |
Cpython 加密流程如下:
基础环境准备:
yum install gcc -y
pip install Cython
使用 Cython 进行开发的步骤
构建一个测试项目test
1)编写文件hellotest.py cat …/test/hello/hellotest.py
class Hello:
def test(self):
return 'Hello World'
main.py 文件cat …/test/main.py
from hello.hellotest import Hello
h = Hello()
str = h.test()
print (t)
2)编写setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(name='Hello World app',
ext_modules=cythonize('hello/hellotest.py')) #注意这里推荐使用相对路径,编译出的so文件在引用其他模块时可能会出现路径问题
3)编译为 .c 在进一步编译为 .so 或 .pyd
python setup.py build_ext --生成.so 文件
python setup.py build_ext --inplace
加密前目录结构
test/
├── hello
│ └── hellotest.py
├── main.py
└── setup.py
加密后目录结构
python setup.py build_ext
test/
├── build
│ ├── lib.linux-aarch64-3.7
│ │ └── hellotest.cpython-37m-aarch64-linux-gnu.so
│ └── temp.linux-aarch64-3.7
│ └── hello
│ └── hellotest.o
├── hello
│ ├── hellotest.c
│ └── hellotest.py
├── main.py
└── setup.py
添加参数后加密后目录结构
python setup.py build_ext --inplace
test/
├── build
│ └── temp.linux-aarch64-3.7
│ └── hello
│ └── hellotest.o
├── hello
│ ├── hellotest.c
│ └── hellotest.py
├── hellotest.cpython-37m-aarch64-linux-gnu.so
├── main.py
└── setup.py
加密后期望结果:
test/
├── hello
│ └── hellotest.cpython-37m-aarch64-linux-gnu.so
├── main.py
└── setup.py
加密后测试结果
python main.py
Hello World
加密步骤: 加密 *.py 文件 ,so, 替换源文件,删除加密过程中生成的相关依赖
方法:蛮力法,逐个遍历
特殊要求: 排除文件,排除目录
1.获取当前目录所有py 文件相对路径
2.切分为 路径 文件
3.切换至 路径 执行加密 操作
4.删除生成的临时文件
梳理工具脚本如下:
encrypt.py
import os
import sys
from distutils.core import setup
from Cython.Build import cythonize
# 不需要编译的文件
global exclude_list
exclude_list=['encrypt.py','main.py']
global pylist
pylist = []
# 功能,遍历搜索目录下所有 py 文件并返回列表
def search(basedir, target, exclude):
# 主目录下的所有文件,文件夹集合
items = os.listdir(basedir)
for item in items:
# 拼接
path = os.path.join(basedir, item)
# path 是目录,继续搜索
if os.path.isdir(path):
#print('[-]', path)
search(path, target, exclude)
# 不是目录,取最后一列值,判断是否以 target 结尾,并且为非排除文件
elif path.split('/')[-1].endswith(target) and path.split('/')[-1] not in exclude:
#print('[+]', path)
pylist.append(str(path))
else:
pass
# print('[!]',path)
#print (pylist)
return pylist
# 根据输入构建 setup.py 文件
def newSetupFile(exclude_list,filename):
str = '''
import os
import sys
from distutils.core import setup
from Cython.Build import cythonize
exclude_list = {} # 不需要编译的py文件
if __name__ == '__main__':
setup(ext_modules = cythonize('{}',exclude=exclude_list))
'''.format(exclude_list,filename)
file = open('setup.py',"w")
file.write(str)
file.close
# 清理setup 构建生成临时文件
def cleanSetupFile(filepath, filename):
os.chdir(filepath)
print('{}/{}'.format(filepath,filename))
os.system("rm -rf build")
os.remove(filename.split('.')[0]+'.c')
os.remove('setup.py')
os.remove(filename)
def main():
# list = search('./', '.py', exclude_list)
list = search(os.getcwd(), '.py', exclude_list)
for filepath in list:
os.path.split(filepath)
filename=os.path.split(filepath)[1]
filepath=os.path.split(filepath)[0]
# 切换目录
os.chdir(filepath)
# 写入setup.py 文件
newSetupFile(exclude_list,filename)
os.system("python setup.py build_ext --inplace")
cleanSetupFile(filepath, filename)
if __name__ == '__main__':
print('\033[1;31;40m 加密py文件为{} 路径下所有py文件,如有排除请更新exclude_list 列表 \033[0m'.format(os.getcwd()))
tag = input('请确认: \033[1;31;40m 加密后会删除源文件,请确认执行前是否备份: yes/no \033[0m')
if tag == 'yes':
main()
else:
print('\033[1;31;40m 请备份后执行加密操作 \033[0m')