pyarmor 9.2.6__3-py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyarmor/README.rst +53 -0
- pyarmor/__init__.py +4 -0
- pyarmor/benchmark.py +382 -0
- pyarmor/build_meta.py +126 -0
- pyarmor/cli/__init__.py +46 -0
- pyarmor/cli/__main__.py +812 -0
- pyarmor/cli/batch.py +62 -0
- pyarmor/cli/bootstrap.py +207 -0
- pyarmor/cli/bug.py +137 -0
- pyarmor/cli/command.py +563 -0
- pyarmor/cli/config.py +306 -0
- pyarmor/cli/context.py +790 -0
- pyarmor/cli/core.data.1 +0 -0
- pyarmor/cli/core.data.2 +0 -0
- pyarmor/cli/core.data.3 +0 -0
- pyarmor/cli/default.cfg +564 -0
- pyarmor/cli/docker.py +192 -0
- pyarmor/cli/generate.py +256 -0
- pyarmor/cli/hdinfo.py +81 -0
- pyarmor/cli/merge.py +232 -0
- pyarmor/cli/mixer.py +109 -0
- pyarmor/cli/model.py +460 -0
- pyarmor/cli/plugin.py +292 -0
- pyarmor/cli/project.py +1281 -0
- pyarmor/cli/public_capsule.zip +0 -0
- pyarmor/cli/register.py +1093 -0
- pyarmor/cli/repack.py +793 -0
- pyarmor/cli/resource.py +265 -0
- pyarmor/cli/shell.py +481 -0
- pyarmor/cobuilder.py +154 -0
- pyarmor/config.py +58 -0
- pyarmor/examples/README-ZH.md +188 -0
- pyarmor/examples/README.md +201 -0
- pyarmor/examples/build-for-exe.bat +166 -0
- pyarmor/examples/build-for-freeze.bat +166 -0
- pyarmor/examples/build-with-project.bat +152 -0
- pyarmor/examples/build-with-project.sh +110 -0
- pyarmor/examples/cx_Freeze/hello.py +5 -0
- pyarmor/examples/cx_Freeze/queens.py +87 -0
- pyarmor/examples/cx_Freeze/setup.py +23 -0
- pyarmor/examples/helloworld/foo.py +68 -0
- pyarmor/examples/obfuscate-app.bat +65 -0
- pyarmor/examples/obfuscate-app.sh +45 -0
- pyarmor/examples/obfuscate-pkg.bat +82 -0
- pyarmor/examples/obfuscate-pkg.sh +60 -0
- pyarmor/examples/pack-obfuscated-scripts.bat +38 -0
- pyarmor/examples/pack-obfuscated-scripts.sh +31 -0
- pyarmor/examples/py2exe/hello.py +5 -0
- pyarmor/examples/py2exe/queens.py +87 -0
- pyarmor/examples/py2exe/setup.py +36 -0
- pyarmor/examples/pybench/Arithmetic.py +777 -0
- pyarmor/examples/pybench/Calls.py +560 -0
- pyarmor/examples/pybench/CommandLine.py +642 -0
- pyarmor/examples/pybench/Constructs.py +564 -0
- pyarmor/examples/pybench/Dict.py +504 -0
- pyarmor/examples/pybench/Exceptions.py +699 -0
- pyarmor/examples/pybench/Imports.py +138 -0
- pyarmor/examples/pybench/Instances.py +66 -0
- pyarmor/examples/pybench/Lists.py +350 -0
- pyarmor/examples/pybench/Lookups.py +945 -0
- pyarmor/examples/pybench/NewInstances.py +75 -0
- pyarmor/examples/pybench/Numbers.py +784 -0
- pyarmor/examples/pybench/Setup.py +43 -0
- pyarmor/examples/pybench/Strings.py +568 -0
- pyarmor/examples/pybench/Tuples.py +360 -0
- pyarmor/examples/pybench/With.py +190 -0
- pyarmor/examples/pybench/clockres.py +42 -0
- pyarmor/examples/pybench/package/__init__.py +0 -0
- pyarmor/examples/pybench/package/submodule.py +0 -0
- pyarmor/examples/pybench/pybench.py +954 -0
- pyarmor/examples/pybench/systimes.py +214 -0
- pyarmor/examples/simple/queens.py +87 -0
- pyarmor/examples/testmod/hello.py +66 -0
- pyarmor/examples/testmod/queens.py +159 -0
- pyarmor/examples/testpkg/main.py +4 -0
- pyarmor/examples/testpkg/mypkg/__init__.py +13 -0
- pyarmor/examples/testpkg/mypkg/foo.py +2 -0
- pyarmor/helper/__init__.py +1 -0
- pyarmor/helper/build_data_module.py +130 -0
- pyarmor/helper/buildext.py +446 -0
- pyarmor/helper/get_bind_key.py +29 -0
- pyarmor/helper/get_license_info.py +25 -0
- pyarmor/helper/get_platform_name.py +82 -0
- pyarmor/helper/merge.py +298 -0
- pyarmor/helper/repack.py +395 -0
- pyarmor/helper/superuntime.py +58 -0
- pyarmor/license.tri +0 -0
- pyarmor/packer.py +720 -0
- pyarmor/platforms/darwin/x86_64/_pytransform.dylib +0 -0
- pyarmor/platforms/linux/x86/_pytransform.so +0 -0
- pyarmor/platforms/linux/x86_64/_pytransform.so +0 -0
- pyarmor/platforms/windows/x86/_pytransform.dll +0 -0
- pyarmor/platforms/windows/x86_64/_pytransform.dll +0 -0
- pyarmor/plugins/README.md +176 -0
- pyarmor/plugins/check_ntp_time.py +482 -0
- pyarmor/polyfills/__init__.py +62 -0
- pyarmor/polyfills/argparse.py +2360 -0
- pyarmor/product.key +1 -0
- pyarmor/project.py +249 -0
- pyarmor/protect_code.pt +68 -0
- pyarmor/protect_code2.pt +47 -0
- pyarmor/public.key +0 -0
- pyarmor/public_capsule.zip +0 -0
- pyarmor/pyarmor-deprecated.py +843 -0
- pyarmor/pyarmor-webui.py +2 -0
- pyarmor/pyarmor.py +1647 -0
- pyarmor/pyimcore.py +65 -0
- pyarmor/pyshield.key +0 -0
- pyarmor/pyshield.lic +0 -0
- pyarmor/pytransform.py +483 -0
- pyarmor/reform.py +81 -0
- pyarmor/register.py +220 -0
- pyarmor/sppmode.py +105 -0
- pyarmor/utils.py +1871 -0
- pyarmor-9.2.6.dist-info/LICENSE +287 -0
- pyarmor-9.2.6.dist-info/LICENSE-ZH +297 -0
- pyarmor-9.2.6.dist-info/LICENSE-ZH.7 +102 -0
- pyarmor-9.2.6.dist-info/LICENSE.7 +145 -0
- pyarmor-9.2.6.dist-info/METADATA +79 -0
- pyarmor-9.2.6.dist-info/RECORD +123 -0
- pyarmor-9.2.6.dist-info/WHEEL +6 -0
- pyarmor-9.2.6.dist-info/entry_points.txt +6 -0
- pyarmor-9.2.6.dist-info/top_level.txt +1 -0
pyarmor/README.rst
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Protect Python Scripts By Pyarmor
|
|
2
|
+
=================================
|
|
3
|
+
|
|
4
|
+
Pyarmor is a command line tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.
|
|
5
|
+
|
|
6
|
+
Key Features
|
|
7
|
+
------------
|
|
8
|
+
|
|
9
|
+
* The obfuscated script is still a normal `.py` script, in most of cases the original python scripts can be replaced with obfuscated scripts seamlessly.
|
|
10
|
+
* Provide many ways to obfuscate the scripts to balance security and performance
|
|
11
|
+
* Rename functions/methods/classes/variables/arguments, irreversible obfuscation
|
|
12
|
+
* Convert part of Python functions to C function, compile to binary by high optimize option, irreversible obfuscation
|
|
13
|
+
* Bind obfuscated scripts to fixed machine or expire obfuscted scripts
|
|
14
|
+
* Protect obfuscated scripts by Themida (Only for Windows)
|
|
15
|
+
|
|
16
|
+
Support Platforms
|
|
17
|
+
-----------------
|
|
18
|
+
|
|
19
|
+
* Python 3.7~3.15
|
|
20
|
+
* Windows
|
|
21
|
+
* Many linuxs, include embedded systems
|
|
22
|
+
* Apple Intel and Apple Silicon
|
|
23
|
+
|
|
24
|
+
Quick Start
|
|
25
|
+
-----------
|
|
26
|
+
|
|
27
|
+
Install::
|
|
28
|
+
|
|
29
|
+
pip install pyarmor
|
|
30
|
+
|
|
31
|
+
Obfuscate the script `foo.py`::
|
|
32
|
+
|
|
33
|
+
pyarmor gen foo.py
|
|
34
|
+
|
|
35
|
+
This command generates an obfuscated script `dist/foo.py` like this:
|
|
36
|
+
|
|
37
|
+
.. code:: python
|
|
38
|
+
|
|
39
|
+
from pyarmor_runtime import __pyarmor__
|
|
40
|
+
__pyarmor__(__name__, __file__, b'\x28\x83\x20\x58....')
|
|
41
|
+
|
|
42
|
+
Run it::
|
|
43
|
+
|
|
44
|
+
python dist/foo.py
|
|
45
|
+
|
|
46
|
+
More Resources
|
|
47
|
+
--------------
|
|
48
|
+
|
|
49
|
+
- `Home <https://github.com/dashingsoft/pyarmor>`_
|
|
50
|
+
- `Website <http://pyarmor.dashingsoft.com>`_
|
|
51
|
+
- `中文网站 <http://pyarmor.dashingsoft.com/index-zh.html>`_
|
|
52
|
+
- `Issues <https://github.com/dashingsoft/pyarmor/issues>`_
|
|
53
|
+
- `Documentation <https://pyarmor.readthedocs.io/>`_
|
pyarmor/__init__.py
ADDED
pyarmor/benchmark.py
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
#############################################################
|
|
5
|
+
# #
|
|
6
|
+
# Copyright @ 2013 - 2017 Dashingsoft corp. #
|
|
7
|
+
# All rights reserved. #
|
|
8
|
+
# #
|
|
9
|
+
# pyarmor #
|
|
10
|
+
# #
|
|
11
|
+
# Version: 1.7.0 - #
|
|
12
|
+
# #
|
|
13
|
+
#############################################################
|
|
14
|
+
#
|
|
15
|
+
#
|
|
16
|
+
# @File: benchmark.py
|
|
17
|
+
#
|
|
18
|
+
# @Author: Jondy Zhao(jondy.zhao@gmail.com)
|
|
19
|
+
#
|
|
20
|
+
# @Create Date: 2017/11/21
|
|
21
|
+
#
|
|
22
|
+
# @Description:
|
|
23
|
+
#
|
|
24
|
+
# Check performance of pyarmor.
|
|
25
|
+
#
|
|
26
|
+
import logging
|
|
27
|
+
import os
|
|
28
|
+
import shutil
|
|
29
|
+
import sys
|
|
30
|
+
import subprocess
|
|
31
|
+
import time
|
|
32
|
+
|
|
33
|
+
from ctypes import c_int, c_void_p, py_object, pythonapi, PYFUNCTYPE
|
|
34
|
+
|
|
35
|
+
import pytransform
|
|
36
|
+
|
|
37
|
+
OBF_MODULE_MODE = 'none', 'des', 'aes'
|
|
38
|
+
OBF_CODE_MODE = 'none', 'fast', 'aes', 'wrap'
|
|
39
|
+
|
|
40
|
+
PYARMOR_PATH = os.path.dirname(__file__)
|
|
41
|
+
PYARMOR = 'pyarmor.py'
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def make_test_script(filename):
|
|
45
|
+
lines = [
|
|
46
|
+
'def empty():',
|
|
47
|
+
' return 0',
|
|
48
|
+
'',
|
|
49
|
+
'def call_1k_function(n):',
|
|
50
|
+
' for i in range(n):',
|
|
51
|
+
' one_thousand()',
|
|
52
|
+
'',
|
|
53
|
+
'def call_10k_function(n):',
|
|
54
|
+
' for i in range(n):',
|
|
55
|
+
' ten_thousand()',
|
|
56
|
+
'',
|
|
57
|
+
'def one_thousand():',
|
|
58
|
+
' if True:',
|
|
59
|
+
' i = 0',
|
|
60
|
+
]
|
|
61
|
+
lines.extend([' i += 1'] * 100)
|
|
62
|
+
lines.append('\n return 1000\n')
|
|
63
|
+
lines.extend(['def ten_thousand():',
|
|
64
|
+
' if True:',
|
|
65
|
+
' i = 0'])
|
|
66
|
+
lines.extend([' i += 1'] * 1000)
|
|
67
|
+
lines.append('\n return 10000\n')
|
|
68
|
+
|
|
69
|
+
with open(filename, 'wb') as f:
|
|
70
|
+
f.write('\n'.join(lines).encode())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def call_pyarmor(args):
|
|
74
|
+
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
75
|
+
p.wait()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def obffuscate_scripts(output, filename,
|
|
79
|
+
mod_mode, code_mode, wrap_mode, adv_mode):
|
|
80
|
+
project = os.path.join(output, 'project')
|
|
81
|
+
if os.path.exists(project):
|
|
82
|
+
shutil.rmtree(project)
|
|
83
|
+
|
|
84
|
+
args = [sys.executable, PYARMOR, 'init', '--src', output,
|
|
85
|
+
'--entry', filename, project]
|
|
86
|
+
call_pyarmor(args)
|
|
87
|
+
|
|
88
|
+
args = [sys.executable, PYARMOR, 'config',
|
|
89
|
+
'--manifest', 'include %s' % filename,
|
|
90
|
+
'--obf-mod', mod_mode,
|
|
91
|
+
'--obf-code', code_mode,
|
|
92
|
+
'--wrap-mode', wrap_mode,
|
|
93
|
+
'--advanced', adv_mode,
|
|
94
|
+
'--restrict-mode', '0',
|
|
95
|
+
'--package-runtime', '0',
|
|
96
|
+
project]
|
|
97
|
+
call_pyarmor(args)
|
|
98
|
+
|
|
99
|
+
args = [sys.executable, PYARMOR, 'build', '-B', project]
|
|
100
|
+
call_pyarmor(args)
|
|
101
|
+
|
|
102
|
+
for s in os.listdir(os.path.join(project, 'dist')):
|
|
103
|
+
shutil.copy(os.path.join(project, 'dist', s), output)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def metricmethod(func):
|
|
107
|
+
if not hasattr(time, 'process_time'):
|
|
108
|
+
time.process_time = time.clock
|
|
109
|
+
|
|
110
|
+
def wrap(*args, **kwargs):
|
|
111
|
+
t1 = time.process_time()
|
|
112
|
+
result = func(*args, **kwargs)
|
|
113
|
+
t2 = time.process_time()
|
|
114
|
+
logging.info('%-50s: %10.6f ms', func.__name__, (t2 - t1) * 1000)
|
|
115
|
+
return result
|
|
116
|
+
return wrap
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@metricmethod
|
|
120
|
+
def verify_license(m):
|
|
121
|
+
try:
|
|
122
|
+
prototype = PYFUNCTYPE(py_object)
|
|
123
|
+
dlfunc = prototype(('get_registration_code', m))
|
|
124
|
+
code = dlfunc()
|
|
125
|
+
except Exception:
|
|
126
|
+
logging.warning('Verify license failed')
|
|
127
|
+
code = ''
|
|
128
|
+
return code
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@metricmethod
|
|
132
|
+
def init_pytransform(m):
|
|
133
|
+
major, minor = sys.version_info[0:2]
|
|
134
|
+
# Python2.5 no sys.maxsize but sys.maxint
|
|
135
|
+
# bitness = 64 if sys.maxsize > 2**32 else 32
|
|
136
|
+
prototype = PYFUNCTYPE(c_int, c_int, c_int, c_void_p)
|
|
137
|
+
init_module = prototype(('init_module', m))
|
|
138
|
+
init_module(major, minor, pythonapi._handle)
|
|
139
|
+
|
|
140
|
+
prototype = PYFUNCTYPE(c_int, c_int, c_int, c_int)
|
|
141
|
+
init_runtime = prototype(('init_runtime', m))
|
|
142
|
+
init_runtime(0, 0, 0, 0)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@metricmethod
|
|
146
|
+
def load_pytransform():
|
|
147
|
+
return pytransform._load_library(PYARMOR_PATH, is_runtime=1)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@metricmethod
|
|
151
|
+
def total_extra_init_time():
|
|
152
|
+
m = load_pytransform()
|
|
153
|
+
init_pytransform(m)
|
|
154
|
+
verify_license(m)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@metricmethod
|
|
158
|
+
def import_first_no_obfuscated_module(name):
|
|
159
|
+
return __import__(name)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@metricmethod
|
|
163
|
+
def import_first_obfuscated_module(name):
|
|
164
|
+
return __import__(name)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@metricmethod
|
|
168
|
+
def re_import_no_obfuscated_module(name):
|
|
169
|
+
return __import__(name)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@metricmethod
|
|
173
|
+
def re_import_obfuscated_module(name):
|
|
174
|
+
return __import__(name)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@metricmethod
|
|
178
|
+
def run_empty_obfuscated_code_object(foo):
|
|
179
|
+
return foo.empty()
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@metricmethod
|
|
183
|
+
def run_obfuscated_1k_bytecode(foo):
|
|
184
|
+
return foo.one_thousand()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@metricmethod
|
|
188
|
+
def run_obfuscated_10k_bytecode(foo):
|
|
189
|
+
return foo.ten_thousand()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@metricmethod
|
|
193
|
+
def run_empty_no_obfuscated_code_object(foo):
|
|
194
|
+
return foo.empty()
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@metricmethod
|
|
198
|
+
def run_no_obfuscated_1k_bytecode(foo):
|
|
199
|
+
return foo.one_thousand()
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@metricmethod
|
|
203
|
+
def run_no_obfuscated_10k_bytecode(foo):
|
|
204
|
+
return foo.ten_thousand()
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@metricmethod
|
|
208
|
+
def import_many_obfuscated_modules(name, n=100):
|
|
209
|
+
for i in range(n):
|
|
210
|
+
__import__(name % i)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@metricmethod
|
|
214
|
+
def import_many_no_obfuscated_modules(name, n=100):
|
|
215
|
+
for i in range(n):
|
|
216
|
+
__import__(name % i)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@metricmethod
|
|
220
|
+
def call_1000_no_obfuscated_1k_bytecode(foo):
|
|
221
|
+
return foo.call_1k_function(1000)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
@metricmethod
|
|
225
|
+
def call_1000_obfuscated_1k_bytecode(foo):
|
|
226
|
+
return foo.call_1k_function(1000)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@metricmethod
|
|
230
|
+
def call_1000_no_obfuscated_10k_bytecode(foo):
|
|
231
|
+
return foo.call_10k_function(1000)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@metricmethod
|
|
235
|
+
def call_1000_obfuscated_10k_bytecode(foo):
|
|
236
|
+
return foo.call_10k_function(1000)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@metricmethod
|
|
240
|
+
def call_10000_no_obfuscated_1k_bytecode(foo):
|
|
241
|
+
return foo.call_1k_function(10000)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
@metricmethod
|
|
245
|
+
def call_10000_obfuscated_1k_bytecode(foo):
|
|
246
|
+
return foo.call_1k_function(10000)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
@metricmethod
|
|
250
|
+
def call_10000_no_obfuscated_10k_bytecode(foo):
|
|
251
|
+
return foo.call_10k_function(10000)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@metricmethod
|
|
255
|
+
def call_10000_obfuscated_10k_bytecode(foo):
|
|
256
|
+
return foo.call_10k_function(10000)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def main():
|
|
260
|
+
if not os.path.exists('benchmark.py'):
|
|
261
|
+
logging.warning('Please change current path to %s', PYARMOR_PATH)
|
|
262
|
+
return
|
|
263
|
+
|
|
264
|
+
output = '.benchtest'
|
|
265
|
+
name = 'bfoo'
|
|
266
|
+
filename = os.path.join(output, name + '.py')
|
|
267
|
+
|
|
268
|
+
obname = 'obfoo'
|
|
269
|
+
obfilename = os.path.join(output, obname + '.py')
|
|
270
|
+
|
|
271
|
+
if len(sys.argv) > 1 and 'bootstrap'.startswith(sys.argv[1]):
|
|
272
|
+
if len(sys.argv) < 6:
|
|
273
|
+
sys.argv.extend(['1', '1', '1', '0'])
|
|
274
|
+
obf_mod, obf_code, wrap_mode, adv_mode = sys.argv[2:6]
|
|
275
|
+
|
|
276
|
+
if os.path.exists(output) and output.endswith('.benchtest'):
|
|
277
|
+
logging.info('Clean output path: %s', output)
|
|
278
|
+
shutil.rmtree(output)
|
|
279
|
+
logging.info('Create output path: %s', output)
|
|
280
|
+
os.makedirs(output)
|
|
281
|
+
|
|
282
|
+
logging.info('Generate test script %s ...', filename)
|
|
283
|
+
make_test_script(filename)
|
|
284
|
+
|
|
285
|
+
logging.info('Obffuscate test script ...')
|
|
286
|
+
shutil.copy(filename, obfilename)
|
|
287
|
+
obffuscate_scripts(output, os.path.basename(obfilename),
|
|
288
|
+
obf_mod, obf_code, wrap_mode, adv_mode)
|
|
289
|
+
if not os.path.exists(obfilename):
|
|
290
|
+
logging.info('Something is wrong to obsfucate the script')
|
|
291
|
+
return
|
|
292
|
+
logging.info('Generate obffuscated script %s', obfilename)
|
|
293
|
+
|
|
294
|
+
logging.info('Copy benchmark.py to %s', output)
|
|
295
|
+
shutil.copy('benchmark.py', output)
|
|
296
|
+
|
|
297
|
+
logging.info('')
|
|
298
|
+
logging.info('Now change to "%s"', output)
|
|
299
|
+
logging.info('Run "%s benchmark.py".', sys.executable)
|
|
300
|
+
return
|
|
301
|
+
|
|
302
|
+
filename = os.path.basename(filename)
|
|
303
|
+
if os.path.exists(filename):
|
|
304
|
+
logging.info('Test script: %s', filename)
|
|
305
|
+
else:
|
|
306
|
+
logging.warning('Test script: %s not found', filename)
|
|
307
|
+
logging.info('Run "%s benchmark.py bootstrap" first.', sys.executable)
|
|
308
|
+
return
|
|
309
|
+
|
|
310
|
+
obfilename = os.path.basename(obfilename)
|
|
311
|
+
if os.path.exists(obfilename):
|
|
312
|
+
logging.info('Obfuscated script: %s', obfilename)
|
|
313
|
+
else:
|
|
314
|
+
logging.warning('Obfuscated script: %s not found', obfilename)
|
|
315
|
+
logging.info('Run "%s benchmark.py bootstrap" first.', sys.executable)
|
|
316
|
+
return
|
|
317
|
+
|
|
318
|
+
logging.info('--------------------------------------')
|
|
319
|
+
|
|
320
|
+
# It doens't work for super mode
|
|
321
|
+
# logging.info('')
|
|
322
|
+
# total_extra_init_time()
|
|
323
|
+
|
|
324
|
+
logging.info('')
|
|
325
|
+
foo = import_first_no_obfuscated_module(name)
|
|
326
|
+
obfoo = import_first_obfuscated_module(obname)
|
|
327
|
+
|
|
328
|
+
logging.info('')
|
|
329
|
+
foo = re_import_no_obfuscated_module(name)
|
|
330
|
+
obfoo = re_import_obfuscated_module(obname)
|
|
331
|
+
|
|
332
|
+
logging.info('')
|
|
333
|
+
n = 10
|
|
334
|
+
logging.info('--- Import %d modules ---', n)
|
|
335
|
+
for i in range(n):
|
|
336
|
+
shutil.copy(filename, filename.replace('.py', '_%s.py' % i))
|
|
337
|
+
with open(obfilename) as f:
|
|
338
|
+
lines = f.readlines()
|
|
339
|
+
with open(obfilename.replace('.py', '_%s.py' % i), 'w') as f:
|
|
340
|
+
f.write(lines[2] if lines[0].find('pyarmor_runtime') > 0 \
|
|
341
|
+
else ''.join(lines))
|
|
342
|
+
import_many_no_obfuscated_modules('bfoo_%s', n)
|
|
343
|
+
import_many_obfuscated_modules('obfoo_%s', n)
|
|
344
|
+
|
|
345
|
+
logging.info('')
|
|
346
|
+
run_empty_no_obfuscated_code_object(foo)
|
|
347
|
+
run_empty_obfuscated_code_object(obfoo)
|
|
348
|
+
|
|
349
|
+
logging.info('')
|
|
350
|
+
run_no_obfuscated_1k_bytecode(foo)
|
|
351
|
+
run_obfuscated_1k_bytecode(obfoo)
|
|
352
|
+
|
|
353
|
+
logging.info('')
|
|
354
|
+
run_no_obfuscated_10k_bytecode(foo)
|
|
355
|
+
run_obfuscated_10k_bytecode(obfoo)
|
|
356
|
+
|
|
357
|
+
logging.info('')
|
|
358
|
+
call_1000_no_obfuscated_1k_bytecode(foo)
|
|
359
|
+
call_1000_obfuscated_1k_bytecode(obfoo)
|
|
360
|
+
|
|
361
|
+
logging.info('')
|
|
362
|
+
call_1000_no_obfuscated_10k_bytecode(foo)
|
|
363
|
+
call_1000_obfuscated_10k_bytecode(obfoo)
|
|
364
|
+
|
|
365
|
+
logging.info('')
|
|
366
|
+
call_10000_no_obfuscated_1k_bytecode(foo)
|
|
367
|
+
call_10000_obfuscated_1k_bytecode(obfoo)
|
|
368
|
+
|
|
369
|
+
logging.info('')
|
|
370
|
+
call_10000_no_obfuscated_10k_bytecode(foo)
|
|
371
|
+
call_10000_obfuscated_10k_bytecode(obfoo)
|
|
372
|
+
|
|
373
|
+
logging.info('')
|
|
374
|
+
logging.info('--------------------------------------')
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
if __name__ == '__main__':
|
|
378
|
+
logging.basicConfig(
|
|
379
|
+
level=logging.INFO,
|
|
380
|
+
format='%(message)s',
|
|
381
|
+
)
|
|
382
|
+
main()
|
pyarmor/build_meta.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""A PEP 517 interface to building pyarmored wheel based on setuptools
|
|
2
|
+
|
|
3
|
+
Here is an example package
|
|
4
|
+
|
|
5
|
+
mypkg/
|
|
6
|
+
pyproject.toml
|
|
7
|
+
setup.py
|
|
8
|
+
src/
|
|
9
|
+
__init__.py
|
|
10
|
+
...
|
|
11
|
+
|
|
12
|
+
The content of minimum build file "pyproject.toml"
|
|
13
|
+
|
|
14
|
+
[build-system]
|
|
15
|
+
requires = ["setuptools", "wheel", "pyarmor>=7.2.0"]
|
|
16
|
+
build-backend = "pyarmor.build_meta"
|
|
17
|
+
|
|
18
|
+
Now build a pyarmored wheel by pip
|
|
19
|
+
|
|
20
|
+
cd mypkg/
|
|
21
|
+
pip wheel .
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Again, this is not a formal definition! Just a "taste" of the module.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import os
|
|
28
|
+
import shutil
|
|
29
|
+
import sys
|
|
30
|
+
|
|
31
|
+
from wheel.wheelfile import WheelFile
|
|
32
|
+
from wheel.cli.pack import pack as wheel_pack
|
|
33
|
+
from pyarmor.pyarmor import main as pyarmor_main
|
|
34
|
+
|
|
35
|
+
from setuptools.build_meta import build_wheel as setuptools_build_wheel
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
from distutils.util import get_platform
|
|
39
|
+
except ModuleNotFoundError:
|
|
40
|
+
from polyfills import get_platform
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _wheel_unpack(path, dest='.'):
|
|
44
|
+
with WheelFile(path) as wf:
|
|
45
|
+
namever = wf.parsed_filename.group('namever')
|
|
46
|
+
destination = os.path.join(dest, namever)
|
|
47
|
+
sys.stdout.flush()
|
|
48
|
+
wf.extractall(destination)
|
|
49
|
+
return namever
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _wheel_append_runtime_files(build_path, namever, pkgname):
|
|
53
|
+
namelist = []
|
|
54
|
+
for name in os.listdir(os.path.join(build_path, pkgname)):
|
|
55
|
+
if name.startswith('pytransform'):
|
|
56
|
+
path = os.path.join(build_path, pkgname, name)
|
|
57
|
+
n = len(path) + 1
|
|
58
|
+
if os.path.isdir(path):
|
|
59
|
+
for root, dirs, files in os.walk(path):
|
|
60
|
+
prefix = root[n:].replace('\\', '/')
|
|
61
|
+
for x in files:
|
|
62
|
+
namelist.append(prefix + '/' + x)
|
|
63
|
+
else:
|
|
64
|
+
namelist.append(name)
|
|
65
|
+
|
|
66
|
+
wheel_record = os.path.join(build_path, namever + '.dist-info', 'RECORD')
|
|
67
|
+
with open(wheel_record, 'a') as f:
|
|
68
|
+
for name in namelist:
|
|
69
|
+
f.write(pkgname + '/' + name + ',,\n')
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _fix_config(config_settings, obf_options):
|
|
73
|
+
from pip._internal.configuration import Configuration, ConfigurationError
|
|
74
|
+
config = Configuration(False)
|
|
75
|
+
config.load()
|
|
76
|
+
for k, v in reversed(config.items()):
|
|
77
|
+
if k in ('pyarmor.advanced', ':env:.pyarmor-advanced'):
|
|
78
|
+
if v not in ('2', '3', '4', '5'):
|
|
79
|
+
raise ConfigurationError('Invalid pyarmor.advanced')
|
|
80
|
+
obf_options.extend(['--advanced', v])
|
|
81
|
+
break
|
|
82
|
+
|
|
83
|
+
config_settings = config_settings or {}
|
|
84
|
+
global_options = config_settings.get('--global-option', [])
|
|
85
|
+
|
|
86
|
+
plat_name = get_platform().replace('-', '_').replace('.', '_')
|
|
87
|
+
global_options.append('--plat-name=%s' % plat_name)
|
|
88
|
+
|
|
89
|
+
global_options.append('--python-tag=cp%s%s' % sys.version_info[:2])
|
|
90
|
+
# global_options.append('--py-limited-api=cp%s%s' % sys.version_info[:2])
|
|
91
|
+
|
|
92
|
+
config_settings['--global-option'] = global_options
|
|
93
|
+
return config_settings
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def build_wheel(wheel_directory, config_settings=None,
|
|
97
|
+
metadata_directory=None):
|
|
98
|
+
obf_options = ['obfuscate', '--enable-suffix', '--in-place',
|
|
99
|
+
'-r', '--bootstrap', '3']
|
|
100
|
+
config_settings = _fix_config(config_settings, obf_options)
|
|
101
|
+
|
|
102
|
+
# Build wheel by setuptools
|
|
103
|
+
result_basename = setuptools_build_wheel(
|
|
104
|
+
wheel_directory,
|
|
105
|
+
config_settings=config_settings,
|
|
106
|
+
metadata_directory=metadata_directory
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Unpack wheel and replace the original .py with obfuscated ones
|
|
110
|
+
result_wheel = os.path.join(wheel_directory, result_basename)
|
|
111
|
+
namever = _wheel_unpack(result_wheel, wheel_directory)
|
|
112
|
+
|
|
113
|
+
pkgname = namever.split('-')[0]
|
|
114
|
+
build_path = os.path.join(wheel_directory, namever)
|
|
115
|
+
|
|
116
|
+
obf_options.append(os.path.join(build_path, pkgname, '__init__.py'))
|
|
117
|
+
pyarmor_main(obf_options)
|
|
118
|
+
|
|
119
|
+
# Append runtime files of obfuscated scripts to wheel
|
|
120
|
+
_wheel_append_runtime_files(build_path, namever, pkgname)
|
|
121
|
+
|
|
122
|
+
# Pack the patched wheel again
|
|
123
|
+
wheel_pack(build_path, wheel_directory, None)
|
|
124
|
+
|
|
125
|
+
shutil.rmtree(build_path)
|
|
126
|
+
return result_basename
|
pyarmor/cli/__init__.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
__VERSION__ = '9.2.6'
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger('cli')
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CliError(Exception):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def resoptions(meth):
|
|
13
|
+
|
|
14
|
+
def process(self, res, *args, **kwargs):
|
|
15
|
+
self._options = self.ctx.get_res_options(res.fullname, self._Catalog)
|
|
16
|
+
return meth(self, res, *args, **kwargs)
|
|
17
|
+
|
|
18
|
+
return process
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Component(object):
|
|
22
|
+
|
|
23
|
+
def __init__(self, ctx):
|
|
24
|
+
self.ctx = ctx
|
|
25
|
+
self._options = {}
|
|
26
|
+
|
|
27
|
+
self.logger = logging.getLogger(self.LOGNAME)
|
|
28
|
+
|
|
29
|
+
def __getattr__(self, opt):
|
|
30
|
+
if opt.startswith('o_'):
|
|
31
|
+
return self._options.get(opt[2:], '')
|
|
32
|
+
elif opt.startswith('oi_'):
|
|
33
|
+
return int(self._options.get(opt[3:]))
|
|
34
|
+
elif opt.startswith('ob_'):
|
|
35
|
+
v = self._options.get(opt[3:], '')
|
|
36
|
+
if isinstance(v, str):
|
|
37
|
+
if v.isdigit():
|
|
38
|
+
return bool(int(v))
|
|
39
|
+
return v.lower() in ('1', 'true', 'on', 'yes')
|
|
40
|
+
|
|
41
|
+
return v
|
|
42
|
+
return AttributeError(opt)
|
|
43
|
+
|
|
44
|
+
def trace(self, res, node, value):
|
|
45
|
+
lineno = getattr(node, 'lineno', -1)
|
|
46
|
+
self.logger.info('%s:%s:%s', res.fullname, lineno, value)
|