我正在用 Python 开发一个软件,该软件将分发给我雇主的客户。我的雇主想通过有时间限制的许可证文件来限制软件的使用。
如果我们分发 .py
文件甚至 .pyc
文件,则很容易(反编译和)删除检查许可证文件的代码。
另一方面是我的雇主不希望我们的客户阅读代码,担心代码可能被盗或至少是“新颖的想法”。
有没有好的方法来处理这个问题?
“有什么好办法处理这个问题吗?”不会。没有任何东西可以防止逆向工程。甚至 DVD 机器上的固件也被逆向工程并暴露了 AACS Encryption key。尽管 DMCA 将其定为刑事犯罪。
由于没有任何技术方法可以阻止您的客户阅读您的代码,因此您必须使用普通的商业方法。
许可证。合同。条款和条件。即使人们可以阅读代码,这仍然有效。请注意,您的某些基于 Python 的组件可能要求您在销售使用这些组件的软件之前支付费用。此外,一些开源许可证禁止您隐藏该组件的来源。提供重要价值。如果你的东西非常好——价格难以拒绝——就没有动力浪费时间和金钱对任何东西进行逆向工程。逆向工程很昂贵。让你的产品稍微便宜一点。提供升级和增强功能,使任何逆向工程都成为一个坏主意。当下一个版本破坏他们的逆向工程时,就没有意义了。这可能会走极端,但您应该提供新功能,使下一个版本比逆向工程更有价值。以极具吸引力的价格提供定制服务,以至于他们宁愿付钱给您来构建和支持增强功能。使用过期的许可证密钥。这很残忍,会给你带来坏名声,但它肯定会让你的软件停止工作。将其作为 Web 服务提供。 SaaS 不涉及向客户下载。
Python 作为一种字节码编译的解释语言,很难锁定。即使您使用像 py2exe 这样的 exe 打包程序,可执行文件的布局也是众所周知的,并且 Python 字节码也很容易理解。
通常在这种情况下,您必须做出权衡。保护代码到底有多重要?那里有真正的秘密(例如银行转账对称加密的密钥),还是你只是偏执?选择可以让您最快开发出最佳产品的语言,并对您的新颖想法的价值保持现实。
如果您决定确实需要安全地执行许可证检查,请将其编写为一个小的 C 扩展,以便许可证检查代码可以非常困难(但并非不可能!)进行逆向工程,并将大部分代码留在 Python 中.
mylicensedfunction(licenseblob liblob, int foo, int bar, std::string bash)
Python 不是你需要的工具
你必须使用正确的工具来做正确的事,而 Python 的设计初衷不是为了混淆。恰恰相反;在 Python 中,一切都是开放的或易于显示或修改的,因为这是该语言的哲学。
如果您想要一些无法看穿的东西,请寻找其他工具。这不是一件坏事,重要的是存在用于不同用途的几种不同工具。
混淆真的很难
即使是编译好的程序也可以进行逆向工程,所以不要认为你可以完全保护任何代码。您可以分析混淆的PHP,破解flash加密密钥等。新版本的Windows每次都被破解。
有法律要求是一个好方法
您无法阻止某人滥用您的代码,但您可以轻松发现是否有人这样做。因此,这只是一个偶然的法律问题。
代码保护被高估了
如今,商业模式倾向于销售服务而不是产品。您不能复制服务、盗版或窃取服务。也许是时候考虑顺其自然了……
编译python并分发二进制文件!
明智的想法:
使用 Cython、Nuitka、Shed Skin 或类似的东西将 python 编译为 C 代码,然后将您的应用程序作为 python 二进制库 (pyd) 分发。
这样一来,就不会留下任何 Python(字节)代码,而且我认为您已经完成了任何人(即您的雇主)可以从常规代码中获得的任何合理数量的模糊处理。 (.NET 或 Java 没有这种情况安全,因为该字节码没有被混淆,并且可以相对容易地被反编译成合理的源代码。)
Cython 越来越兼容 CPython,所以我认为它应该可以工作。 (我实际上正在为我们的产品考虑这个。我们已经在构建一些第三方库作为 pyd/dlls,所以将我们自己的 python 代码作为二进制文件发布对我们来说并不是一个太大的步骤。)
有关如何执行此操作的教程,请参阅 This Blog Post(不是我的)。 (谢谢@hithwen)
疯狂的想法:
您可能会让 Cython 为每个模块单独存储 C 文件,然后将它们全部连接起来并使用大量内联构建它们。这样一来,您的 Python 模块就非常单一,难以使用常用工具进行处理。
超越疯狂:
如果您可以静态链接到(并优化)python 运行时和所有库(dll),您可能能够构建单个可执行文件。这样,肯定很难拦截到/来自 python 和您使用的任何框架库的调用。但是,如果您使用的是 LGPL 代码,则无法做到这一点。
我了解您希望您的客户使用 python 的强大功能,但不想公开源代码。
以下是我的建议:
(a) 将代码的关键部分编写为 C 或 C++ 库,然后使用 SIP 或 swig 将 C/C++ API 公开给 Python 命名空间。
(b) 使用 cython 而不是 Python
(c) 在 (a) 和 (b) 中,应该可以将库作为具有 Python 接口的许可二进制文件分发。
你看过pyminifier吗?它会缩小、混淆和压缩 Python 代码。对于随意的逆向工程来说,示例代码看起来很讨厌。
$ pyminifier --nonlatin --replacement-length=50 /tmp/tumult.py
#!/usr/bin/env python3
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲמּ=ImportError
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ燱=print
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ巡=False
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ澨=object
try:
import demiurgic
except ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲמּ:
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ燱("Warning: You're not demiurgic. Actually, I think that's normal.")
try:
import mystificate
except ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲמּ:
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ燱("Warning: Dark voodoo may be unreliable.")
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲﺬ=ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ巡
class ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ𐦚(ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ澨):
def __init__(self,*args,**kwargs):
pass
def ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ클(self,dactyl):
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ퐐=demiurgic.palpitation(dactyl)
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ𠛲=mystificate.dark_voodoo(ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ퐐)
return ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ𠛲
def ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ𐠯(self,whatever):
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ燱(whatever)
if __name__=="__main__":
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ燱("Forming...")
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲﺃ=ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ𐦚("epicaricacy","perseverate")
ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲﺃ.ﺭ异𞸐𐤔ﭞﰣﺁں𝕌𨿩𞸇뻛𐬑𥰫嬭ﱌ𢽁𐡆𧪮Ꝫﴹ뙫𢤴퉊ﳦﲣפּܟﺶ𐐤ﶨࠔ𐰷𢡶𧐎𐭈𞸏𢢘𦘼ﶻ𩏃𦽨𞺎𠛘𐠲䉊ﰸﭳᣲ𐠯("Codswallop")
# Created by pyminifier (https://github.com/liftoff/pyminifier)
您的雇主是否知道他可以“窃取”其他人从您的代码中获得的任何想法?我的意思是,如果他们可以阅读您的作品,那么您也可以阅读他们的作品。也许看看你如何从这种情况中受益会比担心你会损失多少来获得更好的投资回报。
[编辑] 回答尼克的评论:
一无所获,一无所失。客户拥有他想要的东西(并且因为他自己做了改变而为此付出了代价)。由于他没有发布更改,就好像其他所有人都没有发生一样。
现在如果客户出售软件,他们必须更改版权声明(这是非法的,所以你可以起诉并且会赢 -> 简单案例)。
如果他们不更改版权声明,第 2 级客户会注意到该软件来自您的原创,并想知道发生了什么。他们很有可能会与您联系,因此您将了解您作品的转售情况。
同样,我们有两种情况:原始客户只卖了几份。这意味着他们无论如何都没有赚到多少钱,所以为什么要麻烦。或者他们大量出售。这意味着您有更好的机会了解他们的所作所为并采取相应措施。
但最终,大多数公司都试图遵守法律(一旦声誉受损,做生意就更难了)。所以他们不会窃取你的工作,而是与你一起改进它。因此,如果您包含源代码(带有保护您免于简单转售的许可证),他们很可能会简单地退回他们所做的更改,因为这将确保更改在下一个版本中并且他们不必维护它.这是双赢的:你得到了改变,如果他们真的非常需要,他们可以自己做出改变,即使你不愿意将它包含在官方版本中。
使用 Cython。它将您的模块编译为高性能的 C 文件,然后可以将其编译为本机二进制库。与 .pyc 字节码相比,这基本上是不可逆的!
我写了一篇关于如何为 Python 项目设置 Cython 的详细文章,请查看:
Protecting Python Sources With Cython
不要依赖混淆。正如您正确得出的结论,它提供的保护非常有限。更新:这是一个 link to paper,它在 Dropbox 中对混淆后的 python 代码进行了逆向工程。方法 - 操作码重新映射是一个很好的障碍,但显然它可以被击败。
相反,正如许多海报提到的那样:
不值得花时间进行逆向工程(你的软件太好了,付费是有意义的)
让他们签署合同并在可行的情况下进行许可证审核。
或者,正如出色的 Python IDE WingIDE 所做的那样:放弃代码。没错,放弃代码,让人们回来进行升级和支持。
运送 .pyc 文件有其问题——它们与创建它们的 python 版本以外的任何其他 python 版本不兼容,这意味着您必须知道在产品将运行的系统上运行的是哪个 python 版本。这是一个非常有限的因素。
在某些情况下,可以将软件的(全部,或至少一个关键部分)移动到您的组织托管的 Web 服务中。
这样,可以在您自己的服务器机房安全地执行许可证检查。
虽然没有完美的解决方案,但可以做到以下几点:
将一些关键的启动代码移动到本机库中。在本机库中强制执行许可证检查。
如果要删除对本机代码的调用,则程序无论如何都不会启动。如果它没有被删除,那么许可证将被强制执行。
尽管这不是跨平台或纯 Python 解决方案,但它会起作用。
我很惊讶在任何答案中都没有看到 pyconcrete。也许是因为它比问题更新?
这可能正是您所需要的(编辑)。
它不是混淆代码,而是在加载时对其进行加密和解密。
从 pypi page:
保护 python 脚本工作流程 your_script.py import pyconcrete pyconcrete 会在你的脚本导入 MODULE 时挂钩 import 模块,pyconcrete import hook 将首先尝试找到 MODULE.pye,然后通过 _pyconcrete.pyd 解密 MODULE.pye 并执行解密数据(如 . pyc 内容)加密和解密 _pyconcrete.pyd 中的密钥记录(如 DLL 或 SO)密钥将隐藏在二进制代码中,无法直接在 HEX 视图中看到
我认为还有另一种方法可以保护您的 Python 代码;混淆方法的一部分。我相信有一个像 Mount and Blade 这样的游戏,或者改变并重新编译了他们自己的 python 解释器(我认为是开源的原始解释器)并且只是将 OP 代码表中的 OP 代码更改为与标准 python OP 不同代码。
因此,python 源代码未修改,但 *.pyc 文件的文件扩展名不同,并且操作码与公共 python.exe 解释器不匹配。如果您检查了游戏数据文件,所有数据都是 Python 源格式。
可以用各种恶作剧来惹恼不成熟的黑客。阻止一群没有经验的黑客很容易。这是您不太可能击败的专业黑客。但我想,大多数公司不会让专业黑客长期留在员工中(可能是因为事情被黑客入侵了)。但是不成熟的黑客无处不在(读作好奇的 IT 人员)。
例如,您可以在修改后的解释器中允许它检查源代码中的某些注释或文档字符串。对于这样的代码行,您可以有特殊的 OP 代码。例如:
OP 234 用于源代码行“# Copyright I write this”,或者将该行编译成相当于“if False:”的操作码,如果“# Copyright”缺失。基本上由于某些晦涩的原因禁用了整个代码块。
重新编译修改后的解释器可能可行的一个用例是,您没有编写应用程序,该应用程序很大,但您需要付费保护它,例如当您是金融应用程序的专用服务器管理员时。
我发现让源代码或操作码对眼球开放,但对网络流量使用 SSL 有点矛盾。 SSL 也不是 100% 安全的。但它被用来阻止大多数人的眼睛阅读它。一点预防措施是明智的。
此外,如果有足够多的人认为 Python 源代码和操作码太显眼,那么很可能有人最终会为其开发至少一个简单的保护工具。因此,更多人问“如何保护 Python 应用程序”只会促进这种发展。
保护代码的唯一可靠方法是在您控制的服务器上运行它,并为您的客户端提供与该服务器接口的客户端。
根据客户是谁,一个简单的保护机制,结合一个合理的许可协议将比任何复杂的许可/加密/混淆系统更有效。
最好的解决方案是将代码作为服务出售,例如通过托管服务或提供支持——尽管这并不总是可行的。
将代码作为 .pyc
文件提供可以防止您的保护被几个 #
挫败,但这几乎不是有效的反盗版保护(好像有这样的技术),归根结底,它应该与公司签订体面的许可协议无法实现任何目标。
专注于使您的代码尽可能好用-拥有满意的客户将使您的公司获得更多的钱,而不是防止一些理论上的盗版..
使您的代码更难窃取的另一种尝试是使用 jython,然后使用 java obfuscator。
这应该可以很好地工作,因为 jythonc 将 python 代码转换为 java,然后将 java 编译为字节码。所以你混淆了类,反编译后真的很难理解发生了什么,更不用说恢复实际代码了。
jython 的唯一问题是您不能使用用 c 编写的 python 模块。
通过散列和签署重要文件并使用公钥方法检查它,使用标准加密方案签署您的代码怎么样?
通过这种方式,您可以为每个客户颁发带有公钥的许可证文件。
另外,您可以使用像 this one 这样的 python 混淆器(只是用谷歌搜索)。
你应该看看 getdropbox.com 上的人是如何为他们的客户端软件做的,包括 Linux。破解非常棘手,需要一些非常有创意的拆卸才能通过保护机制。
你可以用 Python 做的最好的事情就是模糊事物。
删除所有文档字符串
仅分发 .pyc 编译文件。
冻结它
隐藏类/模块中的常量,以便 help(config) 不会显示所有内容
您可以通过加密其中的一部分并即时解密并将其传递给 eval() 来添加一些额外的模糊性。但无论你做什么,有人可以打破它。
这些都不会阻止一个坚定的攻击者反汇编字节码或在帮助、目录等的帮助下挖掘你的 api。
拥有时间限制许可证并在本地安装的程序中检查它的想法是行不通的。即使有完美的混淆,也可以删除许可证检查。但是,如果您检查远程系统上的许可证并在封闭的远程系统上运行程序的重要部分,您将能够保护您的 IP。
防止竞争对手将源代码用作自己的源代码或编写相同代码的灵感版本,一种保护方法是在您的程序逻辑中添加签名(一些秘密能够证明代码是从您那里窃取的)并混淆python源代码,所以很难阅读和使用。
良好的混淆为您的代码添加了与将其编译为可执行文件(并剥离二进制文件)基本相同的保护。弄清楚混淆的复杂代码是如何工作的可能比实际编写自己的实现更难。
这无助于防止您的程序遭到黑客攻击。即使使用混淆代码许可证的东西也会被破解,并且程序可能会被修改为具有稍微不同的行为(就像将代码编译为二进制文件无助于保护本机程序一样)。
除了符号混淆之外,解构代码可能是个好主意,如果调用图指向许多不同的地方,即使实际上这些不同的地方最终做同样的事情,这会使一切变得更加混乱。
混淆代码中的逻辑签名(例如,您可以创建程序逻辑使用的值表,但也用作签名),可用于确定代码来自您。如果有人决定将您的混淆代码模块用作他们自己产品的一部分(即使在对其进行重新混淆以使其看起来不同之后),您可以证明,该代码与您的秘密签名一起被盗。
我已经为我自己的项目研究过一般的软件保护,一般的理念是完全保护是不可能的。您唯一希望实现的目标是将保护添加到一个级别,使您的客户绕过比购买另一个许可证要付出更多的代价。
话虽如此,我只是在检查谷歌的 python 混淆,并没有发现很多东西。在 .Net 解决方案中,混淆将是在 Windows 平台上解决问题的第一种方法,但我不确定是否有人在 Linux 上提供与 Mono 一起使用的解决方案。
接下来就是用编译语言编写代码,或者如果你真的想一路走下去,那就用汇编语言。剥离出来的可执行文件比解释语言更难反编译。
这一切都归结为权衡。一方面,您可以轻松地使用 python 进行软件开发,其中也很难隐藏秘密。另一方面,您有用汇编程序编写的软件,这更难编写,但更容易隐藏秘密。
你的老板必须在支持他要求的连续体中选择一个点。然后他必须给你工具和时间,这样你就可以建造他想要的东西。但是我敢打赌,他会反对实际开发成本与潜在的金钱损失。
可以将 py2exe 字节码放在 C 启动器的加密资源中,以便在内存中加载和执行它。一些想法here和here。
有些人还认为 a self modifying program 会使逆向工程变得昂贵。
您还可以找到 tutorials for preventing debuggers,使反汇编程序失败,设置 false debugger breakpoints 并使用校验和保护您的代码。搜索 ["crypted code" execute "in memory"] 获取更多链接。
但正如其他人已经说过的,如果你的代码值得,逆向工程师最终会成功。
使用与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 解释器使用
第一个op是JUMP_ABSOLUTE,它会跳转到offset n
在偏移 n 处,指令是调用 PyCFunction。该函数将恢复偏移量 3 和 n 之间的混淆字节码,并将原始字节码放在偏移量 0 处。混淆码可以通过以下代码 char *obfucated_bytecode; py_ssize_t len; PyFrameObject* 帧 = PyEval_GetFrame(); PyCodeObject *f_code = frame->f_code; PyObject *co_code = f_code->co_code; PyBytes_AsStringAndSize(co_code, &obfucated_bytecode, &len)
此函数返回后,最后一条指令是跳转到偏移量 0。现在执行真正的字节码。
有一个工具 Pyarmor 可以通过这种方式混淆 python 脚本。
关于隐藏python源代码有一个全面的答案,可以找到here。
讨论的可能技术有:
- 使用编译后的字节码 (python -m compileall
)
- 可执行创建者(或像 PyInstaller 这样的安装程序)
- 软件即服务(隐藏代码的最佳解决方案在我看来)
- python 源代码混淆器
uncompyle6
似乎可以很容易地反编译字节码。
使用 cxfreeze ( py2exe for linux ) 将完成这项工作。
http://cx-freeze.sourceforge.net/
它在 ubuntu 存储库中可用
如果我们专注于软件许可,我建议看一下我写的另一个 Stack Overflow 答案 here,以获得有关如何构建许可证密钥验证系统的一些灵感。
GitHub 上有一个开源库,可以帮助您进行许可证验证。
您可以通过 pip install licensing
安装它,然后添加以下代码:
pubKey = "<RSAKeyValue><Modulus>sGbvxwdlDbqFXOMlVUnAF5ew0t0WpPW7rFpI5jHQOFkht/326dvh7t74RYeMpjy357NljouhpTLA3a6idnn4j6c3jmPWBkjZndGsPL4Bqm+fwE48nKpGPjkj4q/yzT4tHXBTyvaBjA8bVoCTnu+LiC4XEaLZRThGzIn5KQXKCigg6tQRy0GXE13XYFVz/x1mjFbT9/7dS8p85n8BuwlY5JvuBIQkKhuCNFfrUxBWyu87CFnXWjIupCD2VO/GbxaCvzrRjLZjAngLCMtZbYBALksqGPgTUN7ZM24XbPWyLtKPaXF2i4XRR9u6eTj5BfnLbKAU5PIVfjIS+vNYYogteQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"
res = Key.activate(token="WyIyNTU1IiwiRjdZZTB4RmtuTVcrQlNqcSszbmFMMHB3aWFJTlBsWW1Mbm9raVFyRyJd",\
rsa_pub_key=pubKey,\
product_id=3349, key="ICVLD-VVSZR-ZTICT-YKGXL", machine_code=Helpers.GetMachineCode())
if res[0] == None not Helpers.IsOnRightMachine(res[0]):
print("An error occured: {0}".format(res[1]))
else:
print("Success")
您可以阅读有关配置 RSA 公钥等方式的更多信息 here。
我建议使用此服务来保护源代码:www.secupy.com。以下是快速入门摘录:
$ pip install secupy
$ secupy activate --token ...
$ secupy build -s . -d ./build
唯一的问题是它是商业软件,但有免费计划。
Cython
和 Nuitka
都不是答案,因为当运行使用 Nuitka
或 Cython
编译到 .pyd
或 .exe
文件中的解决方案时,会生成缓存目录并且所有 .pyc
文件都是复制到缓存目录中,因此攻击者只需反编译 .pyc
文件并查看您的代码或更改它。
import sys sys.dont_write_bytecode = true
不定期副业成功案例分享