我如何保护Python代码?

时间:2008-11-04 11:57:28

标签: python licensing obfuscation copy-protection

我正在开发一个Python软件,将分发给我的雇主的客户。我的雇主希望用限时许可证文件来限制软件的使用。

如果我们分发.py文件甚至.pyc文件,那么很容易(反编译)删除检查许可证文件的代码。

另一方面是我的雇主不希望客户阅读代码,担心代码可能被盗或至少是“新颖的想法”。

有没有一个很好的方法来处理这个问题?最好使用现成的解决方案。

该软件将在Linux系统上运行(因此我认为py2exe不会起作用)。

27 个答案:

答案 0 :(得分:438)

“有办法处理这个问题吗?”没有。没有什么可以防止逆向工程。甚至DVD机上的固件也经过逆向工程和AACS Encryption key曝光。尽管DMCA将其定为刑事犯罪,但这仍然存在。

由于没有任何技术方法可以阻止客户阅读您的代码,因此您必须采用普通的商业方法。

  1. 许可证。合同。条款和条件。即使人们可以阅读代码,这仍然有效。请注意,在使用这些组件销售软件之前,某些基于Python的组件可能要求您支付费用。此外,某些开源许可证禁止您隐藏该组件的来源或来源。

  2. 提供重要价值。如果你的东西是如此优秀 - 以难以拒绝的价格 - 没有动力浪费时间和金钱逆向工程。逆向工程很昂贵。使您的产品稍微便宜一点。

  3. 提供升级和增强功能,使任何逆向工程都成为一个坏主意。当下一个版本打破他们的逆向工程时,没有意义。这可以带到荒谬的极端,但你应该提供新的功能,使下一个版本比逆向工程更有价值。

  4. 以极具吸引力的价格提供定制服务,他们宁愿付钱给您构建并支持增强功能。

  5. 使用过期的许可密钥。这是残酷的,会给你一个坏名声,但它肯定会使你的软件停止工作。

  6. 将其作为网络服务提供。 SaaS不涉及向客户下载。

答案 1 :(得分:346)

Python是一种字节码编译的解释语言,很难锁定。即使您使用像py2exe这样的exe-packager,可执行文件的布局也是众所周知的,并且Python字节码很容易理解。

通常在这种情况下,你必须做出权衡。保护代码真的有多重要?那里有真正的秘密(例如银行转账的对称加密密钥),还是你只是偏执狂?选择能让您以最快的速度开发最佳产品的语言,并对您的新颖想法的价值具有现实性。

如果您确定需要安全地执行许可证检查,请将其写为小型C扩展,以便许可证检查代码可以非常难(但并非不可能!)进行逆向工程,并留下大部分Python中的代码。

答案 2 :(得分:307)

Python不是您需要的工具

您必须使用正确的工具来做正确的事情,并且Python不是设计为混淆的。恰恰相反;一切都是开放的或易于在Python中显示或修改,因为这是语言的哲学。

如果您想要无法透视的内容,请寻找其他工具。这不是一件坏事,重要的是存在不同用途的几种不同工具。

混淆真的很难

即使编译的程序也可以进行逆向工程,因此不要认为您可以完全保护任何代码。您可以分析混淆的PHP,破坏闪存加密密钥等。每次都会破解Windows的新版本。

有法律要求是一个很好的方法

您不能阻止某人滥用您的代码,但您可以轻松发现是否有人这样做。因此,这只是一个偶然的法律问题。

代码保护被高估

如今,商业模式倾向于销售服务而非产品。你不能复制服务,盗版或盗取它。也许现在是时候考虑顺其自然......

答案 3 :(得分:133)

编译python并分发二进制文件!

明智的想法:

使用CythonNuitkaShed Skin或类似的东西将python编译为C代码,然后将您的应用程序分发为python二进制库(pyd)。

这样,我认为没有任何Python(字节)代码,你已经做过任何合理数量的暗示,任何人(即你的雇主)都可以从常规代码中获得。 (.NET或Java比这种情况更安全,因为该字节码不会被混淆,并且可以相对容易地反编译成合理的源。)

Cython越来越与CPython兼容,所以我认为它应该有效。 (我实际上是在为我们的产品考虑这个问题。我们已经建立了一些第三方库作为pyd / dll,所以将我们自己的python代码作为二进制文件运送对我们来说并不是一个过大的步骤。)

有关如何操作的教程,请参阅This Blog Post(不是我)。 (thx @hithwen)

疯狂的想法:

你可能会让Cython分别为每个模块存储C文件,然后将它们全部连接起来并用重型内联构建它们。这样,你的Python模块非常单一,很难用常用工具进行芯片化。

