我正在用Python开发一款软件,它将分发给我雇主的客户。我的雇主想用一个有时间限制的许可证文件来限制软件的使用。
如果我们分发.py文件甚至.pyc文件,将很容易(反编译和)删除检查许可证文件的代码。
另一个方面是,我的雇主不希望我们的客户读到代码,担心代码可能被窃取,或者至少是“新颖的想法”。
有什么好办法来解决这个问题吗?
我正在用Python开发一款软件,它将分发给我雇主的客户。我的雇主想用一个有时间限制的许可证文件来限制软件的使用。
如果我们分发.py文件甚至.pyc文件,将很容易(反编译和)删除检查许可证文件的代码。
另一个方面是,我的雇主不希望我们的客户读到代码,担心代码可能被窃取,或者至少是“新颖的想法”。
有什么好办法来解决这个问题吗?
当前回答
编译python并分发二进制文件!
明智的想法:
使用Cython, Nuitka, Shed Skin或类似的工具将python编译成C代码,然后将应用程序作为python二进制库(pyd)分发。
这样,就不会留下任何Python(字节)代码,我认为你已经做了任何人(即你的雇主)可以从常规代码中期望的任何合理数量的模糊。(.NET或Java比这种情况更不安全,因为字节码没有混淆,可以相对容易地反编译成合理的源代码。)
Cython与CPython的兼容性越来越好,所以我认为它应该可以工作。(实际上,我正在考虑把这个应用到我们的产品上。我们已经以pyd/dll的形式构建了一些第三方库,所以以二进制文件的形式发布我们自己的python代码对我们来说并不是太大的一步。)
看看这篇博客文章(不是我写的),关于如何做到这一点的教程。(thx @hithwen)
疯狂的想法:
您可能可以让Cython为每个模块分别存储c文件,然后将它们全部连接起来,并使用大量内联来构建它们。这样一来,你的Python模块就变得非常单一,很难用普通工具来解决。
超越疯狂:
如果你可以静态地链接(并优化)python运行时和所有库(dll),你就可以构建一个单独的可执行文件。这样,就很难拦截对python和你所使用的任何框架库的调用。但是,如果您使用的是LGPL代码,则无法做到这一点。
其他回答
在我自己的项目中,我对软件保护进行了一般的研究,总的观点是完全的保护是不可能的。您唯一希望实现的事情是将保护添加到一个级别,使您的客户绕过该级别的成本高于购买另一个许可证的成本。
话虽如此,我只是检查谷歌的python混淆,没有发现很多东西。在. net解决方案中,混淆将是在windows平台上解决问题的第一种方法,但我不确定是否有人在Linux上有与Mono一起工作的解决方案。
接下来要做的就是用编译语言写代码,如果你真的想这么做,那就用汇编语言。一个被剥离的可执行文件将比解释语言更难反编译。
这一切都归结于权衡。一方面,你可以用python轻松地进行软件开发,在python中也很难隐藏秘密。另一方面,你用汇编程序编写的软件更难编写,但更容易隐藏秘密。
你的老板必须在这个连续统一体中选择一个点来支持他的要求。然后他必须给你工具和时间,这样你才能建造他想要的东西。然而,我敢打赌,他会反对实际开发成本与潜在货币损失之间的对立。
使用Cython。它将您的模块编译为高性能的C文件,然后这些C文件可以编译为本机二进制库。与.pyc字节码相比,这基本上是不可逆转的!
我已经写了一篇关于如何为Python项目设置Cython的详细文章,请查看:
使用Cython保护Python源代码
用同样的方法保护c/c++的二进制文件,即对可执行文件或库二进制文件中的每个函数体进行混淆,在每个函数项的开头插入指令“跳转”,跳转到特定的函数来恢复混淆的代码。字节码是Python脚本的二进制代码,所以
首先编译python脚本代码对象 然后迭代每个代码对象,将每个代码对象的co_code混淆如下所示
0 JUMP_ABSOLUTE n = 3 + len(bytecode) 3 ... ... Here it's obfuscated bytecode ... n LOAD_GLOBAL ? (__pyarmor__) n+3 CALL_FUNCTION 0 n+6 POP_TOP n+7 JUMP_ABSOLUTE 0
将混淆的代码对象保存为.pyc或.pyo文件
那些模糊的文件(。Pyc或.pyo)可以被普通的python解释器使用,当这些代码对象第一次被调用时
First op is JUMP_ABSOLUTE, it will jump to offset n At offset n, the instruction is to call a PyCFunction. This function will restore those obfuscated bytecode between offset 3 and n, and put the original byte-code at offset 0. The obfuscated code can be got by the following code char *obfucated_bytecode; Py_ssize_t len; PyFrameObject* frame = PyEval_GetFrame(); PyCodeObject *f_code = frame->f_code; PyObject *co_code = f_code->co_code; PyBytes_AsStringAndSize(co_code, &obfucated_bytecode, &len) After this function returns, the last instruction is to jump to offset 0. The really byte-code now is executed.
有一个工具Pyarmor可以通过这种方式混淆python脚本。
我记录了如何通过将其转换为.so文件和将其转换为python轮文件来混淆python: https://github.com/UM-NLP/python-obfuscation
无论是Cython还是Nuitka都不是答案,因为当运行用Nuitka或Cython编译成.pyd或.exe文件的解决方案时,会生成一个缓存目录,所有的.pyc文件都会复制到缓存目录中,因此攻击者可以简单地反编译.pyc文件并查看您的代码或更改它。