PyArmor?加密和传递python源代码的简单方法?


介绍

在合同开发过程中,我认为有些情况下您必须将交付的产品交付给客户。在这种情况下,例如,如果该功能可以以SaaS的形式提供,则客户端将访问该API并使用该功能,因此,当然不可能在此端掌握源代码。
但是,我认为在许多情况下这是不现实的。有一个名为PyArmor的库在这种情况下很有用。 PyArmor是一个对源代码进行加密的库,从理论上讲,源代码无法恢复。当您要快速交付源代码时,这是一个非常方便的库。除了加密外,还可以在授予各种许可证(可用期限,执行设备等)之后进行加密。
关于PyArmor,如果您用google搜索,还会有其他文章发表,但是由于规范稍有变化,我这次尝试将其概述为一篇文章,其中包括备忘录的含义。
有关如何使用PyArmor的信息,请参阅以下官方文档。

PyArmor官方文档

该博客的源代码发布在[GitHub]上。有关环境,请参阅Mac的本地环境,有关所需的库,请参阅Pipfile。

其实尝试

加密前

这是加密之前的代码。 [Single_Module]
读取图像文件后,将训练有素的VGG16模型用于图像分类和图像显示。

Single_Module / main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import os
import sys
import cv2
import numpy as np
import matplotlib.pyplot as plt
import torch
from torchvision import models, transforms

sys.path.append(os.path.abspath('..'))
import imagenet_class


img = cv2.imread('../baseball.png')
img = cv2.resize(img, (256, 256))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_tensor = transforms.ToTensor()(img)
img_tensor = img_tensor.unsqueeze_(0)

model = models.vgg16(pretrained=True)

output = model(img_tensor)
output = np.argmax(output.detach().numpy())

print(imagenet_class.target[str(output)][1])   # ballplayer

plt.imshow(img)
plt.show()

スクリーンショット 2020-08-26 18.31.36.png

您可以看到

结果也正确地分类为ballplayer

加密

使用以下命令执行加密。

1
$ pyarmor obfuscate main.py

执行

之后,将直接在dist目录下创建目录。内容文件如下。

  • pytransform / _pytransform.dylib

    • 运行时使用的动态库(在Mac上为.dylib文件,在Linux上为.so文件)
  • dist / main.py

    • 混淆文件

许可加密

尽管它在正式文档的Generating License For Obfuscated Scripts部分中列出,但首先执行以下命令。 (免费名称,例如r001)

1
$ pyarmor licenses --expired 2022-01-01 r001

然后,将直接在目录下创建licenses目录,并在目录下创建各种文件。接下来,像以前一样,使用pyarmor obfuscate命令加密主文件,但是使用以下选项执行该文件。

1
$ pyarmor obfuscate --with-license licenses/r001/license.lic main.py

然后,可以以具有到期日期的许可证形式进行加密。 [Single_Module_Obfuscating_pre]

  • 如果您使用前面的命令尝试--expired 2019-01-01,则将无法执行加密的主文件,因为它已经过期。
  • 也可以通过与上述相同的方式颁发指定设备的许可证。有关详细信息,请参见官方文档。

执行加密的文件

加密后的主文件可以用与普通python脚本相同的方式执行。由于到目前为止,加密的主文件直接存在于dist目录下,因此相对路径与原始路径略有不同。因此,为了对齐路径,我进行了类似[Single_Module_Obfuscating]的配置。除了更改文件的位置之外,我没有其他麻烦。尝试执行以下命令。

1
$ python main.py

[结果]

[out]球手

スクリーンショット 2020-08-26 18.31.36.png

您可以看到结果与加密之前完全相同。另外,让我们尝试看看主文件的外观。

1
2
3
4
5
$ cat main.py

from pytransform import pyarmor_runtime
pyarmor_runtime()
__pyarmor__(__name__, __file__, b'\x50\x59\x41\x52 ...(以下省略)

您可以看到它通常以这种方式加密。正如我在前面的项目符号列表中所写的那样,要执行此主文件,总是需要同时生成一个动态库。

混淆包含不同目录下的.py文件时

对于以前的方法,默认情况下,直接加密在其下面的所有.py文件。如果要递归加密所有.py文件(包括子目录),请使用以下选项执行。

1
$ pyarmor obfuscate --recursive main.py

我会尝试的。
[Whole_Module]是加密之前的源代码,但是我们所做的是相同的。 (只需将文件分开)
正下方的main.py正在读取子目录下的model/model.py

Whole_Module /模型/ model.py

1
2
3
4
5
6
7
8
9
10
11
12
from torch import nn
from torchvision import models


class SampleModel(nn.Module):
    def __init__(self):
        super(SampleModel, self).__init__()
        self.backborn = models.vgg16(pretrained=True)

    def forward(self, x):
        x = self.backborn(x)
        return x

Whole_Module / main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import os
import sys
import cv2
import numpy as np
import matplotlib.pyplot as plt
import torch
from torchvision import transforms

from model.model import SampleModel
sys.path.append(os.path.abspath('..'))
import imagenet_class


img = cv2.imread('../baseball.png')
img = cv2.resize(img, (256, 256))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_tensor = transforms.ToTensor()(img)
img_tensor = img_tensor.unsqueeze_(0)

model = SampleModel()

output = model(img_tensor)
output = np.argmax(output.detach().numpy())

print(imagenet_class.target[str(output)][1])

plt.imshow(img)
plt.show()

在这里,当执行上一条命令时,将创建一个新的dist目录,并还将创建加密的main.pymodel.py以及动态库。 [Whole_Module_Obfuscating_pre]。但是,由于与以前相同的原因无法执行(图像文件的相对路径不同),因此生成的文件已被移动。可以像以前一样毫无问题地执行此操作。 [Whole_Module_Obfuscating]