1.1 什么是代码混淆
代码混淆是指将代码进行加密、压缩、乱序等操作,使得代码难以被阅读和理解,从而达到保护代码的目的。代码混淆可以有效地防止代码被反编译和盗用,提高代码的安全性。
严格意义上说,这一方法并不是加密,而是上代码的可读性变差。比如删除注释,添加毫无意义的注释,添加无效代码,对变量、函数、类进行重命名等。内容不可读,代码就受到了保护。代码混淆的工具很多,比如pyobfuscate。
1.2 pyobfuscate 安装使用
pyobfusate
通过多种方式转换源代码。其中一些转换是可逆的,有些转换则是不可逆的。以下是pyobfuscate
目前的作用列表:
-
删除注释和文档字符串(不可逆)
-
更改缩进(可逆)
-
在标记之间添加空白(有些可逆)
-
重命名函数、类和变量(不可逆)
-
插入伪行而不是空行。
pyobfusate
一次只对一个源文件进行操作,它没有混淆几个想文件之间的接口。
安装:
git clone https://github.com/astrand/pyobfuscate.git
cd pyobfuscate/
pip install .
执行代码混淆命令,将混淆后的结果重定向输出到指定文件:
python pyobfuscate.py [source.py] > [out.py]
将pyobfuscate.py
复制到python环境的Scripts
,每次进行代码混淆,则进入该Scripts执行python pyobfuscate.py [source.py] > [out.py]
1.3 实践
代码混淆后会改变其中的函数名,引用到该代码的外部函数需要将其改为混淆之后的函数名。项目实践中,在变与不变之间构建一个桥梁,避免每次混淆代码后都要改变其引用的代码。
将函数名放到了字典中,该字典的key为字符串常量,不会被混淆,value存函数名,是会被混淆的。该字典在__init__.py
包(package)中初始化,并由模块(module)中赋具体的函数名。执行代码混淆时,__init__.py
混淆,而是混淆包内的模块,这样就能保证__init__.py
中的字典记录的是字符串常量与最新函数名对应关系。
代码混淆前
目录结构如上所示,需要混淆的文件以包(package)的形式放到一个文件夹下。
main.py
if __name__ == '__main__':
import my_package
my_package.func_dict['hello']()
my_package.func_dict['func_1']()
my_package.func_dict['func_2']()
my_package/__init__.py
# 1. 先定义函数名字典func_dict
func_dict = {
'hello': None,
'func_1': None,
'func_2': None,
}
# 2. 再通过 from import
# 将func_dict赋值为混淆后的函数名
from . import my_module_1
from . import my_module_2
my_package/my_module_1.py
from . import func_dict
def hello():
print('hello')
def func_1():
print('func_1')
func_dict['hello'] = hello
func_dict['func_1'] = func_1
my_package/my_module_2.py
from . import func_dict
def func_2():
func_dict['hello']()
print('func_2')
func_dict['func_2'] = func_2
代码混淆后
将my_module_1.py
、my_module_2.py
混淆后置dist文件夹:
python pyobfuscate.py my_algorithm_1.py > dist\my_module_1.py
python pyobfuscate.py my_algorithm_2.py > dist\my_module_2.py
my_package/my_module_1.py
if 82 - 82: Iii1i
from . import func_dict
if 87 - 87: Ii % i1i1i1111I . Oo / OooOoo * I1Ii1I1 - I1I
if 81 - 81: i1 + ooOOO / oOo0O00 * i1iiIII111 * IiIIii11Ii
def OOoOoo000O00 ( ) :
print ( 'hello' )
if 55 - 55: o0Oo - ii1I1iII1I1I . i1I1IiIIiIi1 % oo0O000ooO * iIIiiIIiii1
if 11 - 11: ooo0O0oO00
def o00o0OO00O ( ) :
print ( 'func_1' )
if 57 - 57: iiIi1 - ii % Ii * i1i1i1111I / Ii
if 43 - 43: iIIiiIIiii1
func_dict [ 'hello' ] = OOoOoo000O00
func_dict [ 'func_1' ] = o00o0OO00O
# dd678faae9ac167bc83abf78e5cb2f3f0688d3a3
my_package/my_module_2.py
from . import func_dict
if 82 - 82: Iii1i
if 87 - 87: Ii % i1i1i1111I . Oo / OooOoo * I1Ii1I1 - I1I
def ooo0oOoooOOO0 ( ) :
func_dict [ 'hello' ] ( )
print ( 'func_2' )
if 47 - 47: oO000o00o00o + II111i1I
if 99 - 99: iIIii11
func_dict [ 'func_2' ] = ooo0oOoooOOO0
# dd678faae9ac167bc83abf78e5cb2f3f0688d3a3
总结:
使用代码混淆时,需要清楚哪些内容是可以混淆的(如变量名等),哪些是不会混淆的(字符串、import等),了解其中的变与不变能更好构建项目。