pylockware 2.2.0__tar.gz → 2.3.0__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.
- {pylockware-2.2.0 → pylockware-2.3.0}/PKG-INFO +26 -8
- {pylockware-2.2.0 → pylockware-2.3.0}/README.md +24 -6
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/cli/main.py +5 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/name_generator.py +3 -2
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/obfuscator.py +14 -8
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__init__.py +2 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/anti_tamper_builtins_module.py +0 -1
- pylockware-2.3.0/pylockware/modules/builtin_dispatcher_module.py +98 -0
- pylockware-2.3.0/pylockware/modules/expr_virtualize_module.py +57 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/sdk/builder.py +1 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/sdk/config.py +2 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__init__.py +3 -0
- pylockware-2.3.0/pylockware/transforms/builtin_dispatcher.py +355 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/call_obf_v2.py +11 -3
- pylockware-2.3.0/pylockware/transforms/expr_virtualize.py +698 -0
- pylockware-2.3.0/pylockware/transforms/junk_code_transformer.py +1193 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/num_obf.py +13 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/remap_transformer.py +60 -34
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/str_prot.py +34 -99
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware.egg-info/PKG-INFO +26 -8
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware.egg-info/SOURCES.txt +2 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pyproject.toml +1 -1
- {pylockware-2.2.0 → pylockware-2.3.0}/setup.py +2 -2
- pylockware-2.2.0/pylockware/modules/builtin_dispatcher_module.py +0 -231
- pylockware-2.2.0/pylockware/transforms/builtin_dispatcher.py +0 -197
- pylockware-2.2.0/pylockware/transforms/junk_code_transformer.py +0 -698
- {pylockware-2.2.0 → pylockware-2.3.0}/.github/workflows/python-publish.yml +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/.gitignore +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/LICENSE +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/MANIFEST.in +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/__init__.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/__pycache__/__init__.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/__pycache__/decorators.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/anti_debug/__init__.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/anti_debug/antidebug_crossplatform.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/anti_debug/antidebug_llvm.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/anti_tamper/anti_tamper_builtins.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/cli/__init__.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/cli/build.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/__init__.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/__pycache__/__init__.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/__pycache__/module_base.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/__pycache__/module_manager.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/__pycache__/name_generator.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/__pycache__/obfuscator.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/module_base.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/core/module_manager.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/decorators.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/gui/__init__.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/gui/main.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/gui/obfuscator_gui.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/__init__.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/anti_debug_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/anti_tamper_builtins_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/builtin_dispatcher_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/call_obf_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/crypt_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/decorator_obf_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/import_obf_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/junk_code_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/nuitka_builder_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/number_obf_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/remap_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/remove_annotations_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/state_machine_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/string_protect_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/__pycache__/type_annotation_obf_module.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/anti_debug_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/call_obf_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/crypt_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/decorator_obf_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/disable_traceback_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/import_obf_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/junk_code_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/nuitka_builder_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/number_obf_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/remap_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/remove_annotations_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/state_machine_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/string_protect_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/modules/type_annotation_obf_module.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/sdk/__init__.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/sdk/__pycache__/__init__.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/sdk/__pycache__/builder.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/sdk/__pycache__/config.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/__init__.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/builtin_dispatcher.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/crypter.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/decorator_obf.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/junk_code_transformer.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/num_obf.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/remap_transformer.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/state_machine_transformer.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/str_prot.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/__pycache__/type_annotation_obf.cpython-312.pyc +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/annotation_aware_transformer.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/crypter.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/decorator_obf.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/state_machine_transformer.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware/transforms/type_annotation_obf.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware.egg-info/dependency_links.txt +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware.egg-info/entry_points.txt +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware.egg-info/requires.txt +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/pylockware.egg-info/top_level.txt +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/requirements.txt +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/setup.cfg +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/test_conflict.py +0 -0
- {pylockware-2.2.0 → pylockware-2.3.0}/test_obf.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pylockware
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Python Code Protection SDK with obfuscation and anti-debug features
|
|
5
|
-
Home-page: https://github.com/
|
|
5
|
+
Home-page: https://github.com/amogusgggy/pylockware
|
|
6
6
|
Author: PyLockWare Team
|
|
7
7
|
License: AGPL-3.0-or-later
|
|
8
8
|
Project-URL: Homepage, https://github.com/amogus-gggy/pylockware
|
|
@@ -62,12 +62,30 @@ Dynamic: requires-python
|
|
|
62
62
|
[](https://www.python.org/downloads/)
|
|
63
63
|
[](LICENSE)
|
|
64
64
|
|
|
65
|
-
## Changelog v2.
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
|
|
65
|
+
## Changelog v2.3.0
|
|
66
|
+
**Added**
|
|
67
|
+
- `--expr-virtualize` — compiles expressions to custom VM bytecode with XOR-encrypted dispatch table
|
|
68
|
+
- Anti-dump string poisoning — 500 random garbage strings injected into junk code to pollute static analysis
|
|
69
|
+
- Poison variable chains — self-referential dead variables that raise `NameError` if stripped by deobfuscators
|
|
70
|
+
- Deeply nested dead code — fake `if` chains, `try/except`, `with` blocks for maximum visual noise
|
|
71
|
+
- `l-i` name generator — visually ambiguous identifiers (`I`/`l`/`i`/`L`)
|
|
72
|
+
- Per-module embedded builtin dispatcher — no external files, each module carries its own obfuscated dispatcher
|
|
73
|
+
|
|
74
|
+
**Changed**
|
|
75
|
+
- Builtin dispatcher: scope-aware shadowing detection, no longer renames locally overridden builtins
|
|
76
|
+
- String protection: inline decode calls instead of global variables per string
|
|
77
|
+
- Number obfuscation: auto-injects `os`/`sys` imports when needed(bug fix)
|
|
78
|
+
- Remap: skips imported module attributes (fixes `datetime.datetime.hour`-style breaks)
|
|
79
|
+
- Call obfuscation: full frame stack walk for `_call`/`_resolve`
|
|
80
|
+
- Default name length: 32 → 128 chars; junk density: 0.5 → 0.8
|
|
81
|
+
|
|
82
|
+
**Fixed**
|
|
83
|
+
- `ExprVirtualizeModule` now runs after all AST transforms
|
|
84
|
+
- String protection no longer leaks undeclared globals
|
|
85
|
+
- Removed stale `_builtin_dispatcher.py` references
|
|
86
|
+
|
|
87
|
+
**Removed**
|
|
88
|
+
- Central `_builtin_dispatcher.py` — fully inlined
|
|
71
89
|
|
|
72
90
|
## 🚀 Features
|
|
73
91
|
|
|
@@ -5,12 +5,30 @@
|
|
|
5
5
|
[](https://www.python.org/downloads/)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
## Changelog v2.
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
|
|
8
|
+
## Changelog v2.3.0
|
|
9
|
+
**Added**
|
|
10
|
+
- `--expr-virtualize` — compiles expressions to custom VM bytecode with XOR-encrypted dispatch table
|
|
11
|
+
- Anti-dump string poisoning — 500 random garbage strings injected into junk code to pollute static analysis
|
|
12
|
+
- Poison variable chains — self-referential dead variables that raise `NameError` if stripped by deobfuscators
|
|
13
|
+
- Deeply nested dead code — fake `if` chains, `try/except`, `with` blocks for maximum visual noise
|
|
14
|
+
- `l-i` name generator — visually ambiguous identifiers (`I`/`l`/`i`/`L`)
|
|
15
|
+
- Per-module embedded builtin dispatcher — no external files, each module carries its own obfuscated dispatcher
|
|
16
|
+
|
|
17
|
+
**Changed**
|
|
18
|
+
- Builtin dispatcher: scope-aware shadowing detection, no longer renames locally overridden builtins
|
|
19
|
+
- String protection: inline decode calls instead of global variables per string
|
|
20
|
+
- Number obfuscation: auto-injects `os`/`sys` imports when needed(bug fix)
|
|
21
|
+
- Remap: skips imported module attributes (fixes `datetime.datetime.hour`-style breaks)
|
|
22
|
+
- Call obfuscation: full frame stack walk for `_call`/`_resolve`
|
|
23
|
+
- Default name length: 32 → 128 chars; junk density: 0.5 → 0.8
|
|
24
|
+
|
|
25
|
+
**Fixed**
|
|
26
|
+
- `ExprVirtualizeModule` now runs after all AST transforms
|
|
27
|
+
- String protection no longer leaks undeclared globals
|
|
28
|
+
- Removed stale `_builtin_dispatcher.py` references
|
|
29
|
+
|
|
30
|
+
**Removed**
|
|
31
|
+
- Central `_builtin_dispatcher.py` — fully inlined
|
|
14
32
|
|
|
15
33
|
## 🚀 Features
|
|
16
34
|
|
|
@@ -38,6 +38,7 @@ def main_cli():
|
|
|
38
38
|
parser.add_argument("--decorator-obf", action="store_true", help="Enable decorator obfuscation (converts @decorator to func = decorator(func))")
|
|
39
39
|
parser.add_argument("--call-obf", action="store_true", help="Enable chained-table call obfuscation (_call/_resolve)")
|
|
40
40
|
parser.add_argument("--crypt", action="store_true", help="Enable function encryption using machine fingerprinting and XOR encryption")
|
|
41
|
+
parser.add_argument("--expr-virtualize", action="store_true", help="Enable expression virtualization (compiles expressions to custom bytecode)")
|
|
41
42
|
parser.add_argument("--anti-tamper-builtins", action=argparse.BooleanOptionalAction, default=True,
|
|
42
43
|
help="Enable runtime anti-tamper guard that crashes on patched Python builtins (default: enabled)")
|
|
43
44
|
parser.add_argument("--all", action="store_true", help="Enable all obfuscation options (except Nuitka)")
|
|
@@ -66,6 +67,8 @@ def main_cli():
|
|
|
66
67
|
print(" Please use only one of these options at a time.")
|
|
67
68
|
sys.exit(1)
|
|
68
69
|
|
|
70
|
+
|
|
71
|
+
|
|
69
72
|
# If --all is specified, enable all obfuscation options (except Nuitka)
|
|
70
73
|
if args.all:
|
|
71
74
|
args.remap = False
|
|
@@ -78,6 +81,7 @@ def main_cli():
|
|
|
78
81
|
args.disable_traceback = True
|
|
79
82
|
args.decorator_obf = True
|
|
80
83
|
args.call_obf = False
|
|
84
|
+
args.expr_virtualize = True
|
|
81
85
|
|
|
82
86
|
# Determine anti_debug mode
|
|
83
87
|
anti_debug_value = None
|
|
@@ -113,6 +117,7 @@ def main_cli():
|
|
|
113
117
|
call_obf=args.call_obf,
|
|
114
118
|
crypt=args.crypt,
|
|
115
119
|
anti_tamper_builtins=args.anti_tamper_builtins,
|
|
120
|
+
expr_virtualize=args.expr_virtualize,
|
|
116
121
|
enable_nuitka=args.nuitka,
|
|
117
122
|
nuitka_onefile=args.nuitka_onefile,
|
|
118
123
|
nuitka_standalone=args.nuitka_standalone,
|
|
@@ -20,7 +20,8 @@ class NameGenerator:
|
|
|
20
20
|
'mixed': string.ascii_letters + string.digits + ''.join(chr(i) for i in range(0x4E00, 0x9FFF)),
|
|
21
21
|
'numbers': string.digits,
|
|
22
22
|
'hex': string.hexdigits,
|
|
23
|
-
'ascii': string.printable.strip()
|
|
23
|
+
'ascii': string.printable.strip(), # All printable ASCII except whitespace
|
|
24
|
+
'l-i': "IliL"
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
self.char_set = self.char_sets.get(char_set, self.char_sets['english'])
|
|
@@ -36,7 +37,7 @@ class NameGenerator:
|
|
|
36
37
|
Returns:
|
|
37
38
|
Randomly generated name
|
|
38
39
|
"""
|
|
39
|
-
length =
|
|
40
|
+
length = 128 # Default length
|
|
40
41
|
|
|
41
42
|
# If prefix is empty or doesn't start with letter/underscore, add underscore
|
|
42
43
|
if not prefix or (prefix[0] not in string.ascii_letters + '_'):
|
|
@@ -28,6 +28,7 @@ from pylockware.modules.call_obf_module import CallObfModule
|
|
|
28
28
|
from pylockware.modules.remove_annotations_module import RemoveAnnotationsModule
|
|
29
29
|
from pylockware.modules.crypt_module import CryptModule
|
|
30
30
|
from pylockware.modules.anti_tamper_builtins_module import AntiTamperBuiltinsModule
|
|
31
|
+
from pylockware.modules.expr_virtualize_module import ExprVirtualizeModule
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class PyObfuscator:
|
|
@@ -48,7 +49,8 @@ class PyObfuscator:
|
|
|
48
49
|
nuitka_admin: bool = False, nuitka_plugins: List[str] = None, nuitka_extra_imports: List[str] = None,
|
|
49
50
|
nuitka_options: List[str] = None, disable_traceback: bool = False,
|
|
50
51
|
decorator_obf: bool = False, type_annotation_obf: bool = False, call_obf: bool = False,
|
|
51
|
-
crypt: bool = False, anti_tamper_builtins: bool = True
|
|
52
|
+
crypt: bool = False, anti_tamper_builtins: bool = True,
|
|
53
|
+
expr_virtualize: bool = False):
|
|
52
54
|
self.project_path = Path(project_path)
|
|
53
55
|
self.entry_point = Path(entry_point)
|
|
54
56
|
self.entry_function = entry_function
|
|
@@ -71,6 +73,7 @@ class PyObfuscator:
|
|
|
71
73
|
self.call_obf = call_obf # Enable call obfuscation using getattr pattern
|
|
72
74
|
self.crypt = crypt # Enable function encryption using machine fingerprinting
|
|
73
75
|
self.anti_tamper_builtins = anti_tamper_builtins # Enable runtime anti-tamper guard for builtins
|
|
76
|
+
self.expr_virtualize = expr_virtualize # Enable expression virtualization
|
|
74
77
|
|
|
75
78
|
# Nuitka options
|
|
76
79
|
self.enable_nuitka = enable_nuitka
|
|
@@ -90,7 +93,6 @@ class PyObfuscator:
|
|
|
90
93
|
|
|
91
94
|
# Validate and adjust incompatible options
|
|
92
95
|
self._validate_nuitka_compatibility()
|
|
93
|
-
|
|
94
96
|
self.setup_modules()
|
|
95
97
|
|
|
96
98
|
def _validate_nuitka_compatibility(self):
|
|
@@ -107,7 +109,7 @@ class PyObfuscator:
|
|
|
107
109
|
if self.enable_nuitka:
|
|
108
110
|
if self.anti_debug:
|
|
109
111
|
self.anti_debug = None
|
|
110
|
-
|
|
112
|
+
|
|
111
113
|
if self.import_obf:
|
|
112
114
|
self.import_obf = False
|
|
113
115
|
|
|
@@ -160,10 +162,7 @@ class PyObfuscator:
|
|
|
160
162
|
call_obf_config = {'name_gen': self.name_gen}
|
|
161
163
|
self.module_manager.add_module(CallObfModule(call_obf_config))
|
|
162
164
|
|
|
163
|
-
|
|
164
|
-
if self.string_prot:
|
|
165
|
-
string_prot_config = {'name_gen': self.name_gen}
|
|
166
|
-
self.module_manager.add_module(StringProtectModule(string_prot_config))
|
|
165
|
+
|
|
167
166
|
|
|
168
167
|
if self.anti_debug:
|
|
169
168
|
anti_debug_config = {
|
|
@@ -200,6 +199,10 @@ class PyObfuscator:
|
|
|
200
199
|
num_obf_config = {'name_gen': self.name_gen}
|
|
201
200
|
self.module_manager.add_module(NumberObfModule(num_obf_config))
|
|
202
201
|
|
|
202
|
+
# Add modules based on configuration
|
|
203
|
+
if self.string_prot:
|
|
204
|
+
string_prot_config = {'name_gen': self.name_gen}
|
|
205
|
+
self.module_manager.add_module(StringProtectModule(string_prot_config))
|
|
203
206
|
# Decorator obfuscation - converts @decorator to explicit assignments
|
|
204
207
|
# Module disabled due to conflict with annotations
|
|
205
208
|
# if self.decorator_obf:
|
|
@@ -223,6 +226,10 @@ class PyObfuscator:
|
|
|
223
226
|
|
|
224
227
|
# Add RemoveAnnotations module to clean up decorators
|
|
225
228
|
self.module_manager.add_module(RemoveAnnotationsModule({}))
|
|
229
|
+
|
|
230
|
+
# ExprVirtualize runs AFTER all AST transforms so its output isn't corrupted
|
|
231
|
+
if self.expr_virtualize:
|
|
232
|
+
self.module_manager.add_module(ExprVirtualizeModule({}))
|
|
226
233
|
|
|
227
234
|
# Add crypt module if enabled - runs after all other obfuscation
|
|
228
235
|
if self.crypt:
|
|
@@ -288,7 +295,6 @@ class PyObfuscator:
|
|
|
288
295
|
import python_minifier
|
|
289
296
|
|
|
290
297
|
obfuscator_files = [
|
|
291
|
-
"_builtin_dispatcher.py",
|
|
292
298
|
"anti_tamper_builtins.py",
|
|
293
299
|
"antidebug_crossplatform.py",
|
|
294
300
|
"antidebug_llvm.py",
|
|
@@ -9,6 +9,7 @@ from .anti_debug_module import AntiDebugModule
|
|
|
9
9
|
from .import_obf_module import ImportObfuscateModule
|
|
10
10
|
from .state_machine_module import StateMachineModule
|
|
11
11
|
from .crypt_module import CryptModule
|
|
12
|
+
from .expr_virtualize_module import ExprVirtualizeModule
|
|
12
13
|
|
|
13
14
|
__all__ = [
|
|
14
15
|
'RemapModule',
|
|
@@ -18,4 +19,5 @@ __all__ = [
|
|
|
18
19
|
'ImportObfuscateModule',
|
|
19
20
|
'StateMachineModule',
|
|
20
21
|
'CryptModule',
|
|
22
|
+
'ExprVirtualizeModule',
|
|
21
23
|
]
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Builtin Dispatcher Module for PyLockWare
|
|
3
|
+
Replaces all built-in function calls with calls via a dispatcher
|
|
4
|
+
Встраивает dispatcher прямо в каждый модуль — без внешних файлов
|
|
5
|
+
"""
|
|
6
|
+
import ast
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Dict, Any
|
|
9
|
+
from pylockware.core.module_base import ModuleBase
|
|
10
|
+
from pylockware.transforms.builtin_dispatcher import BuiltinDispatcherTransformer, BUILTIN_FUNCTIONS
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BuiltinDispatcherModule(ModuleBase):
|
|
14
|
+
"""
|
|
15
|
+
Module that replaces built-in function calls with dispatcher calls
|
|
16
|
+
e.g., print() -> _dispatcher.ghjfkd()
|
|
17
|
+
Dispatcher code is embedded directly into each module - no external files needed
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, config: Dict[str, Any] = None):
|
|
21
|
+
super().__init__(config)
|
|
22
|
+
self.name_gen_settings = self.config.get('name_gen', 'english')
|
|
23
|
+
|
|
24
|
+
def process(self, project_path: Path, output_path: Path) -> bool:
|
|
25
|
+
"""
|
|
26
|
+
Process the project by replacing built-in calls with dispatcher calls
|
|
27
|
+
Dispatcher code is embedded directly into each module
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
project_path: Path to the original project
|
|
31
|
+
output_path: Path to the output directory
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
True if processing was successful, False otherwise
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
print("Applying builtin dispatcher obfuscation...")
|
|
38
|
+
|
|
39
|
+
# Find all Python files in the output directory
|
|
40
|
+
py_files = list(output_path.rglob("*.py"))
|
|
41
|
+
|
|
42
|
+
# Files that should NOT be transformed (they contain critical runtime checks)
|
|
43
|
+
protected_files = {
|
|
44
|
+
"antidebug_llvm.py",
|
|
45
|
+
"antidebug_crossplatform.py",
|
|
46
|
+
"anti_tamper_builtins.py",
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
files_modified = 0
|
|
50
|
+
|
|
51
|
+
for py_file in py_files:
|
|
52
|
+
if py_file.name in protected_files:
|
|
53
|
+
continue
|
|
54
|
+
try:
|
|
55
|
+
with open(py_file, 'r', encoding='utf-8') as f:
|
|
56
|
+
original_code = f.read()
|
|
57
|
+
|
|
58
|
+
tree = ast.parse(original_code)
|
|
59
|
+
|
|
60
|
+
# Create a fresh transformer for each file (unique obfuscated names)
|
|
61
|
+
transformer = BuiltinDispatcherTransformer(name_gen_settings=self.name_gen_settings)
|
|
62
|
+
|
|
63
|
+
# Use transform_module which embeds dispatcher directly
|
|
64
|
+
transformed_tree = transformer.transform_module(tree)
|
|
65
|
+
|
|
66
|
+
# Only write if changes were made
|
|
67
|
+
if transformer.builtins_map:
|
|
68
|
+
new_content = ast.unparse(transformed_tree)
|
|
69
|
+
|
|
70
|
+
with open(py_file, 'w', encoding='utf-8') as f:
|
|
71
|
+
f.write(new_content)
|
|
72
|
+
files_modified += 1
|
|
73
|
+
print(f" Obfuscated builtins in {py_file}")
|
|
74
|
+
|
|
75
|
+
except Exception as e:
|
|
76
|
+
print(f"Error processing {py_file}: {e}")
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
if files_modified == 0:
|
|
80
|
+
print("No built-in functions found, skipping builtin dispatcher obfuscation.")
|
|
81
|
+
else:
|
|
82
|
+
print(f"Builtin dispatcher obfuscation complete. Modified {files_modified} files.")
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
except Exception as e:
|
|
86
|
+
print(f"Error during builtin dispatcher obfuscation: {e}")
|
|
87
|
+
import traceback
|
|
88
|
+
traceback.print_exc()
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
def validate_config(self) -> bool:
|
|
92
|
+
"""
|
|
93
|
+
Validate the module's configuration
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
True if configuration is valid, False otherwise
|
|
97
|
+
"""
|
|
98
|
+
return True
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Expression Virtualization Module for PyLockWare
|
|
3
|
+
Replaces expressions with VM-interpreted bytecode
|
|
4
|
+
"""
|
|
5
|
+
import ast
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, Any
|
|
8
|
+
from pylockware.core.module_base import ModuleBase
|
|
9
|
+
from pylockware.transforms.expr_virtualize import virtualize_code, VM_RUNTIME_CODE
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ExprVirtualizeModule(ModuleBase):
|
|
13
|
+
"""
|
|
14
|
+
Module that virtualizes expressions by compiling them to custom bytecode
|
|
15
|
+
and replacing them with calls to a VM interpreter
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, config: Dict[str, Any] = None):
|
|
19
|
+
super().__init__(config)
|
|
20
|
+
|
|
21
|
+
def process(self, project_path: Path, output_path: Path) -> bool:
|
|
22
|
+
try:
|
|
23
|
+
print("Applying expression virtualization to all Python files...")
|
|
24
|
+
|
|
25
|
+
runtime_file = output_path / "_vmentry_rt.py"
|
|
26
|
+
runtime_file.write_text(VM_RUNTIME_CODE, encoding='utf-8')
|
|
27
|
+
|
|
28
|
+
for py_file in output_path.rglob("*.py"):
|
|
29
|
+
if py_file.name in ["anti_debug_injector.py", "anti_debug_injector_normal.py",
|
|
30
|
+
"obfuscator.py", "num_obf.py", "antidebug_llvm.py",
|
|
31
|
+
"_vmentry_rt.py"]:
|
|
32
|
+
continue
|
|
33
|
+
try:
|
|
34
|
+
with open(py_file, 'r', encoding='utf-8') as f:
|
|
35
|
+
original_code = f.read()
|
|
36
|
+
|
|
37
|
+
if '_vmentry' in original_code:
|
|
38
|
+
continue
|
|
39
|
+
|
|
40
|
+
virtualized_code = virtualize_code(original_code)
|
|
41
|
+
|
|
42
|
+
if virtualized_code != original_code:
|
|
43
|
+
final_code = "from _vmentry_rt import _vmentry\n" + virtualized_code
|
|
44
|
+
with open(py_file, 'w', encoding='utf-8') as f:
|
|
45
|
+
f.write(final_code)
|
|
46
|
+
print(f"Virtualized expressions in {py_file}")
|
|
47
|
+
|
|
48
|
+
except Exception as e:
|
|
49
|
+
print(f"Error applying expression virtualization to {py_file}: {e}")
|
|
50
|
+
|
|
51
|
+
return True
|
|
52
|
+
except Exception as e:
|
|
53
|
+
print(f"Error during expression virtualization: {e}")
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
def validate_config(self) -> bool:
|
|
57
|
+
return True
|
|
@@ -148,6 +148,7 @@ class Builder:
|
|
|
148
148
|
call_obf=self.config.call_obf,
|
|
149
149
|
crypt=self.config.crypt,
|
|
150
150
|
anti_tamper_builtins=self.config.anti_tamper_builtins,
|
|
151
|
+
expr_virtualize=self.config.expr_virtualize,
|
|
151
152
|
enable_nuitka=self.config.enable_nuitka,
|
|
152
153
|
nuitka_onefile=self.config.nuitka_onefile,
|
|
153
154
|
nuitka_standalone=self.config.nuitka_standalone,
|
|
@@ -33,6 +33,7 @@ class BuildConfig:
|
|
|
33
33
|
crypt: bool = False
|
|
34
34
|
disable_traceback: bool = True
|
|
35
35
|
anti_tamper_builtins: bool = True
|
|
36
|
+
expr_virtualize: bool = False
|
|
36
37
|
|
|
37
38
|
# Параметры обфускации
|
|
38
39
|
junk_density: float = 0.5
|
|
@@ -179,6 +180,7 @@ def _save_pretty_toml(data: dict, path: Path, config: BuildConfig) -> None:
|
|
|
179
180
|
lines.append(f"crypt = {str(config.crypt).lower()}")
|
|
180
181
|
lines.append(f"disable_traceback = {str(config.disable_traceback).lower()}")
|
|
181
182
|
lines.append(f"anti_tamper_builtins = {str(config.anti_tamper_builtins).lower()}")
|
|
183
|
+
lines.append(f"expr_virtualize = {str(config.expr_virtualize).lower()}")
|
|
182
184
|
lines.append(f"anti_debug = {str(bool(config.anti_debug)).lower()}")
|
|
183
185
|
lines.append("")
|
|
184
186
|
|
|
@@ -14,6 +14,7 @@ from .crypter import (
|
|
|
14
14
|
derive_key,
|
|
15
15
|
generate_seed,
|
|
16
16
|
)
|
|
17
|
+
from .expr_virtualize import virtualize_code, VM_RUNTIME_CODE
|
|
17
18
|
|
|
18
19
|
__all__ = [
|
|
19
20
|
'NumberObfuscator',
|
|
@@ -27,4 +28,6 @@ __all__ = [
|
|
|
27
28
|
'xor_encrypt',
|
|
28
29
|
'derive_key',
|
|
29
30
|
'generate_seed',
|
|
31
|
+
'virtualize_code',
|
|
32
|
+
'VM_RUNTIME_CODE',
|
|
30
33
|
]
|