pylockware 2.0.0__py3-none-any.whl

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 (59) hide show
  1. pylockware/__init__.py +79 -0
  2. pylockware/anti_debug/__init__.py +15 -0
  3. pylockware/anti_debug/antidebug_crossplatform.py +508 -0
  4. pylockware/anti_debug/antidebug_llvm.py +1001 -0
  5. pylockware/cli/__init__.py +3 -0
  6. pylockware/cli/build.py +173 -0
  7. pylockware/cli/main.py +129 -0
  8. pylockware/core/__init__.py +9 -0
  9. pylockware/core/module_base.py +69 -0
  10. pylockware/core/module_manager.py +98 -0
  11. pylockware/core/name_generator.py +72 -0
  12. pylockware/core/obfuscator.py +321 -0
  13. pylockware/decorators.py +101 -0
  14. pylockware/gui/__init__.py +3 -0
  15. pylockware/gui/main.py +28 -0
  16. pylockware/gui/obfuscator_gui.py +789 -0
  17. pylockware/modules/__init__.py +19 -0
  18. pylockware/modules/anti_debug_module.py +123 -0
  19. pylockware/modules/builtin_dispatcher_module.py +214 -0
  20. pylockware/modules/call_obf_module.py +298 -0
  21. pylockware/modules/decorator_obf_module.py +71 -0
  22. pylockware/modules/disable_traceback_module.py +97 -0
  23. pylockware/modules/import_obf_module.py +189 -0
  24. pylockware/modules/junk_code_module.py +82 -0
  25. pylockware/modules/nuitka_builder_module.py +502 -0
  26. pylockware/modules/number_obf_module.py +92 -0
  27. pylockware/modules/remap_module.py +328 -0
  28. pylockware/modules/remove_annotations_module.py +197 -0
  29. pylockware/modules/state_machine_module.py +100 -0
  30. pylockware/modules/string_protect_module.py +73 -0
  31. pylockware/modules/type_annotation_obf_module.py +71 -0
  32. pylockware/modules/virtualization_module.py +410 -0
  33. pylockware/sdk/__init__.py +19 -0
  34. pylockware/sdk/builder.py +228 -0
  35. pylockware/sdk/config.py +477 -0
  36. pylockware/transforms/__init__.py +10 -0
  37. pylockware/transforms/annotation_aware_transformer.py +123 -0
  38. pylockware/transforms/builtin_dispatcher.py +197 -0
  39. pylockware/transforms/decorator_obf.py +195 -0
  40. pylockware/transforms/junk_code_transformer.py +703 -0
  41. pylockware/transforms/num_obf.py +560 -0
  42. pylockware/transforms/remap_transformer.py +234 -0
  43. pylockware/transforms/state_machine_transformer.py +962 -0
  44. pylockware/transforms/str_prot.py +383 -0
  45. pylockware/transforms/type_annotation_obf.py +181 -0
  46. pylockware/vendor/__init__.py +3 -0
  47. pylockware/vendor/customvm/README.md +27 -0
  48. pylockware/vendor/customvm/__init__.py +8 -0
  49. pylockware/vendor/customvm/builder.py +293 -0
  50. pylockware/vendor/customvm/compiler.py +970 -0
  51. pylockware/vendor/customvm/crypto.py +84 -0
  52. pylockware/vendor/customvm/loader.py +167 -0
  53. pylockware/vendor/customvm/opcodes.py +97 -0
  54. pylockware/vendor/customvm/vm.py +554 -0
  55. pylockware-2.0.0.dist-info/METADATA +644 -0
  56. pylockware-2.0.0.dist-info/RECORD +59 -0
  57. pylockware-2.0.0.dist-info/WHEEL +5 -0
  58. pylockware-2.0.0.dist-info/entry_points.txt +6 -0
  59. pylockware-2.0.0.dist-info/top_level.txt +1 -0
