如何保护Python代码不被用户阅读?

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

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

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

有没有好的方法来处理这个问题?

414490 次浏览

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

通常在这种情况下,你必须做出权衡。保护代码到底有多重要?里面是否有真正的秘密(比如银行转账的对称加密密钥),还是你只是多疑了?选择能让你最快开发出最好产品的语言,对你的新想法有多有价值持现实态度。

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

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

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

[编辑]回复Nick的评论:

没有收获也没有损失。客户得到了他想要的东西(并且为此付出了代价,因为他自己做了更改)。由于他没有发布更改,就好像其他人没有发生一样。

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

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

再一次,我们有两种情况:最初的客户只卖了几本。这意味着他们无论如何都赚不到多少钱,所以为什么要麻烦呢?或者他们大量出售。这意味着你有更好的机会了解他们在做什么,并做些什么。

但最终,大多数公司还是会遵守法律(一旦他们的声誉受损,生意就更难做了)。所以他们不会窃取你的作品,而是和你一起改进它。所以如果你包含源代码(有许可证,可以保护你免受简单的转售),很可能他们会简单地推迟他们所做的更改,因为这将确保更改在下一个版本中,他们不必维护它。这是双赢的:你得到了更改,如果他们真的非常需要,他们可以自己做出更改,即使你不愿意将其包含在正式版本中。

我已经为自己的项目研究了软件保护的一般情况,一般的理念是完全保护是不可能的。您唯一希望实现的是将保护添加到一个级别,该级别将使您的客户绕过的成本高于购买另一个许可证的成本。

话虽如此,我只是在谷歌上搜索python的困惑,并没有发现很多东西。在. net解决方案中,困惑将是Windows平台上解决问题的第一种方法,但我不确定是否有人有与Mono一起工作的Linux解决方案。

接下来的事情是用编译语言编写代码,或者如果您真的想一直这样做,那么使用汇编程序。剥离的可执行文件比解释语言更难反编译。

这一切都归结为权衡。一方面,你可以轻松地用python开发软件,其中也很难隐藏秘密。另一方面,你有用汇编程序编写的软件,编写起来要困难得多,但隐藏秘密要容易得多。

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

“有什么好办法来解决这个问题吗?”没有。没有任何东西可以防止逆向工程。甚至DVD机器上的固件也被逆向工程并暴露了AACS加密密钥。尽管DMCA将其定为刑事犯罪。

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

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

  2. 提供显著的价值。如果你的东西是那么好-在一个价格是很难拒绝-没有动机浪费时间和金钱逆向工程任何东西。逆向工程是昂贵的。使你的产品稍微便宜一点。

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

  4. 以如此有吸引力的价格提供定制,以至于他们宁愿付钱给你来构建和支持增强功能。

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

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

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

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

根据客户端的不同,简单的保护机制与合理的许可协议相结合,将比任何复杂的许可/加密/混淆系统更有效。

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

将代码作为.pyc文件发送将防止您的保护被一些#挫败,但它几乎没有有效的反盗版保护(就像有这样的技术一样),并且在一天结束时,它不应该实现与公司签订的体面许可协议所能实现的任何目标。

集中精力让你的代码尽可能好用——拥有满意的客户会让你的公司赚更多的钱,而不是防止一些理论上的盗版。

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

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

另外,您可以使用像这一个这样的python混淆器(刚刚谷歌了一下)。

Python不是你需要的工具

你必须使用正确的工具去做正确的事情,而Python并不是被设计成混淆的。恰恰相反;在Python中,一切都是开放的,或者容易揭示或修改,因为这是语言的哲学。

如果你想要一些你看不透的东西,寻找另一个工具。这不是一件坏事,重要的是有几种不同的工具用于不同的用途。

混淆真的很难

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

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

你无法阻止某人滥用你的代码,但你可以很容易地发现是否有人这样做。因此,这只是一个偶然的法律问题。

代码保护被高估了

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

使用Python所能做的最好的事情就是模糊事物。

  • 去掉所有docstring
  • 仅分发. pyc编译文件。
  • 冻结它
  • 模糊类/模块中的常量,以便help(config)不会显示所有内容

您可能可以通过加密部分内容并动态解密并将其传递给ava()来添加一些额外的隐蔽性。但无论您做什么,都有人可以打破它。

这些都不会阻止有决心的攻击者反汇编字节码或使用help、dir等挖掘您的api。

不要依赖混淆。正如您正确得出的结论,它提供的保护非常有限。 更新:这是一个链接到纸张,它在Dropbox中逆向工程混淆了python代码。方法-操作码重新映射是一个很好的障碍,但显然它可以被击败。

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

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

或者,就像出色的Python IDE WingIDE所做的那样:放弃代码。没错,放弃代码,让人们回来升级和支持。

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

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

  1. 将一些关键的启动代码移动到本机库中。
  2. 在本机库中强制执行许可证检查。

