PyProtect-v3 3.0.0__tar.gz → 3.2.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.
Files changed (21) hide show
  1. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/PKG-INFO +1 -1
  2. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/PyProtect_v3.egg-info/PKG-INFO +1 -1
  3. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/PyProtect_v3.egg-info/SOURCES.txt +0 -1
  4. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/pyproject.toml +1 -1
  5. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/pyprotect/__main__.py +0 -2
  6. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/pyprotect/engine.c +242 -6
  7. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/pyprotect/obfuscator.py +11 -74
  8. pyprotect_v3-3.0.0/pyprotect/_key.py +0 -2
  9. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/MANIFEST.in +0 -0
  10. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/PyProtect_v3.egg-info/dependency_links.txt +0 -0
  11. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/PyProtect_v3.egg-info/entry_points.txt +0 -0
  12. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/PyProtect_v3.egg-info/requires.txt +0 -0
  13. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/PyProtect_v3.egg-info/top_level.txt +0 -0
  14. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/README.md +0 -0
  15. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/pyprotect/__init__.py +0 -0
  16. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/pyprotect/anti_debug.py +0 -0
  17. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/pyprotect/crypto.py +0 -0
  18. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/pyprotect/engine.py +0 -0
  19. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/pyprotect/hooks.py +0 -0
  20. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/setup.cfg +0 -0
  21. {pyprotect_v3-3.0.0 → pyprotect_v3-3.2.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyProtect-v3
3
- Version: 3.0.0
3
+ Version: 3.2.0
4
4
  Summary: Python script obfuscation library with AES-256-GCM encryption and C extension acceleration
5
5
  Author-email: NguyenNgocNam <c.nam020213@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyProtect-v3
3
- Version: 3.0.0
3
+ Version: 3.2.0
4
4
  Summary: Python script obfuscation library with AES-256-GCM encryption and C extension acceleration
5
5
  Author-email: NguyenNgocNam <c.nam020213@gmail.com>
6
6
  License-Expression: MIT
@@ -10,7 +10,6 @@ PyProtect_v3.egg-info/requires.txt
10
10
  PyProtect_v3.egg-info/top_level.txt
11
11
  pyprotect/__init__.py
12
12
  pyprotect/__main__.py
13
- pyprotect/_key.py
14
13
  pyprotect/anti_debug.py
15
14
  pyprotect/crypto.py
16
15
  pyprotect/engine.c
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyProtect-v3"
7
- version = "3.0.0"
7
+ version = "3.2.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, "Debugger detected");
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;
@@ -549,19 +715,89 @@ static PyObject* engine_decrypt_and_get_code(PyObject *self, PyObject *args) {
549
715
  return code_obj;
550
716
  }
551
717
 
718
+ /* ------------------------------------------------------------------ */
719
+ /* Encrypt — used by Python obfuscator so key stays in .so only */
720
+ /* ------------------------------------------------------------------ */
721
+
722
+ static PyObject* engine_encrypt(PyObject *self, PyObject *args) {
723
+ const uint8_t *plain;
724
+ Py_ssize_t plain_len;
725
+
726
+ if (!PyArg_ParseTuple(args, "y#", &plain, &plain_len))
727
+ return NULL;
728
+
729
+ uint8_t iv[12];
730
+ size_t ct_len = (size_t)plain_len;
731
+ size_t out_len = 12 + ct_len + 16; /* iv + ct + tag */
732
+ uint8_t *out = (uint8_t*)malloc(out_len);
733
+ if (!out) return PyErr_NoMemory();
734
+
735
+ /* Generate random IV */
736
+ #if defined(PLATFORM_WINDOWS)
737
+ HCRYPTPROV hProv = 0;
738
+ CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
739
+ CryptGenRandom(hProv, 12, iv);
740
+ CryptReleaseContext(hProv, 0);
741
+ #else
742
+ FILE *urandom = fopen("/dev/urandom", "rb");
743
+ if (!urandom) { free(out); PyErr_SetString(PyExc_RuntimeError, "No /dev/urandom"); return NULL; }
744
+ fread(iv, 1, 12, urandom);
745
+ fclose(urandom);
746
+ #endif
747
+
748
+ memcpy(out, iv, 12); /* prepend iv */
749
+
750
+ #if defined(USE_EMBEDDED_AES)
751
+ /* For embedded AES, we'd need aes_gcm_encrypt. Use OpenSSL fallback. */
752
+ free(out);
753
+ PyErr_SetString(PyExc_RuntimeError, "Encryption requires OpenSSL");
754
+ return NULL;
755
+ #else
756
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
757
+ if (!ctx) { free(out); PyErr_NoMemory(); return NULL; }
758
+
759
+ int len, ct_written = 0;
760
+ if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1) goto err;
761
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1) goto err;
762
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, EMBEDDED_KEY, iv) != 1) goto err;
763
+ if (EVP_EncryptUpdate(ctx, NULL, &len, (const uint8_t*)"pyprotect", 9) != 1) goto err; /* AAD */
764
+ if (EVP_EncryptUpdate(ctx, out + 12, &len, plain, (int)ct_len) != 1) goto err;
765
+ ct_written = len;
766
+ if (EVP_EncryptFinal_ex(ctx, out + 12 + ct_written, &len) != 1) goto err;
767
+ ct_written += len;
768
+
769
+ uint8_t tag[16];
770
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) != 1) goto err;
771
+ memcpy(out + 12 + ct_len, tag, 16); /* append tag */
772
+
773
+ EVP_CIPHER_CTX_free(ctx);
774
+ PyObject *result = PyBytes_FromStringAndSize((const char*)out, (Py_ssize_t)out_len);
775
+ free(out);
776
+ return result;
777
+
778
+ err:
779
+ ERR_print_errors_fp(stderr);
780
+ EVP_CIPHER_CTX_free(ctx);
781
+ free(out);
782
+ PyErr_SetString(PyExc_RuntimeError, "Encryption failed");
783
+ return NULL;
784
+ #endif
785
+ }
786
+
552
787
  /* ------------------------------------------------------------------ */
