Cython编译生成pyd文件后SQL字符串仍可见,该如何隐藏?
问题解答
可以实现该需求。Cython默认只会将Python代码转译为C代码再编译为二进制文件,代码中的字符串常量会默认直接存储在二进制的只读数据段中,因此直接用文本编辑器就能检索到明文,需要额外对SQL字符串做混淆处理才能隐藏。
具体操作方案
方案1:简单字符串拆分拼接(改动最小)
不要将完整的SQL语句定义为全局字符串常量,将SQL拆分为多个零散的子串分散在代码逻辑中,在需要调用SQL的位置再实时拼接生成完整语句,避免完整的明文SQL出现在二进制文件的常量段中。
示例:def get_report_sql(): part1 = "SELECT id, name, create_time " part2 = "FROM report_table " part3 = "WHERE status = 1 AND create_time >= ?" return part1 + part2 + part3该方案改动最小,足以防范普通用户直接打开pyd文件检索明文SQL的场景,但无法对抗有逆向经验的人员分析。
方案2:字符串异或加密(安全性较高)
预先对SQL字符串做异或加密,将加密后的字节数组硬编码到代码中,在需要使用SQL时再通过密钥解密得到明文,二进制文件中只会存储加密后的无意义字节,不会出现明文SQL。
Cython示例代码:from libc.stdlib cimport malloc, free cdef bytes decrypt_sql(const unsigned char* enc_buf, int buf_len, unsigned char key): cdef: int i unsigned char* tmp_buf = <unsigned char*>malloc(buf_len + 1) for i in range(buf_len): tmp_buf[i] = enc_buf[i] ^ key tmp_buf[buf_len] = b'\0' res = <bytes>tmp_buf free(tmp_buf) return res # 加密后的SQL字节数组,可提前用Python脚本生成:[ord(c)^0x3f for c in "SELECT * FROM report"] cdef const unsigned char enc_report_sql[20] = [ 0x27, 0x1a, 0x13, 0x1a, 0x18, 0x24, 0x7f, 0x6a, 0x7f, 0x16, 0x29, 0x22, 0x15, 0x7f, 0x29, 0x1a, 0x20, 0x22, 0x29, 0x24 ] def get_report_sql(): return decrypt_sql(enc_report_sql, 20, 0x3f).decode('utf-8')可以进一步将密钥拆分为多个零散常量分散在代码的不同位置,运行时再拼接生成完整密钥,大幅提高逆向破解的门槛。
方案3:开启编译器字符串混淆选项(无需改代码)
编译pyd时给C编译器添加字符串混淆相关的编译参数,编译器会自动对所有常量字符串做加密存储,运行时自动解密还原,不需要修改业务代码:- 用MSVC(Windows平台常用)编译时,添加
/Obfuscate编译选项 - 用GCC/Clang编译时,添加
-fdata-sections以及第三方字符串混淆插件参数
- 用MSVC(Windows平台常用)编译时,添加
注意事项
所有字符串混淆方案都只能提高破解成本,无法做到100%绝对不可破解。只要程序运行时需要拿到明文SQL执行,理论上就可以通过调试、内存dump等方式拿到明文,但足以应对绝大多数普通场景下的源码保护需求。
内容的提问来源于stack exchange,提问作者AIRGG
相关产品推荐
相关产品推荐