如果删除对本机代码的调用,程序无论如何都不会启动。如果不删除,则将强制执行许可证。

虽然这不是一个跨平台或纯Python解决方案,但它可以工作。

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

以下是我的建议:

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

(b)使用cython而不是Python

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

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

另一种使代码更难窃取的尝试是使用jython,然后使用java混淆器

这应该工作得很好,因为jythonc将python代码翻译为java,然后将java编译为字节码。所以当你混淆类时,很难理解反编译后发生了什么,更不用说恢复实际代码了。

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

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

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

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

这并不能防止您的程序遭到黑客攻击。即使使用混淆代码许可证的东西也会被破解,程序可能会被修改为具有略微不同的行为(就像将代码编译为二进制文件无助于保护本机程序一样)。

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

代码中的逻辑签名(例如,你可能创建了一个价值观表,既被程序逻辑使用,也被用作签名),这可用于确定代码是否来自你。如果有人决定将你的代码模块用作他们自己产品的一部分(即使是经过重新混淆使其看起来不同之后),你可以显示,这段代码是用你的秘密签名窃取的。

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

明智的想法:

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

这样,没有Python(字节)代码被留下,你已经做了任何合理数量的模糊化任何人(即你的雇主)可以期望从常规代码,我认为。(. NET或Java比这种情况下更不安全,因为字节码没有混淆,可以相对容易地反编译成合理的源代码。

Cython与CPython越来越兼容,所以我认为它应该可以工作。(实际上,我正在为我们的产品考虑这一点…我们已经在构建一些第三方库作为pyd/dlls,因此将我们自己的python代码作为二进制文件交付对我们来说并不是太大的一步。)

参见此博客文章(不是我),了解如何做到这一点的教程。(thx@hithwen)

疯狂的想法:

您可能会让Cython为每个模块单独存储C文件,然后只需将它们全部连接起来并使用繁重的内联构建它们。这样,您的Python模块非常单一,难以使用普通工具进行集成。

超越疯狂:

如果你可以静态链接到(并使用)python运行时和所有库(dll),你也许能够构建单个可执行文件。这样,拦截对python和你使用的任何框架库的调用肯定很困难。但是,如果你使用的是LGPL代码,这是无法做到的。

使用cx冻结(py2exe for linux)将完成这项工作。

它在ubuntu存储库中可用

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

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

用这种方式来对付不成熟的黑客,可以用各种卑鄙的伎俩。阻止一群没有经验的黑客很容易。你不太可能打败专业黑客。但我想,大多数公司不会长期保留专业黑客(可能是因为事情被黑了)。但不成熟的黑客无处不在(被理解为好奇的IT员工)。

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

OP 234是源代码行“#版权我写了这个” 或者如果缺少“#版权”,则将该行编译为等效于“if False:”的操作代码。基本上出于某种模糊的原因禁用了整个代码块。

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

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

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

可以在加密资源中为C启动器提供py2exe字节码,该启动器在内存中加载和执行它。一些想法这里这里

有些人还想到了自我修改程序使逆向工程变得昂贵。

您还可以找到防止调试器的教程,使反编译器失败,设置错误调试器断点并使用校验和保护您的代码。搜索[“加密代码”执行“在内存中”]以获取更多链接。

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

你看过小精灵吗?它确实缩小、混淆和压缩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)

使用Cython。它会将您的模块编译为高性能的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解释器使用,当这些代码对象第一次被调用时

  • 第一个操作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)
    
  • After this function returns, the last instruction is to jump to offset 0. The really byte-code now is executed.

There is a tool Pyarmor to obfuscate python scripts by this way.

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

这可能正是你所需要的。

它不会混淆代码,而是在加载时对其进行加密和解密。

来自pypi页面

保护python脚本工作流程

  • your_script.pyimport pyconcrete
  • py具体将挂钩导入模块
  • 当你的脚本导入MODULE时, py混凝土导入钩子将首先尝试找到MODULE.pye,然后 通过_pyconcrete.pyd解密MODULE.pye并执行解密数据(如 . pyc内容)
  • 加密和解密_pyconcrete.pyd中的密钥记录 (如DLL或SO)密钥将隐藏在二进制代码中,不能 直接在HEX视图中看到它

如果我们专注于软件许可,我建议看看我写的另一个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")

您可以阅读有关RSA公钥等配置方式的更多信息这里

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

讨论的可能技术有:
-使用编译的字节码(python -m compileall
-可执行创建者(或安装程序,如PyInstaller
-软件即服务(在我看来,隐藏代码的最佳解决方案)
-python源代码混淆器

NeiherCythonNuitka不是答案,因为当运行用NuitkaCython编译成.pyd.exe文件的解决方案时,会生成一个缓存目录,并且所有.pyc文件都被复制到缓存目录中,因此攻击者只需反编译.pyc文件即可查看您的代码或更改它。

我记录了如何通过将python转换为. so文件并将其转换为python轮文件来混淆python: https://github.com/UM-NLP/python-obfuscation