AutoCython-zhang 2.3.5__tar.gz → 2.3.7__tar.gz
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.
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython/_version.py +1 -1
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython/obfuscate.py +194 -82
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython_zhang.egg-info/PKG-INFO +5 -5
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython_zhang.egg-info/top_level.txt +0 -1
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/PKG-INFO +5 -5
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/README.md +4 -4
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/pyproject.toml +1 -1
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython/AutoCython.py +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython/__init__.py +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython/compile.py +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython/run_tasks.py +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython/tools.py +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython_zhang.egg-info/SOURCES.txt +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython_zhang.egg-info/dependency_links.txt +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython_zhang.egg-info/entry_points.txt +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython_zhang.egg-info/requires.txt +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/LICENSE +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/MANIFEST.in +0 -0
- {autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/setup.cfg +0 -0
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
"""AST 混淆模块:去 docstring
|
|
1
|
+
"""AST 混淆模块:去 docstring、局部变量重命名、字符串加密、常量折叠、控制流平坦化、虚假分支。
|
|
2
|
+
|
|
3
|
+
注解(annotation)默认完整保留,以兼容 FastAPI/Pydantic/dataclass/attrs 等依赖运行时
|
|
4
|
+
``__annotations__`` 的框架;字符串与常量混淆会跳过 annotation 子树。
|
|
5
|
+
"""
|
|
2
6
|
import ast
|
|
3
7
|
import copy
|
|
4
8
|
import hashlib
|
|
@@ -6,6 +10,16 @@ import random
|
|
|
6
10
|
|
|
7
11
|
_UNSAFE_CALLS = frozenset({'globals', 'locals', 'eval', 'exec', 'vars'})
|
|
8
12
|
_PATTERN_SKIP_ATTR = '_autocython_skip_literal_obf'
|
|
13
|
+
_SCOPE_BOUNDARY_NODES = (
|
|
14
|
+
ast.FunctionDef,
|
|
15
|
+
ast.AsyncFunctionDef,
|
|
16
|
+
ast.ClassDef,
|
|
17
|
+
ast.Lambda,
|
|
18
|
+
ast.ListComp,
|
|
19
|
+
ast.SetComp,
|
|
20
|
+
ast.DictComp,
|
|
21
|
+
ast.GeneratorExp,
|
|
22
|
+
)
|
|
9
23
|
|
|
10
24
|
|
|
11
25
|
def _has_unsafe_call(node):
|
|
@@ -21,14 +35,18 @@ def _has_unsafe_call(node):
|
|
|
21
35
|
|
|
22
36
|
|
|
23
37
|
def _walk_no_nested_scope(body):
|
|
24
|
-
"""遍历 body
|
|
38
|
+
"""遍历 body 中的节点,不穿透嵌套词法作用域。
|
|
39
|
+
|
|
40
|
+
Python 3 中 lambda 与各类 comprehension 也会创建独立词法作用域。
|
|
41
|
+
局部变量重命名若穿透这些节点,容易把 ``lambda e: ...`` 的参数
|
|
42
|
+
与外层 ``for e in ...`` 的重命名混在一起,生成
|
|
43
|
+
``free variable ... referenced before assignment`` 一类运行时错误。
|
|
44
|
+
"""
|
|
25
45
|
for node in body:
|
|
26
46
|
yield node
|
|
27
|
-
if isinstance(node,
|
|
47
|
+
if isinstance(node, _SCOPE_BOUNDARY_NODES):
|
|
28
48
|
continue
|
|
29
49
|
for child in ast.iter_child_nodes(node):
|
|
30
|
-
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
|
|
31
|
-
continue
|
|
32
50
|
yield from _walk_no_nested_scope([child])
|
|
33
51
|
|
|
34
52
|
|
|
@@ -49,6 +67,34 @@ def _mark_pattern_constants(pattern):
|
|
|
49
67
|
setattr(child, _PATTERN_SKIP_ATTR, True)
|
|
50
68
|
|
|
51
69
|
|
|
70
|
+
def _mark_annotation_constants(tree):
|
|
71
|
+
"""标记 annotation 子树内常量,避免字符串加密/常量折叠改变运行时注解语义。"""
|
|
72
|
+
|
|
73
|
+
def mark(node):
|
|
74
|
+
if node is None:
|
|
75
|
+
return
|
|
76
|
+
for child in ast.walk(node):
|
|
77
|
+
if isinstance(child, ast.Constant):
|
|
78
|
+
setattr(child, _PATTERN_SKIP_ATTR, True)
|
|
79
|
+
|
|
80
|
+
def mark_arg_annotations(args):
|
|
81
|
+
all_args = args.posonlyargs + args.args + args.kwonlyargs
|
|
82
|
+
if args.vararg:
|
|
83
|
+
all_args.append(args.vararg)
|
|
84
|
+
if args.kwarg:
|
|
85
|
+
all_args.append(args.kwarg)
|
|
86
|
+
for arg in all_args:
|
|
87
|
+
mark(arg.annotation)
|
|
88
|
+
|
|
89
|
+
for node in ast.walk(tree):
|
|
90
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
91
|
+
mark_arg_annotations(node.args)
|
|
92
|
+
mark(node.returns)
|
|
93
|
+
elif isinstance(node, ast.AnnAssign):
|
|
94
|
+
mark(node.annotation)
|
|
95
|
+
return tree
|
|
96
|
+
|
|
97
|
+
|
|
52
98
|
class _DocstringRemover(ast.NodeTransformer):
|
|
53
99
|
"""移除 module/class/function 首部的 docstring"""
|
|
54
100
|
|
|
@@ -74,80 +120,151 @@ class _DocstringRemover(ast.NodeTransformer):
|
|
|
74
120
|
return self._strip_docstring(node)
|
|
75
121
|
|
|
76
122
|
|
|
77
|
-
|
|
78
|
-
"""
|
|
79
|
-
|
|
80
|
-
|
|
123
|
+
def _collect_names(nodes, ctx_type, *, skip_nested=True):
|
|
124
|
+
"""收集一组节点中的 Name;默认不穿透新的词法作用域。"""
|
|
125
|
+
names = set()
|
|
126
|
+
walker = _walk_no_nested_scope(nodes) if skip_nested else ast.walk(ast.Module(body=list(nodes), type_ignores=[]))
|
|
127
|
+
for child in walker:
|
|
128
|
+
if isinstance(child, ast.Name) and isinstance(child.ctx, ctx_type):
|
|
129
|
+
names.add(child.id)
|
|
130
|
+
return names
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _collect_argument_names(args):
|
|
134
|
+
"""收集函数/lambda 参数名。"""
|
|
135
|
+
names = set()
|
|
136
|
+
for arg in args.args + args.posonlyargs + args.kwonlyargs:
|
|
137
|
+
names.add(arg.arg)
|
|
138
|
+
if args.vararg:
|
|
139
|
+
names.add(args.vararg.arg)
|
|
140
|
+
if args.kwarg:
|
|
141
|
+
names.add(args.kwarg.arg)
|
|
142
|
+
return names
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _collect_argument_expression_nodes(args):
|
|
146
|
+
"""收集默认值与注解表达式,它们在外层作用域求值。"""
|
|
147
|
+
nodes = []
|
|
148
|
+
nodes.extend(args.defaults)
|
|
149
|
+
nodes.extend(default for default in args.kw_defaults if default is not None)
|
|
150
|
+
all_args = args.posonlyargs + args.args + args.kwonlyargs
|
|
151
|
+
if args.vararg:
|
|
152
|
+
all_args.append(args.vararg)
|
|
153
|
+
if args.kwarg:
|
|
154
|
+
all_args.append(args.kwarg)
|
|
155
|
+
for arg in all_args:
|
|
156
|
+
if arg.annotation is not None:
|
|
157
|
+
nodes.append(arg.annotation)
|
|
158
|
+
return nodes
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _collect_nonlocal_global_names(body):
|
|
162
|
+
"""收集当前作用域直接声明的 nonlocal/global 名称。"""
|
|
163
|
+
nonlocal_names = set()
|
|
164
|
+
global_names = set()
|
|
165
|
+
for child in _walk_no_nested_scope(body):
|
|
166
|
+
if isinstance(child, ast.Nonlocal):
|
|
167
|
+
nonlocal_names.update(child.names)
|
|
168
|
+
elif isinstance(child, ast.Global):
|
|
169
|
+
global_names.update(child.names)
|
|
170
|
+
return nonlocal_names, global_names
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _collect_direct_bound_names(body):
|
|
174
|
+
"""收集当前作用域直接绑定的名称,不穿透嵌套作用域。"""
|
|
175
|
+
bound = _collect_names(body, ast.Store)
|
|
176
|
+
for child in _walk_no_nested_scope(body):
|
|
177
|
+
if isinstance(child, ast.ExceptHandler) and child.name:
|
|
178
|
+
bound.add(child.name)
|
|
179
|
+
elif isinstance(child, (ast.Import, ast.ImportFrom)):
|
|
180
|
+
for alias in child.names:
|
|
181
|
+
bound.add(alias.asname or alias.name.split('.', 1)[0])
|
|
182
|
+
return bound
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _collect_load_names_no_nested(nodes):
|
|
186
|
+
"""收集 Load 名称,不穿透嵌套作用域。"""
|
|
187
|
+
return _collect_names(nodes, ast.Load)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _collect_nested_scope_nodes(body):
|
|
191
|
+
"""收集 body 中的直接/间接嵌套词法作用域节点。"""
|
|
192
|
+
nested = []
|
|
193
|
+
for node in body:
|
|
194
|
+
if isinstance(node, _SCOPE_BOUNDARY_NODES):
|
|
195
|
+
nested.append(node)
|
|
196
|
+
continue
|
|
197
|
+
for child in ast.iter_child_nodes(node):
|
|
198
|
+
if isinstance(child, _SCOPE_BOUNDARY_NODES):
|
|
199
|
+
nested.append(child)
|
|
200
|
+
else:
|
|
201
|
+
nested.extend(_collect_nested_scope_nodes([child]))
|
|
202
|
+
return nested
|
|
81
203
|
|
|
82
|
-
def __init__(self):
|
|
83
|
-
self._scope_stack = ['module']
|
|
84
204
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
205
|
+
def _collect_function_like_free_refs(node, local_names):
|
|
206
|
+
"""收集嵌套函数/lambda 中引用的外层变量名。"""
|
|
207
|
+
body = node.body if isinstance(node.body, list) else [node.body]
|
|
208
|
+
param_names = _collect_argument_names(node.args)
|
|
209
|
+
nonlocal_names, global_names = _collect_nonlocal_global_names(body)
|
|
210
|
+
nested_locals = _collect_direct_bound_names(body)
|
|
211
|
+
nested_locals.update(param_names)
|
|
212
|
+
nested_locals -= nonlocal_names
|
|
90
213
|
|
|
91
|
-
|
|
214
|
+
free = set()
|
|
215
|
+
outer_expr_nodes = _collect_argument_expression_nodes(node.args)
|
|
216
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
217
|
+
outer_expr_nodes.extend(node.decorator_list)
|
|
218
|
+
if node.returns is not None:
|
|
219
|
+
outer_expr_nodes.append(node.returns)
|
|
220
|
+
free.update(_collect_load_names_no_nested(outer_expr_nodes) & local_names)
|
|
221
|
+
|
|
222
|
+
for name in _collect_load_names_no_nested(body):
|
|
223
|
+
if name in local_names and name not in nested_locals and name not in global_names:
|
|
224
|
+
free.add(name)
|
|
225
|
+
|
|
226
|
+
free.update(_collect_nested_free_refs(body, local_names))
|
|
227
|
+
return free
|
|
92
228
|
|
|
93
|
-
def visit_ClassDef(self, node):
|
|
94
|
-
self._scope_stack.append('class')
|
|
95
|
-
self.generic_visit(node)
|
|
96
|
-
self._scope_stack.pop()
|
|
97
|
-
if not node.body:
|
|
98
|
-
node.body.append(ast.Pass())
|
|
99
|
-
return node
|
|
100
229
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
230
|
+
def _collect_class_free_refs(node, local_names):
|
|
231
|
+
"""收集嵌套类体中直接引用的外层变量名。"""
|
|
232
|
+
free = set()
|
|
233
|
+
outer_expr_nodes = list(node.decorator_list)
|
|
234
|
+
outer_expr_nodes.extend(node.bases)
|
|
235
|
+
outer_expr_nodes.extend(keyword.value for keyword in node.keywords)
|
|
236
|
+
free.update(_collect_load_names_no_nested(outer_expr_nodes) & local_names)
|
|
237
|
+
|
|
238
|
+
for name in _collect_load_names_no_nested(node.body):
|
|
239
|
+
if name in local_names:
|
|
240
|
+
free.add(name)
|
|
241
|
+
free.update(_collect_nested_free_refs(node.body, local_names))
|
|
242
|
+
return free
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _collect_comprehension_free_refs(node, local_names):
|
|
246
|
+
"""保守收集 comprehension 中对外层变量的引用。
|
|
247
|
+
|
|
248
|
+
comprehension 是隐式函数作用域;为避免 Cython/CPython 闭包细节差异,
|
|
249
|
+
只要其中出现外层局部名,就将该外层名排除出重命名集合。
|
|
250
|
+
"""
|
|
251
|
+
free = set()
|
|
252
|
+
for child in ast.walk(node):
|
|
253
|
+
if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Load) and child.id in local_names:
|
|
254
|
+
free.add(child.id)
|
|
255
|
+
return free
|
|
110
256
|
|
|
111
257
|
|
|
112
258
|
def _collect_nested_free_refs(body, local_names):
|
|
113
|
-
"""
|
|
259
|
+
"""收集嵌套词法作用域中引用的外层变量名(闭包变量)"""
|
|
114
260
|
free = set()
|
|
115
|
-
for node in body:
|
|
116
|
-
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
117
|
-
|
|
118
|
-
nested_locals = set()
|
|
119
|
-
# nonlocal/global 声明的变量不是局部变量
|
|
120
|
-
nonlocal_names = set()
|
|
121
|
-
for child in _walk_no_nested_scope(node.body):
|
|
122
|
-
if isinstance(child, (ast.Nonlocal, ast.Global)):
|
|
123
|
-
nonlocal_names.update(child.names)
|
|
124
|
-
for arg in node.args.args + node.args.posonlyargs + node.args.kwonlyargs:
|
|
125
|
-
nested_locals.add(arg.arg)
|
|
126
|
-
if node.args.vararg:
|
|
127
|
-
nested_locals.add(node.args.vararg.arg)
|
|
128
|
-
if node.args.kwarg:
|
|
129
|
-
nested_locals.add(node.args.kwarg.arg)
|
|
130
|
-
for child in _walk_no_nested_scope(node.body):
|
|
131
|
-
if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Store):
|
|
132
|
-
if child.id not in nonlocal_names:
|
|
133
|
-
nested_locals.add(child.id)
|
|
134
|
-
# 嵌套函数中读取的、属于外层 local_names 且不被自身遮蔽的名字
|
|
135
|
-
for child in ast.walk(node):
|
|
136
|
-
if isinstance(child, ast.Name) and child.id in local_names and child.id not in nested_locals:
|
|
137
|
-
free.add(child.id)
|
|
261
|
+
for node in _collect_nested_scope_nodes(body):
|
|
262
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda)):
|
|
263
|
+
free.update(_collect_function_like_free_refs(node, local_names))
|
|
138
264
|
elif isinstance(node, ast.ClassDef):
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
free.add(child.id)
|
|
143
|
-
free |= _collect_nested_free_refs(node.body, local_names)
|
|
144
|
-
else:
|
|
145
|
-
# 递归搜索所有子节点中的嵌套函数/类(穿透 Try/With/For/If 等)
|
|
146
|
-
for child in ast.walk(node):
|
|
147
|
-
if child is node:
|
|
148
|
-
continue
|
|
149
|
-
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
|
|
150
|
-
free |= _collect_nested_free_refs([child], local_names)
|
|
265
|
+
free.update(_collect_class_free_refs(node, local_names))
|
|
266
|
+
elif isinstance(node, (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp)):
|
|
267
|
+
free.update(_collect_comprehension_free_refs(node, local_names))
|
|
151
268
|
return free
|
|
152
269
|
|
|
153
270
|
|
|
@@ -167,26 +284,20 @@ class _LocalVarRenamer(ast.NodeTransformer):
|
|
|
167
284
|
|
|
168
285
|
# 收集参数名(不重命名)
|
|
169
286
|
param_names = set()
|
|
170
|
-
|
|
171
|
-
param_names.add(arg.arg)
|
|
172
|
-
if node.args.vararg:
|
|
173
|
-
param_names.add(node.args.vararg.arg)
|
|
174
|
-
if node.args.kwarg:
|
|
175
|
-
param_names.add(node.args.kwarg.arg)
|
|
287
|
+
param_names.update(_collect_argument_names(node.args))
|
|
176
288
|
|
|
177
289
|
# 收集局部赋值目标(不穿透嵌套作用域)
|
|
178
290
|
local_names = set()
|
|
179
291
|
# 排除 nonlocal/global 声明的变量
|
|
180
|
-
nonlocal_names =
|
|
292
|
+
nonlocal_names, global_names = _collect_nonlocal_global_names(node.body)
|
|
293
|
+
excluded_scope_names = nonlocal_names | global_names
|
|
181
294
|
for child in _walk_no_nested_scope(node.body):
|
|
182
|
-
if isinstance(child, (ast.Nonlocal, ast.Global)):
|
|
183
|
-
nonlocal_names.update(child.names)
|
|
184
295
|
if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Store):
|
|
185
296
|
name = child.id
|
|
186
|
-
if (name not in param_names and name
|
|
297
|
+
if (name not in param_names and name not in excluded_scope_names
|
|
298
|
+
and name != 'self' and name != 'cls'
|
|
187
299
|
and not name.startswith('__')):
|
|
188
300
|
local_names.add(name)
|
|
189
|
-
local_names -= nonlocal_names
|
|
190
301
|
|
|
191
302
|
if not local_names:
|
|
192
303
|
self.generic_visit(node)
|
|
@@ -482,8 +593,9 @@ class _OpaquePredicateInserter(ast.NodeTransformer):
|
|
|
482
593
|
|
|
483
594
|
|
|
484
595
|
def obfuscate_source(source_code: str, seed=None) -> str:
|
|
485
|
-
"""
|
|
596
|
+
"""对源码执行六重 AST 变换:去 docstring、局部变量重命名、
|
|
486
597
|
字符串加密、常量折叠、控制流平坦化、虚假分支。
|
|
598
|
+
函数、类和局部变量 annotation 默认保留。
|
|
487
599
|
ast.unparse() 天然丢弃所有注释。
|
|
488
600
|
|
|
489
601
|
:param seed: 随机种子;传入后可复现混淆结果
|
|
@@ -493,10 +605,10 @@ def obfuscate_source(source_code: str, seed=None) -> str:
|
|
|
493
605
|
rng = random.Random(seed) if seed is not None else random
|
|
494
606
|
tree = ast.parse(source_code)
|
|
495
607
|
tree = _DocstringRemover().visit(tree)
|
|
496
|
-
tree = _AnnotationRemover().visit(tree)
|
|
497
608
|
tree = _LocalVarRenamer().visit(tree)
|
|
498
609
|
tree = _ControlFlowFlattener(rng=rng).visit(tree)
|
|
499
610
|
tree = _OpaquePredicateInserter(rng=rng).visit(tree)
|
|
611
|
+
tree = _mark_annotation_constants(tree)
|
|
500
612
|
tree = _StringEncryptor(rng=rng).visit(tree)
|
|
501
613
|
tree = _ConstantFoldingObfuscator(rng=rng).visit(tree)
|
|
502
614
|
ast.fix_missing_locations(tree)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AutoCython-zhang
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.7
|
|
4
4
|
Summary: 自动Cython,使用Cython批量编译.py文件为.pyd文件!
|
|
5
5
|
Author-email: zhang_gavin <qq814608@163.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -20,7 +20,7 @@ Dynamic: license-file
|
|
|
20
20
|
|
|
21
21
|
# AutoCython
|
|
22
22
|
|
|
23
|
-
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd
|
|
23
|
+
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd`),支持六重 AST 混淆、并发编译、跨平台运行。
|
|
24
24
|
|
|
25
25
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
26
26
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
@@ -33,7 +33,7 @@ AutoCython 是一个 Python 源码保护工具,通过 Cython 编译 + AST 混
|
|
|
33
33
|
## 特性
|
|
34
34
|
|
|
35
35
|
- **一键编译** — 单文件 (`-f`) 或整目录 (`-p`) 批量编译为 `.so`/`.pyd`
|
|
36
|
-
-
|
|
36
|
+
- **六重 AST 混淆** — docstring 移除、局部变量重命名、字符串 XOR 加密、常量折叠、控制流平坦化、虚假分支注入;默认完整保留运行时 annotation,兼容 FastAPI / Pydantic / dataclass
|
|
37
37
|
- **并发编译** — 基于 `ThreadPoolExecutor` 的多线程并行编译,可配置并发数
|
|
38
38
|
- **实时进度面板** — 基于 Rich 的实时任务状态表格、进度条、耗时统计
|
|
39
39
|
- **跨平台** — 支持 Linux、macOS、Windows,自动适配 `.so`/`.pyd` 扩展名
|
|
@@ -108,7 +108,7 @@ print(f"生成: {output}")
|
|
|
108
108
|
|------|------|------|
|
|
109
109
|
| `compile()` | `AutoCython.AutoCython` | 主入口:解析参数并调度编译任务 |
|
|
110
110
|
| `compile_to_binary()` | `AutoCython.compile` | 将单个 `.py` 文件编译为二进制扩展 |
|
|
111
|
-
| `obfuscate_source()` | `AutoCython.obfuscate` |
|
|
111
|
+
| `obfuscate_source()` | `AutoCython.obfuscate` | 对源码执行六重 AST 混淆变换,并保留运行时 annotation |
|
|
112
112
|
| `run_tasks()` | `AutoCython.run_tasks` | 并发任务执行引擎(含实时进度面板) |
|
|
113
113
|
| `find_python_files()` | `AutoCython.tools` | 递归扫描目录下的可编译 `.py` 文件 |
|
|
114
114
|
| `parse_arguments()` | `AutoCython.tools` | CLI 参数解析(中英双语) |
|
|
@@ -124,7 +124,7 @@ AutoCython/
|
|
|
124
124
|
│ ├── _version.py # 单一版本号来源
|
|
125
125
|
│ ├── AutoCython.py # 主编译调度逻辑
|
|
126
126
|
│ ├── compile.py # Cython 编译核心(临时目录隔离)
|
|
127
|
-
│ ├── obfuscate.py #
|
|
127
|
+
│ ├── obfuscate.py # 六重 AST 混淆引擎
|
|
128
128
|
│ ├── run_tasks.py # 并发任务执行 + Rich 实时面板
|
|
129
129
|
│ └── tools.py # CLI 参数解析、文件扫描、国际化
|
|
130
130
|
├── tests/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AutoCython-zhang
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.7
|
|
4
4
|
Summary: 自动Cython,使用Cython批量编译.py文件为.pyd文件!
|
|
5
5
|
Author-email: zhang_gavin <qq814608@163.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -20,7 +20,7 @@ Dynamic: license-file
|
|
|
20
20
|
|
|
21
21
|
# AutoCython
|
|
22
22
|
|
|
23
|
-
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd
|
|
23
|
+
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd`),支持六重 AST 混淆、并发编译、跨平台运行。
|
|
24
24
|
|
|
25
25
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
26
26
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
@@ -33,7 +33,7 @@ AutoCython 是一个 Python 源码保护工具,通过 Cython 编译 + AST 混
|
|
|
33
33
|
## 特性
|
|
34
34
|
|
|
35
35
|
- **一键编译** — 单文件 (`-f`) 或整目录 (`-p`) 批量编译为 `.so`/`.pyd`
|
|
36
|
-
-
|
|
36
|
+
- **六重 AST 混淆** — docstring 移除、局部变量重命名、字符串 XOR 加密、常量折叠、控制流平坦化、虚假分支注入;默认完整保留运行时 annotation,兼容 FastAPI / Pydantic / dataclass
|
|
37
37
|
- **并发编译** — 基于 `ThreadPoolExecutor` 的多线程并行编译,可配置并发数
|
|
38
38
|
- **实时进度面板** — 基于 Rich 的实时任务状态表格、进度条、耗时统计
|
|
39
39
|
- **跨平台** — 支持 Linux、macOS、Windows,自动适配 `.so`/`.pyd` 扩展名
|
|
@@ -108,7 +108,7 @@ print(f"生成: {output}")
|
|
|
108
108
|
|------|------|------|
|
|
109
109
|
| `compile()` | `AutoCython.AutoCython` | 主入口:解析参数并调度编译任务 |
|
|
110
110
|
| `compile_to_binary()` | `AutoCython.compile` | 将单个 `.py` 文件编译为二进制扩展 |
|
|
111
|
-
| `obfuscate_source()` | `AutoCython.obfuscate` |
|
|
111
|
+
| `obfuscate_source()` | `AutoCython.obfuscate` | 对源码执行六重 AST 混淆变换,并保留运行时 annotation |
|
|
112
112
|
| `run_tasks()` | `AutoCython.run_tasks` | 并发任务执行引擎(含实时进度面板) |
|
|
113
113
|
| `find_python_files()` | `AutoCython.tools` | 递归扫描目录下的可编译 `.py` 文件 |
|
|
114
114
|
| `parse_arguments()` | `AutoCython.tools` | CLI 参数解析(中英双语) |
|
|
@@ -124,7 +124,7 @@ AutoCython/
|
|
|
124
124
|
│ ├── _version.py # 单一版本号来源
|
|
125
125
|
│ ├── AutoCython.py # 主编译调度逻辑
|
|
126
126
|
│ ├── compile.py # Cython 编译核心(临时目录隔离)
|
|
127
|
-
│ ├── obfuscate.py #
|
|
127
|
+
│ ├── obfuscate.py # 六重 AST 混淆引擎
|
|
128
128
|
│ ├── run_tasks.py # 并发任务执行 + Rich 实时面板
|
|
129
129
|
│ └── tools.py # CLI 参数解析、文件扫描、国际化
|
|
130
130
|
├── tests/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AutoCython
|
|
2
2
|
|
|
3
|
-
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd
|
|
3
|
+
> 自动将 Python 源码编译为 Cython 二进制扩展(`.so`/`.pyd`),支持六重 AST 混淆、并发编译、跨平台运行。
|
|
4
4
|
|
|
5
5
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
6
6
|
[](https://pypi.org/project/AutoCython-zhang/)
|
|
@@ -13,7 +13,7 @@ AutoCython 是一个 Python 源码保护工具,通过 Cython 编译 + AST 混
|
|
|
13
13
|
## 特性
|
|
14
14
|
|
|
15
15
|
- **一键编译** — 单文件 (`-f`) 或整目录 (`-p`) 批量编译为 `.so`/`.pyd`
|
|
16
|
-
-
|
|
16
|
+
- **六重 AST 混淆** — docstring 移除、局部变量重命名、字符串 XOR 加密、常量折叠、控制流平坦化、虚假分支注入;默认完整保留运行时 annotation,兼容 FastAPI / Pydantic / dataclass
|
|
17
17
|
- **并发编译** — 基于 `ThreadPoolExecutor` 的多线程并行编译,可配置并发数
|
|
18
18
|
- **实时进度面板** — 基于 Rich 的实时任务状态表格、进度条、耗时统计
|
|
19
19
|
- **跨平台** — 支持 Linux、macOS、Windows,自动适配 `.so`/`.pyd` 扩展名
|
|
@@ -88,7 +88,7 @@ print(f"生成: {output}")
|
|
|
88
88
|
|------|------|------|
|
|
89
89
|
| `compile()` | `AutoCython.AutoCython` | 主入口:解析参数并调度编译任务 |
|
|
90
90
|
| `compile_to_binary()` | `AutoCython.compile` | 将单个 `.py` 文件编译为二进制扩展 |
|
|
91
|
-
| `obfuscate_source()` | `AutoCython.obfuscate` |
|
|
91
|
+
| `obfuscate_source()` | `AutoCython.obfuscate` | 对源码执行六重 AST 混淆变换,并保留运行时 annotation |
|
|
92
92
|
| `run_tasks()` | `AutoCython.run_tasks` | 并发任务执行引擎(含实时进度面板) |
|
|
93
93
|
| `find_python_files()` | `AutoCython.tools` | 递归扫描目录下的可编译 `.py` 文件 |
|
|
94
94
|
| `parse_arguments()` | `AutoCython.tools` | CLI 参数解析(中英双语) |
|
|
@@ -104,7 +104,7 @@ AutoCython/
|
|
|
104
104
|
│ ├── _version.py # 单一版本号来源
|
|
105
105
|
│ ├── AutoCython.py # 主编译调度逻辑
|
|
106
106
|
│ ├── compile.py # Cython 编译核心(临时目录隔离)
|
|
107
|
-
│ ├── obfuscate.py #
|
|
107
|
+
│ ├── obfuscate.py # 六重 AST 混淆引擎
|
|
108
108
|
│ ├── run_tasks.py # 并发任务执行 + Rich 实时面板
|
|
109
109
|
│ └── tools.py # CLI 参数解析、文件扫描、国际化
|
|
110
110
|
├── tests/
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython_zhang.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{autocython_zhang-2.3.5 → autocython_zhang-2.3.7}/AutoCython_zhang.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|