超越疯狂:

如果可以静态链接(并优化)python运行时和所有库(dll),则可以构建单个可执行文件。这样,拦截来自/来自python的调用以及你使用的任何框架库肯定是很困难的。如果您使用的是LGPL代码,则无法完成此操作。

答案 4 :(得分:57)

我知道您希望您的客户使用python的强大功能,但不希望公开源代码。

以下是我的建议:

(a)将代码的关键部分写为C或C ++库,然后使用SIPswig将C / C ++ API公开给Python命名空间。

(b)使用cython代替Python

(c)在(a)和(b)中,应该可以使用Python接口将库分发为许可二进制文件。

答案 5 :(得分:33)

您的雇主是否意识到他可以“窃取”其他人从您的代码中获得的任何想法?我的意思是,如果他们能读你的作品,他们也可以。也许看看如何从这种情况中获益将会比你担心损失多少会带来更好的投资回报。

[编辑]回答尼克的评论:

没有任何收获,也没有任何损失。顾客拥有他想要的东西(并且因为他自己做了改变而付了钱)。由于他没有发布变更,所以就好像其他人都没有这样做。

现在,如果客户出售该软件,他们必须更改版权声明(这是非法的,因此您可以起诉并赢得 - >简单的案例)。

如果他们没有更改版权声明,二级客户会注意到该软件来自您原创并且想知道发生了什么。他们很可能会与您联系,因此您将了解转售您的工作。

我们又有两个案例:原始客户只卖了几份。这意味着他们无论如何也赚不到多少钱,所以为什么要这么麻烦。或者他们批量出售。这意味着你有更好的机会了解他们做了什么并做了些什么。

但最终,大多数公司都试图遵守法律(一旦他们的声誉被破坏,开展业务就会困难得多)。所以他们不会偷你的工作,而是和你一起改进它。因此,如果您包含源代码(具有保护您免受简单转售的许可证),他们可能会简单地推回他们所做的更改,因为这将确保更改在下一个版本中,并且他们不必维护它。这是双赢的:你得到了改变,即使你不愿意将它包括在官方版本中,他们也可以自己做出改变,如果他们真的迫切需要它。

答案 6 :(得分:25)

不要依赖混淆。正如您已正确总结的那样,它提供的保护非常有限。 更新:这是一个link to paper,它在Dropbox中反向设计混淆的python代码。这种方法 - 操作码重新映射是一个很好的障碍,但很明显它可以被击败。

相反,正如许多海报所提到的那样:

  • 不值得逆向工程时间(你的软件非常好,支付是有意义的)
  • 让他们签订合同并在可行的情况下进行许可审核。

或者,正如kick-ass Python IDE WingIDE所做的那样:赠送代码。这是正确的,让代码远离,让人们回来升级和支持。

答案 7 :(得分:18)

运送.pyc文件存在问题 - 它们与其创建的python版本不兼容任何其他python版本,这意味着您必须知道产品将运行的系统上运行的是哪个python版本。这是一个非常有限的因素。

答案 8 :(得分:16)

在某些情况下,可以将软件(全部或至少一个关键部分)移动到您的组织托管的Web服务中。

这样,可以在您自己的服务器机房的安全性下执行许可证检查。

答案 9 :(得分:14)

虽然没有完美的解决方案,但可以做到以下几点:

  1. 将一些关键的启动代码移动到本机库中。
  2. 在本机库中强制执行许可检查。
  3. 如果要删除对本机代码的调用,程序将无法启动。如果没有删除,则将强制执行许可。

    虽然这不是跨平台或纯Python解决方案,但它会起作用。

答案 10 :(得分:10)

我认为还有一种方法可以保护您的Python代码;混淆方法的一部分。我相信有一个像Mount和Blade这样的游戏或者改变并重新编译了他们自己的python解释器(我认为是开源的原始解释器)并且只是改变了OP代码表中的OP代码而不是标准的python OP码。

所以python源是未修改的,但* .pyc文件的文件扩展名不同,操作码与公共python.exe解释器不匹配。如果您检查了游戏数据文件,则所有数据都是Python源格式。

可以通过这种方式解决各种不成熟的黑客问题。阻止一群没有经验的黑客很容易。这是你不可能击败的专业黑客。但是大多数公司并没有让我的黑客长期存在于我想象中(可能是因为事情被黑客入侵)。但不成熟的黑客到处都是(好像是好奇的IT人员)。

例如,您可以在修改后的解释器中,允许它检查源中的某些注释或文档字符串。您可以为此类代码行提供特殊的OP代码。例如:

