PyProtect-v3 3.0.0__tar.gz → 3.1.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.
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/PKG-INFO +1 -1
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/PyProtect_v3.egg-info/PKG-INFO +1 -1
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyproject.toml +1 -1
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyprotect/__main__.py +0 -2
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyprotect/engine.c +172 -6
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyprotect/obfuscator.py +8 -67
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/MANIFEST.in +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/PyProtect_v3.egg-info/SOURCES.txt +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/PyProtect_v3.egg-info/dependency_links.txt +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/PyProtect_v3.egg-info/entry_points.txt +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/PyProtect_v3.egg-info/requires.txt +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/PyProtect_v3.egg-info/top_level.txt +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/README.md +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyprotect/__init__.py +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyprotect/_key.py +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyprotect/anti_debug.py +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyprotect/crypto.py +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyprotect/engine.py +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/pyprotect/hooks.py +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/setup.cfg +0 -0
- {pyprotect_v3-3.0.0 → pyprotect_v3-3.1.0}/setup.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "PyProtect-v3"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.1.0"
|
|
8
8
|
description = "Python script obfuscation library with AES-256-GCM encryption and C extension acceleration"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -15,7 +15,6 @@ def cmd_encrypt(args):
|
|
|
15
15
|
)
|
|
16
16
|
out_path = obf.encrypt_file(args.input)
|
|
17
17
|
print(f"[+] Encrypted: {args.input} -> {out_path}")
|
|
18
|
-
_copy_engine(args.output_dir)
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
def cmd_encrypt_dir(args):
|
|
@@ -29,7 +28,6 @@ def cmd_encrypt_dir(args):
|
|
|
29
28
|
print(f"[+] Encrypted {len(out_files)} files from {args.input}")
|
|
30
29
|
for f in out_files:
|
|
31
30
|
print(f" -> {f}")
|
|
32
|
-
_copy_engine(args.output_dir)
|
|
33
31
|
|
|
34
32
|
|
|
35
33
|
def cmd_build_engine(args):
|
|
@@ -298,6 +298,86 @@ static int deep_anti_debug(void) {
|
|
|
298
298
|
return detected;
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
+
/* ------------------------------------------------------------------ */
|
|
302
|
+
/* Anti-hook — detect debugger trace, profile, suspicious import hooks */
|
|
303
|
+
/* ------------------------------------------------------------------ */
|
|
304
|
+
|
|
305
|
+
static int deep_anti_hook(void) {
|
|
306
|
+
int detected = 0;
|
|
307
|
+
PyObject *sys_mod = PyImport_AddModule("sys");
|
|
308
|
+
if (!sys_mod) return 0;
|
|
309
|
+
PyObject *f = PyObject_GetAttrString(sys_mod, "gettrace");
|
|
310
|
+
if (f) {
|
|
311
|
+
PyObject *v = PyObject_CallNoArgs(f);
|
|
312
|
+
if (v && v != Py_None) detected = 1;
|
|
313
|
+
Py_XDECREF(v); Py_DECREF(f);
|
|
314
|
+
}
|
|
315
|
+
f = PyObject_GetAttrString(sys_mod, "getprofile");
|
|
316
|
+
if (f) {
|
|
317
|
+
PyObject *v = PyObject_CallNoArgs(f);
|
|
318
|
+
if (v && v != Py_None) detected = 1;
|
|
319
|
+
Py_XDECREF(v); Py_DECREF(f);
|
|
320
|
+
}
|
|
321
|
+
/* Check meta_path for known hostile importers */
|
|
322
|
+
PyObject *meta_path = PySys_GetObject("meta_path");
|
|
323
|
+
if (meta_path && PyList_Check(meta_path)) {
|
|
324
|
+
Py_ssize_t n = PyList_Size(meta_path);
|
|
325
|
+
for (Py_ssize_t i = 0; i < n; i++) {
|
|
326
|
+
PyObject *item = PyList_GetItem(meta_path, i);
|
|
327
|
+
if (!item) continue;
|
|
328
|
+
PyObject *name = PyObject_GetAttrString(item, "__class__");
|
|
329
|
+
if (!name) { PyErr_Clear(); continue; }
|
|
330
|
+
PyObject *cname = PyObject_GetAttrString(name, "__name__");
|
|
331
|
+
Py_DECREF(name);
|
|
332
|
+
if (!cname) { PyErr_Clear(); continue; }
|
|
333
|
+
const char *s = PyUnicode_AsUTF8(cname);
|
|
334
|
+
if (s) {
|
|
335
|
+
if (strstr(s, "Hook") || strstr(s, "Redirect") ||
|
|
336
|
+
strstr(s, "Monitor") || strstr(s, "Interceptor") ||
|
|
337
|
+
strstr(s, "Tracer") || strstr(s, "Proxy") ||
|
|
338
|
+
strstr(s, "Debug") || strstr(s, "Inject")) {
|
|
339
|
+
detected = 1;
|
|
340
|
+
Py_DECREF(cname);
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
Py_DECREF(cname);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return detected;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* ------------------------------------------------------------------ */
|
|
351
|
+
/* Anti-decode — block decompilers, profilers, debugger modules */
|
|
352
|
+
/* ------------------------------------------------------------------ */
|
|
353
|
+
|
|
354
|
+
static int deep_anti_decode(void) {
|
|
355
|
+
int detected = 0;
|
|
356
|
+
PyObject *sys_mod = PyImport_AddModule("sys");
|
|
357
|
+
if (sys_mod) {
|
|
358
|
+
PyObject *modules = PyObject_GetAttrString(sys_mod, "modules");
|
|
359
|
+
if (modules && PyDict_Check(modules)) {
|
|
360
|
+
const char *sus[] = {
|
|
361
|
+
"decompyle3","uncompyle6","decompyle","frida",
|
|
362
|
+
"pyrasite","pydevd","pdb","ipdb",
|
|
363
|
+
"pyinstrument","cProfile","line_profiler",NULL
|
|
364
|
+
};
|
|
365
|
+
for (int i = 0; sus[i]; i++) {
|
|
366
|
+
PyObject *k = PyUnicode_FromString(sus[i]);
|
|
367
|
+
if (k) {
|
|
368
|
+
if (PyDict_GetItem(modules, k)) { detected = 1; Py_DECREF(k); break; }
|
|
369
|
+
Py_DECREF(k);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
Py_XDECREF(modules);
|
|
374
|
+
}
|
|
375
|
+
if (getenv("PYTHONDEVMODE")) detected = 1;
|
|
376
|
+
if (getenv("PYTHONINSPECT")) detected = 1;
|
|
377
|
+
if (getenv("PYSEC")) detected = 1;
|
|
378
|
+
return detected;
|
|
379
|
+
}
|
|
380
|
+
|
|
301
381
|
/* ------------------------------------------------------------------ */
|
|
302
382
|
/* Memory protection: re-encrypt buffer after use */
|
|
303
383
|
/* ------------------------------------------------------------------ */
|
|
@@ -382,6 +462,77 @@ static int _decrypt_payload(const uint8_t *data, size_t data_len,
|
|
|
382
462
|
return 0;
|
|
383
463
|
}
|
|
384
464
|
|
|
465
|
+
/* ------------------------------------------------------------------ */
|
|
466
|
+
/* Frame evaluation hook — anti-tamper check on every function call */
|
|
467
|
+
/* We use the CPython 3.11+ internal API to intercept frame evaluation */
|
|
468
|
+
/* ------------------------------------------------------------------ */
|
|
469
|
+
|
|
470
|
+
/* These are declared in cpython/pystate.h and cpython/ceval.h
|
|
471
|
+
which are included by Python.h */
|
|
472
|
+
|
|
473
|
+
static _PyFrameEvalFunction original_eval_frame = NULL;
|
|
474
|
+
static PyInterpreterState *hooked_interp = NULL;
|
|
475
|
+
|
|
476
|
+
static PyObject* protected_eval_frame(PyThreadState *tstate, struct _PyInterpreterFrame *frame, int throwflag) {
|
|
477
|
+
if (deep_anti_debug() || deep_anti_hook() || deep_anti_decode()) {
|
|
478
|
+
PyErr_SetString(PyExc_RuntimeError, "Tamper detected");
|
|
479
|
+
return NULL;
|
|
480
|
+
}
|
|
481
|
+
return _PyEval_EvalFrameDefault(tstate, frame, throwflag);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
static void install_frame_hook(void) {
|
|
485
|
+
if (original_eval_frame) return;
|
|
486
|
+
PyInterpreterState *interp = PyInterpreterState_Get();
|
|
487
|
+
if (!interp) return;
|
|
488
|
+
_PyFrameEvalFunction cur = _PyInterpreterState_GetEvalFrameFunc(interp);
|
|
489
|
+
if (cur == protected_eval_frame) return;
|
|
490
|
+
original_eval_frame = cur;
|
|
491
|
+
hooked_interp = interp;
|
|
492
|
+
_PyInterpreterState_SetEvalFrameFunc(interp, protected_eval_frame);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
static void restore_frame_hook(void) {
|
|
496
|
+
if (!original_eval_frame || !hooked_interp) return;
|
|
497
|
+
_PyInterpreterState_SetEvalFrameFunc(hooked_interp, original_eval_frame);
|
|
498
|
+
original_eval_frame = NULL;
|
|
499
|
+
hooked_interp = NULL;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/* ------------------------------------------------------------------ */
|
|
503
|
+
/* Wipe code tree — recursively clear all code objects' bytecodes */
|
|
504
|
+
/* ------------------------------------------------------------------ */
|
|
505
|
+
|
|
506
|
+
static void wipe_code_tree(PyObject *co) {
|
|
507
|
+
if (!co || !PyCode_Check(co)) return;
|
|
508
|
+
PyCodeObject *code = (PyCodeObject*)co;
|
|
509
|
+
|
|
510
|
+
PyObject *bc = PyCode_GetCode(code);
|
|
511
|
+
if (bc && PyBytes_Check(bc)) {
|
|
512
|
+
Py_ssize_t sz;
|
|
513
|
+
char *buf;
|
|
514
|
+
if (PyBytes_AsStringAndSize(bc, &buf, &sz) == 0 && buf && sz > 0) {
|
|
515
|
+
memset(buf, 0, (size_t)sz);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
Py_XDECREF(bc);
|
|
519
|
+
|
|
520
|
+
PyObject *consts = code->co_consts;
|
|
521
|
+
if (consts && PyTuple_Check(consts)) {
|
|
522
|
+
Py_ssize_t n = PyTuple_Size(consts);
|
|
523
|
+
for (Py_ssize_t i = 0; i < n; i++) {
|
|
524
|
+
PyObject *item = PyTuple_GetItem(consts, i);
|
|
525
|
+
if (item && PyCode_Check(item)) {
|
|
526
|
+
wipe_code_tree(item);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/* ------------------------------------------------------------------ */
|
|
533
|
+
/* Decrypt and exec */
|
|
534
|
+
/* ------------------------------------------------------------------ */
|
|
535
|
+
|
|
385
536
|
static PyObject* engine_decrypt_and_exec(PyObject *self, PyObject *args) {
|
|
386
537
|
const uint8_t *data;
|
|
387
538
|
Py_ssize_t data_len;
|
|
@@ -389,8 +540,8 @@ static PyObject* engine_decrypt_and_exec(PyObject *self, PyObject *args) {
|
|
|
389
540
|
if (!PyArg_ParseTuple(args, "y#", &data, &data_len))
|
|
390
541
|
return NULL;
|
|
391
542
|
|
|
392
|
-
if (deep_anti_debug()) {
|
|
393
|
-
PyErr_SetString(PyExc_RuntimeError, "
|
|
543
|
+
if (deep_anti_debug() || deep_anti_hook() || deep_anti_decode()) {
|
|
544
|
+
PyErr_SetString(PyExc_RuntimeError, "Tamper detected");
|
|
394
545
|
return NULL;
|
|
395
546
|
}
|
|
396
547
|
|
|
@@ -462,15 +613,25 @@ static PyObject* engine_decrypt_and_exec(PyObject *self, PyObject *args) {
|
|
|
462
613
|
return NULL;
|
|
463
614
|
}
|
|
464
615
|
|
|
616
|
+
/* Install frame eval hook */
|
|
617
|
+
install_frame_hook();
|
|
618
|
+
|
|
465
619
|
PyObject *builtins = PyEval_GetBuiltins();
|
|
466
|
-
if (!builtins) { Py_DECREF(code_obj); return NULL; }
|
|
620
|
+
if (!builtins) { restore_frame_hook(); Py_DECREF(code_obj); return NULL; }
|
|
467
621
|
|
|
468
622
|
PyObject *globals = PyDict_New();
|
|
469
|
-
if (!globals) { Py_DECREF(code_obj); return NULL; }
|
|
623
|
+
if (!globals) { restore_frame_hook(); Py_DECREF(code_obj); return NULL; }
|
|
470
624
|
|
|
471
625
|
PyDict_SetItemString(globals, "__builtins__", builtins);
|
|
472
626
|
|
|
473
627
|
PyObject *result = PyEval_EvalCode((PyObject*)code_obj, globals, globals);
|
|
628
|
+
|
|
629
|
+
/* Restore frame hook */
|
|
630
|
+
restore_frame_hook();
|
|
631
|
+
|
|
632
|
+
/* Wipe all decrypted bytecodes from memory */
|
|
633
|
+
wipe_code_tree(code_obj);
|
|
634
|
+
|
|
474
635
|
Py_DECREF(code_obj);
|
|
475
636
|
Py_DECREF(globals);
|
|
476
637
|
|
|
@@ -489,6 +650,11 @@ static PyObject* engine_decrypt_and_get_code(PyObject *self, PyObject *args) {
|
|
|
489
650
|
if (!PyArg_ParseTuple(args, "y#", &data, &data_len))
|
|
490
651
|
return NULL;
|
|
491
652
|
|
|
653
|
+
if (deep_anti_debug() || deep_anti_hook() || deep_anti_decode()) {
|
|
654
|
+
PyErr_SetString(PyExc_RuntimeError, "Tamper detected");
|
|
655
|
+
return NULL;
|
|
656
|
+
}
|
|
657
|
+
|
|
492
658
|
uint8_t iv[12];
|
|
493
659
|
uint8_t *plain = NULL;
|
|
494
660
|
size_t plain_len = 0;
|
|
@@ -554,14 +720,14 @@ static PyObject* engine_decrypt_and_get_code(PyObject *self, PyObject *args) {
|
|
|
554
720
|
/* ------------------------------------------------------------------ */
|
|
555
721
|
|
|
556
722
|
static PyMethodDef EngineMethods[] = {
|
|
557
|
-
{"decrypt_and_exec", engine_decrypt_and_exec, METH_VARARGS, "Decrypt
|
|
723
|
+
{"decrypt_and_exec", engine_decrypt_and_exec, METH_VARARGS, "Decrypt+execute with frame hook + anti-tamper + memory wipe."},
|
|
558
724
|
{"decrypt_and_get_code", engine_decrypt_and_get_code, METH_VARARGS, "Decrypt and return code object."},
|
|
559
725
|
{NULL, NULL, 0, NULL}
|
|
560
726
|
};
|
|
561
727
|
|
|
562
728
|
static struct PyModuleDef enginemodule = {
|
|
563
729
|
PyModuleDef_HEAD_INIT, "engine_c",
|
|
564
|
-
"pyprotect-v4 engine -
|
|
730
|
+
"pyprotect-v4 engine - frame hook, anti-tamper, anti-dump",
|
|
565
731
|
-1, EngineMethods
|
|
566
732
|
};
|
|
567
733
|
|
|
@@ -21,36 +21,13 @@ except ImportError:
|
|
|
21
21
|
EMBEDDED_KEY = b'\xa1\xb2\xc3\xd4\xe5\xf6\x07\x18\x29\x3a\x4b\x5c\x6d\x7e\x8f\x90\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10'
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
BOOTSTRAP_TEMPLATE = '''
|
|
25
|
-
import
|
|
26
|
-
import os
|
|
27
|
-
|
|
28
|
-
{payload_var} = {payload!r}
|
|
29
|
-
|
|
30
|
-
def _exec_protected():
|
|
31
|
-
import importlib.util
|
|
32
|
-
_d = os.path.dirname(os.path.abspath(__file__))
|
|
33
|
-
for _f in os.listdir(_d):
|
|
34
|
-
if _f.startswith('engine_c') and any(_f.endswith(e) for e in ('.so', '.pyd', '.dll')):
|
|
35
|
-
_spec = importlib.util.spec_from_file_location('engine_c', os.path.join(_d, _f))
|
|
36
|
-
if _spec:
|
|
37
|
-
_mod = importlib.util.module_from_spec(_spec)
|
|
38
|
-
_spec.loader.exec_module(_mod)
|
|
39
|
-
return _mod.decrypt_and_exec({payload_var})
|
|
40
|
-
from pyprotect.engine_c import decrypt_and_exec as _e
|
|
41
|
-
return _e({payload_var})
|
|
42
|
-
|
|
43
|
-
if __name__ == "__main__":
|
|
44
|
-
try:
|
|
45
|
-
_exec_protected()
|
|
46
|
-
except BaseException:
|
|
47
|
-
sys.stderr.write("[-] C engine not available. Install pyprotect-v3 with C extension.\\n")
|
|
48
|
-
sys.exit(1)
|
|
49
|
-
'''
|
|
24
|
+
BOOTSTRAP_TEMPLATE = '''# PyProtect-v3 | github.com/PyProtect/PyProtect
|
|
25
|
+
from pyprotect.engine_c import decrypt_and_exec; decrypt_and_exec({payload!r})'''
|
|
50
26
|
|
|
51
27
|
MULTI_BOOTSTRAP_TEMPLATE = '''"""Protected package - generated by pyprotect-v3 v{version}."""
|
|
52
28
|
import sys
|
|
53
29
|
import os
|
|
30
|
+
|
|
54
31
|
import importlib.abc
|
|
55
32
|
import importlib.machinery
|
|
56
33
|
import types
|
|
@@ -288,41 +265,9 @@ def _add_junk_imports(tree):
|
|
|
288
265
|
# ---------------------------------------------------------------------------
|
|
289
266
|
|
|
290
267
|
def _generate_polymorphic_stub(payload_expr: str) -> str:
|
|
291
|
-
"""Generate a
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
stub = f'''"""Protected - {base64.b64encode(os.urandom(8)).decode()}"""
|
|
296
|
-
import sys
|
|
297
|
-
import os
|
|
298
|
-
|
|
299
|
-
{pname} = {payload_expr}
|
|
300
|
-
|
|
301
|
-
if __name__ == "__main__":
|
|
302
|
-
try:
|
|
303
|
-
import importlib.util
|
|
304
|
-
_d = os.path.dirname(os.path.abspath(__file__))
|
|
305
|
-
_ok = False
|
|
306
|
-
for _f in os.listdir(_d):
|
|
307
|
-
if _f.startswith('engine_c') and any(_f.endswith(e) for e in ('.so', '.pyd', '.dll')):
|
|
308
|
-
_spec = importlib.util.spec_from_file_location('engine_c', os.path.join(_d, _f))
|
|
309
|
-
if _spec:
|
|
310
|
-
_mod = importlib.util.module_from_spec(_spec)
|
|
311
|
-
_spec.loader.exec_module(_mod)
|
|
312
|
-
_mod.decrypt_and_exec({pname})
|
|
313
|
-
_ok = True
|
|
314
|
-
break
|
|
315
|
-
if not _ok:
|
|
316
|
-
from pyprotect.engine_c import decrypt_and_exec as _e
|
|
317
|
-
_e({pname})
|
|
318
|
-
_ok = True
|
|
319
|
-
except SystemExit:
|
|
320
|
-
raise
|
|
321
|
-
except BaseException:
|
|
322
|
-
if not _ok:
|
|
323
|
-
sys.stderr.write("[-] C engine not available. Install pyprotect-v3 with C extension.\\n")
|
|
324
|
-
sys.exit(1)
|
|
325
|
-
'''
|
|
268
|
+
"""Generate a compact stub. No key in stub — key is in .so binary."""
|
|
269
|
+
stub = f'''# PyProtect-v3 | github.com/PyProtect/PyProtect
|
|
270
|
+
from pyprotect.engine_c import decrypt_and_exec; decrypt_and_exec({payload_expr})'''
|
|
326
271
|
return stub
|
|
327
272
|
|
|
328
273
|
# ---------------------------------------------------------------------------
|
|
@@ -434,7 +379,7 @@ class Obfuscator:
|
|
|
434
379
|
|
|
435
380
|
# Generate multi bootstrap
|
|
436
381
|
bootstrap_source = MULTI_BOOTSTRAP_TEMPLATE.format(
|
|
437
|
-
version="3.
|
|
382
|
+
version="3.1.0",
|
|
438
383
|
modules=modules,
|
|
439
384
|
)
|
|
440
385
|
|
|
@@ -467,14 +412,12 @@ class Obfuscator:
|
|
|
467
412
|
)
|
|
468
413
|
os.makedirs(output_dir, exist_ok=True)
|
|
469
414
|
|
|
470
|
-
payload_var = random.choice(string.ascii_letters) + "_" + base64.b16encode(os.urandom(6)).decode()
|
|
471
415
|
if self.polymorphic:
|
|
472
416
|
stub_source = _generate_polymorphic_stub(repr(encrypted))
|
|
473
417
|
else:
|
|
474
418
|
stub_source = BOOTSTRAP_TEMPLATE.format(
|
|
475
|
-
version="3.
|
|
419
|
+
version="3.1.0",
|
|
476
420
|
payload=encrypted,
|
|
477
|
-
payload_var=f"_{payload_var}",
|
|
478
421
|
)
|
|
479
422
|
|
|
480
423
|
stub_name = original_filename.replace(".py", "_protected.py")
|
|
@@ -485,8 +428,6 @@ class Obfuscator:
|
|
|
485
428
|
|
|
486
429
|
os.chmod(stub_path, 0o755)
|
|
487
430
|
|
|
488
|
-
self._copy_engine(output_dir)
|
|
489
|
-
|
|
490
431
|
return stub_path
|
|
491
432
|
|
|
492
433
|
def _copy_engine(self, output_dir: str):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|