553
788
  /* Module definition */
554
789
  /* ------------------------------------------------------------------ */
555
790
 
556
791
  static PyMethodDef EngineMethods[] = {
557
- {"decrypt_and_exec", engine_decrypt_and_exec, METH_VARARGS, "Decrypt and execute protected payload."},
792
+ {"decrypt_and_exec", engine_decrypt_and_exec, METH_VARARGS, "Decrypt+execute with frame hook + anti-tamper + memory wipe."},
558
793
  {"decrypt_and_get_code", engine_decrypt_and_get_code, METH_VARARGS, "Decrypt and return code object."},
794
+ {"encrypt", engine_encrypt, METH_VARARGS, "Encrypt payload with embedded key."},
559
795
  {NULL, NULL, 0, NULL}
560
796
  };
561
797
 
562
798
  static struct PyModuleDef enginemodule = {
563
799
  PyModuleDef_HEAD_INIT, "engine_c",
564
- "pyprotect-v4 engine - embedded key, anti-debug, anti-dump",
800
+ "pyprotect-v4 engine - frame hook, anti-tamper, anti-dump",
565
801
  -1, EngineMethods
566
802
  };
567
803
 
@@ -14,43 +14,16 @@ import shutil
14
14
  import ast
15
15
  import base64
16
16
 
17
- from pyprotect import crypto
18
- try:
19
- from pyprotect._key import EMBEDDED_KEY
20
- except ImportError:
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'
17
+ from pyprotect.engine_c import encrypt
22
18
 
23
19
 
24
- BOOTSTRAP_TEMPLATE = '''"""Protected script - generated by pyprotect-v3 v{version}."""
25
- import sys
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
- '''
20
+ BOOTSTRAP_TEMPLATE = '''# PyProtect-v3 | github.com/PyProtect/PyProtect
21
+ from pyprotect.engine_c import decrypt_and_exec; decrypt_and_exec({payload!r})'''
50
22
 
51
23
  MULTI_BOOTSTRAP_TEMPLATE = '''"""Protected package - generated by pyprotect-v3 v{version}."""
52
24
  import sys
53
25
  import os
26
+
54
27
  import importlib.abc
55
28
  import importlib.machinery
56
29
  import types
@@ -288,41 +261,9 @@ def _add_junk_imports(tree):
288
261
  # ---------------------------------------------------------------------------
289
262
 
290
263
  def _generate_polymorphic_stub(payload_expr: str) -> str:
291
- """Generate a polymorphic stub. No key in stub — key is in .so binary."""
292
- used = set(_BAD_NAMES)
293
- pname = _random_name(used)
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
- '''
264
+ """Generate a compact stub. No key in stub — key is in .so binary."""
265
+ stub = f'''# PyProtect-v3 | github.com/PyProtect/PyProtect
266
+ from pyprotect.engine_c import decrypt_and_exec; decrypt_and_exec({payload_expr})'''
326
267
  return stub
327
268
 
328
269
  # ---------------------------------------------------------------------------
@@ -375,7 +316,7 @@ class Obfuscator:
375
316
  payload = _marshal_and_compress(code, self.compress)
376
317
 
377
318
  iv = os.urandom(12)
378
- encrypted = crypto.encrypt(EMBEDDED_KEY, payload)
319
+ encrypted = encrypt(payload)
379
320
 
380
321
  filename = os.path.basename(input_path)
381
322
  output = self._build_stub(encrypted, filename)
@@ -429,12 +370,12 @@ class Obfuscator:
429
370
 
430
371
  code = _compile_code(source, os.path.basename(py_file))
431
372
  payload = _marshal_and_compress(code, self.compress)
432
- encrypted = crypto.encrypt(EMBEDDED_KEY, payload)
373
+ encrypted = encrypt(payload)
433
374
  modules[module_name] = encrypted
434
375
 
435
376
  # Generate multi bootstrap
436
377
  bootstrap_source = MULTI_BOOTSTRAP_TEMPLATE.format(
437
- version="3.0.0",
378
+ version="3.2.0",
438
379
  modules=modules,
439
380
  )
440
381
 
@@ -467,14 +408,12 @@ class Obfuscator:
467
408
  )
468
409
  os.makedirs(output_dir, exist_ok=True)
469
410
 
470
- payload_var = random.choice(string.ascii_letters) + "_" + base64.b16encode(os.urandom(6)).decode()
471
411
  if self.polymorphic:
472
412
  stub_source = _generate_polymorphic_stub(repr(encrypted))
473
413
  else:
474
414
  stub_source = BOOTSTRAP_TEMPLATE.format(
475
- version="3.0.0",
415
+ version="3.2.0",
476
416
  payload=encrypted,
477
- payload_var=f"_{payload_var}",
478
417
  )
479
418
 
480
419
  stub_name = original_filename.replace(".py", "_protected.py")
@@ -485,8 +424,6 @@ class Obfuscator:
485
424
 
486
425
  os.chmod(stub_path, 0o755)
487
426
 
488
- self._copy_engine(output_dir)
489
-
490
427
  return stub_path
491
428
 
492
429
  def _copy_engine(self, output_dir: str):
@@ -1,2 +0,0 @@
1
- """Auto-generated. Must match EMBEDDED_KEY in engine.c."""
2
- 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'
File without changes
File without changes
File without changes
File without changes