pylockware/__init__.py ADDED
@@ -0,0 +1,79 @@
1
+ """
2
+ PyLockWare - Python Code Protection SDK
3
+ A comprehensive SDK for protecting Python code with multiple obfuscation layers.
4
+
5
+ Usage:
6
+ # Using decorators
7
+ from pylockware import external, skip_obf, virtualize
8
+
9
+ @external
10
+ def public_api():
11
+ pass
12
+
13
+ @skip_obf
14
+ def debug_function():
15
+ pass
16
+
17
+ @virtualize
18
+ def secret_algorithm():
19
+ # Converted to CustomVM bytecode
20
+ pass
21
+
22
+ # Using SDK
23
+ from pylockware.sdk import Builder, BuildConfig
24
+
25
+ config = BuildConfig(entry_point="main.py", virtualization=True)
26
+ builder = Builder(config)
27
+ builder.build()
28
+
29
+ # Using pyproject.toml
30
+ from pylockware.sdk import Builder
31
+
32
+ builder = Builder.from_pyproject()
33
+ builder.build()
34
+ """
35
+
36
+ # Core components
37
+ from .core import ModuleBase, PyObfuscator
38
+
39
+ # Modules
40
+ from .modules import (
41
+ RemapModule,
42
+ StringProtectModule,
43
+ NumberObfModule,
44
+ AntiDebugModule,
45
+ ImportObfuscateModule,
46
+ StateMachineModule
47
+ )
48
+
49
+ # SDK components
50
+ from .decorators import external, skip_obf, preserve_name, virtualize
51
+ from .sdk import Builder, BuildConfig, load_config, save_config, init_config
52
+
53
+ __version__ = "3.0.0"
54
+ __all__ = [
55
+ # Core
56
+ 'ModuleBase',
57
+ 'PyObfuscator',
58
+
59
+ # Modules
60
+ 'RemapModule',
61
+ 'StringProtectModule',
62
+ 'NumberObfModule',
63
+ 'AntiDebugModule',
64
+ 'ImportObfuscateModule',
65
+ 'StateMachineModule',
66
+
67
+ # SDK
68
+ 'Builder',
69
+ 'BuildConfig',
70
+ 'load_config',
71
+ 'save_config',
72
+ 'init_config',
73
+
74
+ # Decorators
75
+ 'external',
76
+ 'skip_obf',
77
+ 'preserve_name',
78
+ 'virtualize',
79
+ ]
@@ -0,0 +1,15 @@
1
+ """
2
+ PyLockWare Anti-Debug Module
3
+ """
4
+
5
+ from pylockware.anti_debug.antidebug_llvm import AntiDebugEngine, init, check, guard, monitor
6
+ from pylockware.anti_debug.antidebug_crossplatform import AntiDebugCrossPlatform
7
+
8
+ __all__ = [
9
+ 'AntiDebugEngine',
10
+ 'AntiDebugCrossPlatform',
11
+ 'init',
12
+ 'check',
13
+ 'guard',
14
+ 'monitor',
15
+ ]
@@ -0,0 +1,508 @@
1
+ """
2
+ PyLockWare AntiDebug Engine (Cross-Platform)
3
+ =============================================
4
+ Кроссплатформенный антиотладочный модуль для Python.
5
+ Работает на Windows, Linux и macOS.
6
+
7
+ Проверки:
8
+ 1. Python-отладчики — sys.gettrace, sys.monitoring, загруженные модули
9
+ 2. Python-потоки — поиск потоков отладчиков (pydevd, debugpy)
10
+ 3. Переменные окружения — PYTHONDEBUG, PYTHONTRACEMODULESHACK и т.д.
11
+ 4. Файловые дескрипторы — обнаружение отладочных сокетов
12
+ 5. procfs (Linux) — /proc/self/status, /proc/self/wchan
13
+ 6. lsof/netstat — поиск отладочных портов
14
+
15
+ При срабатывании любой проверки — выводит причину в stderr и вызывает os._exit(1).
16
+
17
+ Зависимости: psutil (опционально для расширенных проверок)
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import ctypes
23
+ import os
24
+ import platform
25
+ import re
26
+ import socket
27
+ import sys
28
+ import threading
29
+ import time
30
+ from dataclasses import dataclass, field
31
+ from typing import List, Set, Optional
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Python C-API для callback (печать причины + выход)
35
+ # ---------------------------------------------------------------------------
36
+
37
+ _PySys_WriteStderr = ctypes.pythonapi.PySys_WriteStderr
38
+ _PySys_WriteStderr.argtypes = [ctypes.c_char_p]
39
+ _PySys_WriteStderr.restype = None
40
+
41
+ _os_exit = os._exit
42
+
43
+
44
+ def _native_kill(reason: str) -> None:
45
+ """Вызывается при обнаружении отладчика/инжекции."""
46
+ msg = (
47
+ f"\n[ANTIDEBUG] VIOLATION DETECTED\n"
48
+ f"[ANTIDEBUG] Reason: {reason}\n"
49
+ f"[ANTIDEBUG] Terminating process...\n"
50
+ )
51
+ _PySys_WriteStderr(msg.encode('utf-8'))
52
+ _os_exit(1)
53
+
54
+
55
+ # ---------------------------------------------------------------------------
56
+ # Dataclasses
57
+ # ---------------------------------------------------------------------------
58
+
59
+ @dataclass
60
+ class Violation:
61
+ check_name: str
62
+ reason: str
63
+ details: dict = field(default_factory=dict)
64
+
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # Cross-Platform AntiDebug Engine
68
+ # ---------------------------------------------------------------------------
69
+
70
+ class AntiDebugCrossPlatform:
71
+ """
72
+ Кроссплатформенный движок антиотладки.
73
+ Работает на Windows, Linux, macOS.
74
+ """
75
+
76
+ # Чёрный список DLL/модулей — известные отладчики/инжекторы
77
+ BLACKLIST_MODULES: Set[str] = {
78
+ # Python debuggers
79
+ "pydevd",
80
+ "pydevd_cython",
81
+ "pydevd_pep_669_tracing_cython",
82
+ "debugpy",
83
+ "_pydevd_bundle",
84
+ "pydevd_plugins",
85
+ "pydevd_xml",
86
+ # Native debuggers / analysis tools
87
+ "frida",
88
+ "frida-gadget",
89
+ "libinjector",
90
+ "x64dbg",
91
+ "x32dbg",
92
+ "ollydbg",
93
+ "cheatengine",
94
+ # Injection frameworks
95
+ "pyshell",
96
+ "reflectivedll",
97
+ "sliver",
98
+ "meterpreter",
99
+ }
100
+
101
+ # Чёрный список имён потоков
102
+ BLACKLIST_THREAD_NAMES: Set[str] = {
103
+ "pydevd.Writer",
104
+ "pydevd.Reader",
105
+ "pydevd.CommandThread",
106
+ "pydevd.CheckAliveThread",
107
+ "pydevd.SuspendThread",
108
+ "pydevd.BreakpointWatchThread",
109
+ "debugpy",
110
+ "debugpy.server",
111
+ }
112
+
113
+ # Подозрительные переменные окружения
114
+ SUSPICIOUS_ENV_VARS: Set[str] = {
115
+ "PYTHONDEBUG",
116
+ "PYTHONTRACEMODULESHACK",
117
+ "PYTHONTRACEBACK",
118
+ "PYTHONVERBOSE",
119
+ "PYTHONDUMPREFS",
120
+ "PYTHONDUMPAST",
121
+ "PYTHONASYNCIODEBUG",
122
+ "PYTHONMALLOCSTATS",
123
+ "LD_PRELOAD",
124
+ "LD_DEBUG",
125
+ "DYLD_INSERT_LIBRARIES",
126
+ "DYLD_DEBUG",
127
+ }
128
+
129
+ def __init__(self, strict: bool = True):
130
+ self.strict = strict
131
+ self.violations: List[Violation] = []
132
+ self._baseline_threads: Set[int] = set()
133
+ self._lock = threading.Lock()
134
+
135
+ # Захватываем baseline при инициализации
136
+ self._capture_baseline()
137
+
138
+ def _capture_baseline(self):
139
+ """Запоминаем начальный набор потоков как легитимный."""
140
+ self._baseline_threads = {t.ident for t in threading.enumerate() if t.ident}
141
+
142
+ # ------------------------------------------------------------------
143
+ # Python-level checks
144
+ # ------------------------------------------------------------------
145
+
146
+ def check_python_debugger(self) -> List[Violation]:
147
+ """Эвристики Python-level отладчиков."""
148
+ results: List[Violation] = []
149
+
150
+ # 1. sys.gettrace() — классический способ отладки
151
+ if hasattr(sys, 'gettrace') and sys.gettrace() is not None:
152
+ results.append(Violation(
153
+ "PythonTrace",
154
+ "sys.gettrace() is active — Python-level debugger detected",
155
+ {"trace_function": str(sys.gettrace())}
156
+ ))
157
+
158
+ # 2. sys.monitoring (Python 3.12+ PEP 669)
159
+ if hasattr(sys, 'monitoring') and sys.monitoring:
160
+ try:
161
+ if sys.monitoring.get_tool(sys.monitoring.DEBUGGER_ID) is not None:
162
+ results.append(Violation(
163
+ "PEP669Debugger",
164
+ "sys.monitoring DEBUGGER_ID tool is active"
165
+ ))
166
+ except (AttributeError, ValueError):
167
+ pass
168
+
169
+ # 3. sys.settrace (альтернативный API)
170
+ if hasattr(sys, 'gettrace') and sys.gettrace() is not None:
171
+ # Уже проверено выше, но для полноты
172
+ pass
173
+
174
+ # 4. Проверяем загруженные модули
175
+ current_modules = set(sys.modules.keys())
176
+ for mod in current_modules:
177
+ mod_lower = mod.lower()
178
+ for bad in self.BLACKLIST_MODULES:
179
+ if bad in mod_lower:
180
+ results.append(Violation(
181
+ "BlacklistedModule",
182
+ f"Forbidden debugger/injector module loaded: {mod}",
183
+ {"module": mod, "pattern": bad}
184
+ ))
185
+
186
+ # 5. Проверяем Python-потоки
187
+ for t in threading.enumerate():
188
+ if t.name in self.BLACKLIST_THREAD_NAMES:
189
+ results.append(Violation(
190
+ "BlacklistedThread",
191
+ f"Forbidden debugger thread detected: {t.name}",
192
+ {"thread_name": t.name, "tid": t.ident}
193
+ ))
194
+
195
+ return results
196
+
197
+ def check_environment(self) -> List[Violation]:
198
+ """Проверка подозрительных переменных окружения."""
199
+ results: List[Violation] = []
200
+
201
+ for var in self.SUSPICIOUS_ENV_VARS:
202
+ value = os.environ.get(var)
203
+ if value is not None:
204
+ # Для LD_PRELOAD/DYLD_INSERT_LIBRARIES — проверим конкретные значения
205
+ if var in ("LD_PRELOAD", "DYLD_INSERT_LIBRARIES"):
206
+ # Проверяем на известные инжекторы
207
+ injectors = ["libinjector", "frida", "preload"]
208
+ if any(inj in value.lower() for inj in injectors):
209
+ results.append(Violation(
210
+ "SuspiciousEnvVar",
211
+ f"Suspicious library preloaded: {var}={value}",
212
+ {"variable": var, "value": value}
213
+ ))
214
+ else:
215
+ results.append(Violation(
216
+ "SuspiciousEnvVar",
217
+ f"Suspicious environment variable detected: {var}={value}",
218
+ {"variable": var, "value": value}
219
+ ))
220
+
221
+ return results
222
+
223
+ def check_threads(self) -> List[Violation]:
224
+ """Обнаружение новых подозрительных потоков."""
225
+ results: List[Violation] = []
226
+ current_threads = {t.ident for t in threading.enumerate() if t.ident}
227
+ new_threads = current_threads - self._baseline_threads
228
+
229
+ # Получаем имена известных потоков
230
+ known_thread_names = {t.name for t in threading.enumerate()}
231
+
232
+ for tid in new_threads:
233
+ # Проверяем, не является ли это потоком отладчика
234
+ for t in threading.enumerate():
235
+ if t.ident == tid:
236
+ if t.name in self.BLACKLIST_THREAD_NAMES:
237
+ results.append(Violation(
238
+ "NewDebuggerThread",
239
+ f"New debugger thread detected: {t.name}",
240
+ {"thread_name": t.name, "tid": tid}
241
+ ))
242
+ break
243
+
244
+ # Обновляем baseline
245
+ self._baseline_threads = current_threads
246
+ return results
247
+
248
+ def check_network(self) -> List[Violation]:
249
+ """Проверка открытых сокетов на отладочные порты."""
250
+ results: List[Violation] = []
251
+
252
+ # Известные отладочные порты
253
+ DEBUGGER_PORTS = {
254
+ 5678, # debugpy default
255
+ 5679,
256
+ 5680,
257
+ 5681,
258
+ 12345, # pydevd default
259
+ 12346,
260
+ 4444, # common debug port
261
+ 5005, # Java debugger
262
+ }
263
+
264
+ try:
265
+ # Получаем все открытые сокеты
266
+ import psutil
267
+ for conn in psutil.net_connections(kind='inet'):
268
+ if conn.status == 'LISTEN' and conn.laddr.port in DEBUGGER_PORTS:
269
+ results.append(Violation(
270
+ "DebuggerPort",
271
+ f"Debugger listening port detected: {conn.laddr.port}",
272
+ {"port": conn.laddr.port, "address": conn.laddr.ip}
273
+ ))
274
+ except (ImportError, Exception):
275
+ # psutil недоступен — пропускаем
276
+ pass
277
+
278
+ return results
279
+
280
+ def check_procfs_linux(self) -> List[Violation]:
281
+ """Проверка /proc файловой системы (Linux only)."""
282
+ results: List[Violation] = []
283
+
284
+ if platform.system() != 'Linux':
285
+ return results
286
+
287
+ try:
288
+ # Проверяем /proc/self/status на флаги отладки
289
+ with open('/proc/self/status', 'r') as f:
290
+ content = f.read()
291
+
292
+ # TracerPid — если не 0, значит нас отслеживают
293
+ match = re.search(r'TracerPid:\s*(\d+)', content)
294
+ if match and int(match.group(1)) != 0:
295
+ results.append(Violation(
296
+ "LinuxTracerPid",
297
+ f"TracerPid is non-zero: {match.group(1)} — process is being traced",
298
+ {"tracer_pid": match.group(1)}
299
+ ))
300
+
301
+ # Seccomp — если 1 или 2, может указывать на sandbox
302
+ match = re.search(r'Seccomp:\s*(\d+)', content)
303
+ if match and int(match.group(1)) in (1, 2):
304
+ results.append(Violation(
305
+ "LinuxSeccomp",
306
+ f"Seccomp mode detected: {match.group(1)}",
307
+ {"seccomp_mode": match.group(1)}
308
+ ))
309
+
310
+ # Проверяем /proc/self/wchan — если не 0, поток может быть в отладчике
311
+ try:
312
+ with open('/proc/self/wchan', 'r') as f:
313
+ wchan = f.read().strip()
314
+ # 0 означает, что процесс остановлен отладчиком
315
+ if wchan == '0':
316
+ results.append(Violation(
317
+ "LinuxWchan",
318
+ "Process is stopped (ptraced)"
319
+ ))
320
+ except (FileNotFoundError, PermissionError):
321
+ pass
322
+
323
+ except (FileNotFoundError, PermissionError, IOError):
324
+ pass
325
+
326
+ return results
327
+
328
+ def check_virtualization(self) -> List[Violation]:
329
+ """Проверка на виртуальные машины и контейнеры."""
330
+ results: List[Violation] = []
331
+
332
+ # Проверяем VM/контейнерные индикаторы
333
+ indicators = []
334
+
335
+ if platform.system() == 'Linux':
336
+ # /proc/1/cgroup — если содержит docker/lxc, то в контейнере
337
+ try:
338
+ with open('/proc/1/cgroup', 'r') as f:
339
+ cgroup = f.read()
340
+ if 'docker' in cgroup or 'lxc' in cgroup or 'containerd' in cgroup:
341
+ indicators.append(f"Container: {cgroup[:100]}")
342
+ except:
343
+ pass
344
+
345
+ # /proc/self/root — если отличается от /, то chroot
346
+ try:
347
+ import os
348
+ if os.readlink('/proc/self/root') != '/':
349
+ indicators.append("Chroot detected")
350
+ except:
351
+ pass
352
+
353
+ elif platform.system() == 'Windows':
354
+ # Проверяем реестр на VM
355
+ try:
356
+ import winreg
357
+ key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
358
+ r"SYSTEM\CurrentControlSet\Services\VBoxGuest")
359
+ indicators.append("VirtualBox detected")
360
+ winreg.CloseKey(key)
361
+ except FileNotFoundError:
362
+ pass
363
+
364
+ try:
365
+ key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
366
+ r"SYSTEM\CurrentControlSet\Services\VBoxMouse")
367
+ indicators.append("VirtualBox detected")
368
+ winreg.CloseKey(key)
369
+ except FileNotFoundError:
370
+ pass
371
+
372
+ if indicators:
373
+ results.append(Violation(
374
+ "Virtualization",
375
+ f"Virtualization or container detected: {', '.join(indicators)}",
376
+ {"indicators": indicators}
377
+ ))
378
+
379
+ return results
380
+
381
+ # ------------------------------------------------------------------
382
+ # Orchestration
383
+ # ------------------------------------------------------------------
384
+
385
+ def run_all_checks(self) -> List[Violation]:
386
+ """Выполняет все проверки и возвращает список нарушений."""
387
+ all_violations: List[Violation] = []
388
+
389
+ checks = [
390
+ ("PythonDebugger", self.check_python_debugger),
391
+ ("Environment", self.check_environment),
392
+ ("Threads", self.check_threads),
393
+ ("Network", self.check_network),
394
+ ("ProcFS", self.check_procfs_linux),
395
+ ("Virtualization", self.check_virtualization),
396
+ ]
397
+
398
+ for check_name, check_func in checks:
399
+ try:
400
+ violations = check_func()
401
+ all_violations.extend(violations)
402
+ except Exception as e:
403
+ if self.strict:
404
+ all_violations.append(Violation(
405
+ f"{check_name}CheckError",
406
+ f"{check_name} check failed: {e}"
407
+ ))
408
+
409
+ return all_violations
410
+
411
+ def kill_if_violations(self, violations: Optional[List[Violation]] = None):
412
+ """Если есть нарушения — печатает причину и убивает процесс."""
413
+ if violations is None:
414
+ violations = self.run_all_checks()
415
+
416
+ if not violations:
417
+ return
418
+
419
+ with self._lock:
420
+ lines = [
421
+ "",
422
+ "=" * 70,
423
+ " ANTIDEBUG VIOLATION — PROCESS WILL BE TERMINATED",
424
+ "=" * 70,
425
+ f" Total violations: {len(violations)}",
426
+ "",
427
+ ]
428
+
429
+ for i, v in enumerate(violations, 1):
430
+ lines.append(f" [{i}] {v.check_name}")
431
+ lines.append(f" Reason: {v.reason}")
432
+ if v.details:
433
+ for k, val in v.details.items():
434
+ lines.append(f" {k}: {val}")
435
+ lines.append("")
436
+
437
+ lines.append("=" * 70)
438
+ lines.append(" Terminating with os._exit(1)")
439
+ lines.append("=" * 70)
440
+
441
+ report = "\n".join(lines) + "\n"
442
+ _PySys_WriteStderr(report.encode('utf-8'))
443
+ time.sleep(0.1)
444
+ os._exit(1)
445
+
446
+ def start_monitoring(self, interval_ms: float = 500):
447
+ """Запускает фоновый мониторинг в отдельном потоке."""
448
+ def _monitor():
449
+ while True:
450
+ self.kill_if_violations()
451
+ time.sleep(interval_ms / 1000.0)
452
+
453
+ t = threading.Thread(target=_monitor, name="AntiDebugMonitor", daemon=True)
454
+ t.start()
455
+ return t
456
+
457
+
458
+ # ---------------------------------------------------------------------------
459
+ # Convenience API
460
+ # ---------------------------------------------------------------------------
461
+
462
+ _engine: Optional[AntiDebugCrossPlatform] = None
463
+
464
+
465
+ def init(strict: bool = True) -> AntiDebugCrossPlatform:
466
+ """Инициализирует движок (один на процесс)."""
467
+ global _engine
468
+ if _engine is None:
469
+ _engine = AntiDebugCrossPlatform(strict=strict)
470
+ return _engine
471
+
472
+
473
+ def check() -> List[Violation]:
474
+ """Однократная проверка."""
475
+ return init().run_all_checks()
476
+
477
+
478
+ def guard():
479
+ """Проверить и убить процесс при нарушениях."""
480
+ init().kill_if_violations()
481
+
482
+
483
+ def monitor(interval_ms: float = 500):
484
+ """Запустить фоновый мониторинг."""
485
+ return init().start_monitoring(interval_ms)
486
+
487
+
488
+ # ---------------------------------------------------------------------------
489
+ # CLI / standalone
490
+ # ---------------------------------------------------------------------------
491
+
492
+ if __name__ == "__main__":
493
+ print(f"[PyLockWare AntiDebug] Running self-test on {platform.system()}...")
494
+ print(f"[PyLockWare AntiDebug] PID: {os.getpid()}")
495
+ engine = init(strict=True)
496
+
497
+ violations = engine.run_all_checks()
498
+ if violations:
499
+ print(f"[PyLockWare AntiDebug] Found {len(violations)} violations!")
500
+ for v in violations:
501
+ print(f" - {v.check_name}: {v.reason}")
502
+ else:
503
+ print("[PyLockWare AntiDebug] No violations detected")
504
+
505
+ print("[PyLockWare AntiDebug] Starting monitoring...")
506
+ monitor(interval_ms=500)
507
+ print("[PyLockWare AntiDebug] Monitoring started. Press Enter to exit...")
508
+ input()