OP 234用于源代码行“#Ill rights I written this” 或者将该行编译成等同于“if False:”的操作码,如果缺少“#Impyright”。基本上禁用整个代码块似乎是一些不明原因。

重新编译修改后的解释器可能是可行的一个用例是你没有编写应用程序,应用程序很大,但是你需要付费才能保护它,例如当你是一个专用的服务器管理员用于财务时应用

我发现将源或操作码打开眼球有点矛盾,但使用SSL进行网络流量。 SSL也不是100%安全的。但它用来阻止大多数人的眼睛阅读它。一点点的预防措施是明智的。

此外,如果有足够多的人认为Python源代码和操作码太明显,那么最终可能会有人为它开发至少一个简单的保护工具。因此,越多人问“如何保护Python应用程序”只会促进这种发展。

答案 11 :(得分:10)

保护代码的唯一可靠方法是在您控制的服务器上运行它,并为您的客户端提供与该服务器连接的客户端。

答案 12 :(得分:9)

取决于客户端是谁,一个简单的保护机制,与合理的许可协议相结合,比任何复杂的许可/加密/混淆系统更有效。

最好的解决方案是将代码作为服务销售,比如通过托管服务或提供支持 - 尽管这并不总是实用。

将代码作为.pyc个文件运送,可以防止您的保护被少数#挫败,但这几乎不是有效的反盗版保护(就像有这样的技术一样),并且当天结束时,它不应该与公司达成任何合适的许可协议。

专注于使您的代码尽可能好用 - 拥有满意的客户将使您的公司远远超过防止理论上的盗版行为。

答案 13 :(得分:9)

使用Cython。它会将您的模块编译为高性能的C文件,然后可以将其编译为本机二进制库。与.pyc字节码相比,这基本上是不可逆的!

我写了一篇关于如何为Python项目设置Cython的详细文章,请查看:

<强> Protecting Python Sources With Cython

答案 14 :(得分:8)

使代码更难窃取的另一种尝试是使用jython然后使用java obfuscator

这应该可以正常工作,因为jythonc将python代码转换为java,然后将java编译为字节码。所以,如果你对这些类进行模糊处理,那么在反编译后很难理解发生了什么,更不用说恢复实际的代码了。

jython的唯一问题是你不能使用用c编写的python模块。

答案 15 :(得分:6)

我很惊讶没有在任何答案中看到pyconcrete。也许是因为它比问题更新?

它可能正是您所需要的(编辑)。

它不会混淆代码,而是加密它并在加载时解密。

来自pypi page

  

保护python脚本工作流程

     
      
  • your_script.py import pyconcrete
  •   
  • pyconcrete将挂钩导入模块
  •   
  • 当您的脚本导入MODULE时,   pyconcrete import hook将首先尝试查找MODULE.pye   通过MODULE.pye解密_pyconcrete.pyd并执行解密数据(如   .pyc内容)
  •   
  • 加密&amp;解密_pyconcrete.pyd中的密钥记录   (如DLL或SO)秘密密钥将隐藏在二进制代码中,不能   直接在HEX视图中查看
  •   

答案 16 :(得分:6)

你应该看看getdropbox.com的人如何为他们的客户端软件做这件事,包括Linux。破解是非常棘手的,需要一些非常有创意的反汇编才能通过保护机制。

答案 17 :(得分:6)

如何使用标准加密方案通过散列和签名重要文件并使用公钥方法进行检查来对代码进行签名?

通过这种方式,您可以为每个客户发布带有公钥的许可证文件。

另外,您可以使用像this one这样的python混淆器(只需用Google搜索)。

答案 18 :(得分:5)

有时间限制许可证并在本地安装的程序中检查它的想法是行不通的。即使有完美的混淆,也可以删除许可证检查。但是,如果您检查远程系统上的许可证并在封闭的远程系统上运行程序的重要部分,您将能够保护您的IP。

防止竞争对手将源代码用作自己的代码或编写相同代码的灵感版本,一种保护方法是向程序逻辑添加签名(一些秘密可以证明代码是从您那里窃取的)并且混淆了python源代码,因此很难阅读和利用。

良好的混淆为您的代码添加了基本相同的保护,将其编译为可执行文件(以及剥离二进制文件)。弄清楚混淆的复杂代码如何工作可能比实际编写自己的实现更难。

这无助于防止程序被黑客攻击。即使使用混淆代码,许可证的内容也会被破解,并且程序可能会被修改为具有稍微不同的行为(与将代码编译为二进制文件无法帮助保护本机程序的方式相同)。

除了符号混淆之外,重写代码可能是个好主意,这使得一切都变得更加混乱,例如,调用图指向许多不同的地方,即使实际上那些不同的地方最终会做同样的事情。

混淆代码中的逻辑签名(例如,您可以创建程序逻辑使用的值表,但也可以用作签名),可用于确定代码是否源自您。如果某人决定使用您的混淆代码模块作为他们自己产品的一部分(即使在重新进行混淆以使其看起来不同之后),您可以显示该代码被您的秘密签名窃取。

答案 19 :(得分:5)

使用Python可以做的最好的事情就是模糊不清。

  • 删除所有文档字符串
  • 仅分发.pyc编译文件。
  • 冻结
  • 隐藏类/模块中的常量,以便help(config)不显示所有内容

您可以通过加密部分内容并在运行中解密并将其传递给eval()来添加一些额外的默认设置。但无论你做什么,都有人可以打破它。

这些都不会阻止确定的攻击者通过帮助,dir等拆解字节码或挖掘你的api。

答案 20 :(得分:4)

我一直在研究自己的项目的软件保护,一般的理念是完全保护是不可能的。您唯一可以实现的目标是将保护添加到一个级别,这个级别会使您的客户更多地绕过,而不是购买另一个许可证。

有了这个说我只是在谷歌检查python封闭,并没有提出很多任何东西。在.Net解决方案中,在Windows平台上阻塞是第一种解决问题的方法,但我不确定是否有人在Linux上使用与Mono一起使用的解决方案。

接下来的事情是用编译语言编写代码,或者如果你真的想要一直使用汇编语言。一个被剥离的可执行文件比解释语言更难反编译。

这一切都取决于权衡。一方面,你可以轻松地在python中进行软件开发,其中也很难隐藏秘密。另一方面,你有用汇编语言编写的软件,这个软件更难写,但更容易隐藏秘密。

你的老板必须选择一个支持他的要求的连续统一体点。然后他必须给你工具和时间,这样你就可以建立他想要的东西。但我敢打赌,他会反对实际开发成本与潜在的金钱损失。

答案 21 :(得分:3)

可以将py2exe字节代码放在C语言启动程序的加密资源中,以便在内存中加载并执行它。一些想法herehere

有些人还想到a self modifying program使逆向工程变得昂贵。

您还可以找到tutorials for preventing debuggers,使反汇编程序失败,设置false debugger breakpoints并使用校验和保护您的代码。搜索[“加密代码”执行“在内存中”]以获取更多链接。

但正如其他人已经说过的,如果您的代码值得,逆向工程师最终会成功。

答案 22 :(得分:2)

长话短说:

  1. 加密您的源代码
  2. 编写自己的python模块加载器,以在导入时解密代码
  3. 在C / C ++中实现模块加载器
  4. 您可以向模块加载器添加更多功能,例如反调试器,许可证控制,硬件指纹绑定等。

有关更多详细信息,请查看此answer

如果您对该主题感兴趣,该项目将为您提供帮助-pyprotect

答案 23 :(得分:2)

如果我们专注于软件许可,我建议您看看我写的here的另一个Stack Overflow答案,以期获得如何构建许可证密钥验证系统的灵感。

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")

您可以了解有关here RSA公钥等配置方式的更多信息。

答案 24 :(得分:1)

使用cxfreeze(py2exe for linux)可以完成这项工作。

http://cx-freeze.sourceforge.net/

它可以在ubuntu存储库中找到

答案 25 :(得分:0)

使用相同的方法保护c / c ++的二进制文件,即对可执行文件或库二进制文件中的每个函数体进行模糊处理,插入指令&#34; jump&#34;在每个函数入口的开头,跳转到特殊函数以恢复混淆代码。字节码是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文件

当第一次调用那些代码对象时,普通的python解释器可以使用那些混淆文件(.pyc或.pyo)

  • 第一个操作是JUMP_ABSOLUTE,它会跳转到偏移量n

  • 在偏移量n处,指令是调用PyCFunction。此函数将在偏移量3和n之间恢复那些混淆的字节码,并将原始字节码放在偏移量0处。可以通过以下代码获取混淆代码

        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)
    
  • 此函数返回后,最后一条指令将跳转到 offset 0.现在执行了真正的字节码。

有一个工具Pyarmor可以通过这种方式混淆python脚本。

答案 26 :(得分:0)

关于隐藏python源代码有一个全面的答案,可以找到here

讨论的可能技术是:
-使用编译后的字节码(python -m compileall
-可执行文件的创建者(或PyInstaller之类的安装程序)
-软件即服务(我认为隐藏代码的最佳解决方案)
-python源代码混淆器