ctf-agent 1.2.0

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 (152) hide show
  1. package/AGENTS.md +131 -0
  2. package/Dockerfile +192 -0
  3. package/README.md +522 -0
  4. package/agents/ctf-analyzer.md +58 -0
  5. package/agents/ctf-controller.md +151 -0
  6. package/agents/ctf-speedrun.md +74 -0
  7. package/bin/ctf-agent.js +119 -0
  8. package/docker-compose.yml +13 -0
  9. package/mcp_config.json +19 -0
  10. package/package.json +44 -0
  11. package/references/ctf-triage-ladder.md +68 -0
  12. package/references/exploit-databases.md +575 -0
  13. package/references/llm-safety-and-policy-compliance.md +173 -0
  14. package/references/multi-agent-orchestration-and-policy-routing.md +278 -0
  15. package/references/security-events-and-intelligence.md +566 -0
  16. package/references/version-matrix.md +59 -0
  17. package/rules/ctf-execution-rules.md +44 -0
  18. package/rules/ctf-safety-framing-rules.md +140 -0
  19. package/rules/flag-validation-rules.md +25 -0
  20. package/scripts/__init__.py +1 -0
  21. package/scripts/ctf-tools.lock +205 -0
  22. package/scripts/ctf_init.py +1026 -0
  23. package/scripts/ctf_update.py +583 -0
  24. package/scripts/ctfd_client.py +81 -0
  25. package/scripts/cve_lookup.py +453 -0
  26. package/scripts/extract_flags.py +155 -0
  27. package/scripts/install_as_agent.py +278 -0
  28. package/scripts/install_ctf_tools.sh +603 -0
  29. package/scripts/parallel_triage.py +395 -0
  30. package/scripts/prompt_policy_sanitizer.py +283 -0
  31. package/scripts/scope_guard.py +444 -0
  32. package/scripts/skill_validator.py +504 -0
  33. package/scripts/workspace_cleaner.py +141 -0
  34. package/skills/ctf-ai-ml/SKILL.md +120 -0
  35. package/skills/ctf-ai-ml/adversarial-ml.md +623 -0
  36. package/skills/ctf-ai-ml/llm-attacks.md +487 -0
  37. package/skills/ctf-ai-ml/model-attacks.md +422 -0
  38. package/skills/ctf-crypto/SKILL.md +320 -0
  39. package/skills/ctf-crypto/advanced-math.md +798 -0
  40. package/skills/ctf-crypto/classic-ciphers.md +651 -0
  41. package/skills/ctf-crypto/ecc-attacks.md +347 -0
  42. package/skills/ctf-crypto/exotic-crypto-2.md +380 -0
  43. package/skills/ctf-crypto/exotic-crypto.md +528 -0
  44. package/skills/ctf-crypto/historical.md +113 -0
  45. package/skills/ctf-crypto/lattice-and-lwe.md +524 -0
  46. package/skills/ctf-crypto/modern-ciphers-2.md +563 -0
  47. package/skills/ctf-crypto/modern-ciphers-3.md +453 -0
  48. package/skills/ctf-crypto/modern-ciphers.md +649 -0
  49. package/skills/ctf-crypto/prng-attacks.md +257 -0
  50. package/skills/ctf-crypto/prng.md +664 -0
  51. package/skills/ctf-crypto/rsa-attacks-2.md +792 -0
  52. package/skills/ctf-crypto/rsa-attacks.md +487 -0
  53. package/skills/ctf-crypto/stream-ciphers.md +390 -0
  54. package/skills/ctf-crypto/zkp-and-advanced.md +456 -0
  55. package/skills/ctf-forensics/3d-printing.md +121 -0
  56. package/skills/ctf-forensics/SKILL.md +379 -0
  57. package/skills/ctf-forensics/disk-advanced.md +497 -0
  58. package/skills/ctf-forensics/disk-and-memory.md +491 -0
  59. package/skills/ctf-forensics/disk-recovery.md +699 -0
  60. package/skills/ctf-forensics/linux-forensics.md +511 -0
  61. package/skills/ctf-forensics/network-advanced.md +583 -0
  62. package/skills/ctf-forensics/network.md +645 -0
  63. package/skills/ctf-forensics/peripheral-capture.md +287 -0
  64. package/skills/ctf-forensics/signals-and-hardware.md +713 -0
  65. package/skills/ctf-forensics/steganography.md +694 -0
  66. package/skills/ctf-forensics/stego-advanced-2.md +475 -0
  67. package/skills/ctf-forensics/stego-advanced.md +481 -0
  68. package/skills/ctf-forensics/stego-image.md +691 -0
  69. package/skills/ctf-forensics/windows.md +625 -0
  70. package/skills/ctf-malware/SKILL.md +181 -0
  71. package/skills/ctf-malware/c2-and-protocols.md +274 -0
  72. package/skills/ctf-malware/pe-and-dotnet.md +108 -0
  73. package/skills/ctf-malware/scripts-and-obfuscation.md +449 -0
  74. package/skills/ctf-misc/SKILL.md +498 -0
  75. package/skills/ctf-misc/bashjails.md +323 -0
  76. package/skills/ctf-misc/ctfd-navigation.md +465 -0
  77. package/skills/ctf-misc/dns.md +255 -0
  78. package/skills/ctf-misc/encodings-advanced.md +504 -0
  79. package/skills/ctf-misc/encodings.md +431 -0
  80. package/skills/ctf-misc/games-and-vms-2.md +254 -0
  81. package/skills/ctf-misc/games-and-vms-3.md +690 -0
  82. package/skills/ctf-misc/games-and-vms-4.md +229 -0
  83. package/skills/ctf-misc/games-and-vms.md +529 -0
  84. package/skills/ctf-misc/linux-privesc.md +333 -0
  85. package/skills/ctf-misc/pyjails.md +671 -0
  86. package/skills/ctf-misc/rf-sdr.md +91 -0
  87. package/skills/ctf-osint/SKILL.md +198 -0
  88. package/skills/ctf-osint/geolocation-and-media.md +464 -0
  89. package/skills/ctf-osint/social-media.md +312 -0
  90. package/skills/ctf-osint/web-and-dns.md +341 -0
  91. package/skills/ctf-pwn/SKILL.md +214 -0
  92. package/skills/ctf-pwn/advanced-exploits-2.md +579 -0
  93. package/skills/ctf-pwn/advanced-exploits-3.md +598 -0
  94. package/skills/ctf-pwn/advanced-exploits-4.md +590 -0
  95. package/skills/ctf-pwn/advanced-exploits-5.md +119 -0
  96. package/skills/ctf-pwn/advanced-exploits.md +773 -0
  97. package/skills/ctf-pwn/advanced.md +326 -0
  98. package/skills/ctf-pwn/field-notes.md +245 -0
  99. package/skills/ctf-pwn/format-string.md +694 -0
  100. package/skills/ctf-pwn/heap-fsop.md +285 -0
  101. package/skills/ctf-pwn/heap-techniques-2.md +333 -0
  102. package/skills/ctf-pwn/heap-techniques.md +513 -0
  103. package/skills/ctf-pwn/kernel-bypass.md +421 -0
  104. package/skills/ctf-pwn/kernel-techniques.md +366 -0
  105. package/skills/ctf-pwn/kernel.md +636 -0
  106. package/skills/ctf-pwn/overflow-basics.md +611 -0
  107. package/skills/ctf-pwn/rop-advanced.md +725 -0
  108. package/skills/ctf-pwn/rop-and-shellcode.md +659 -0
  109. package/skills/ctf-pwn/sandbox-escape.md +313 -0
  110. package/skills/ctf-reverse/SKILL.md +163 -0
  111. package/skills/ctf-reverse/anti-analysis-ctf.md +204 -0
  112. package/skills/ctf-reverse/anti-analysis.md +693 -0
  113. package/skills/ctf-reverse/field-notes.md +376 -0
  114. package/skills/ctf-reverse/languages-compiled.md +666 -0
  115. package/skills/ctf-reverse/languages-platforms.md +592 -0
  116. package/skills/ctf-reverse/languages.md +553 -0
  117. package/skills/ctf-reverse/patterns-ctf-2.md +397 -0
  118. package/skills/ctf-reverse/patterns-ctf-3.md +797 -0
  119. package/skills/ctf-reverse/patterns-ctf.md +670 -0
  120. package/skills/ctf-reverse/patterns-runtime.md +274 -0
  121. package/skills/ctf-reverse/patterns.md +572 -0
  122. package/skills/ctf-reverse/platforms-hardware.md +387 -0
  123. package/skills/ctf-reverse/platforms.md +664 -0
  124. package/skills/ctf-reverse/tools-advanced-2.md +421 -0
  125. package/skills/ctf-reverse/tools-advanced.md +407 -0
  126. package/skills/ctf-reverse/tools-dynamic.md +679 -0
  127. package/skills/ctf-reverse/tools-emulation.md +319 -0
  128. package/skills/ctf-reverse/tools.md +573 -0
  129. package/skills/ctf-web/SKILL.md +153 -0
  130. package/skills/ctf-web/auth-and-access-2.md +82 -0
  131. package/skills/ctf-web/auth-and-access.md +783 -0
  132. package/skills/ctf-web/auth-infra.md +321 -0
  133. package/skills/ctf-web/auth-jwt.md +186 -0
  134. package/skills/ctf-web/client-side-advanced.md +739 -0
  135. package/skills/ctf-web/client-side.md +529 -0
  136. package/skills/ctf-web/cves.md +373 -0
  137. package/skills/ctf-web/field-notes.md +482 -0
  138. package/skills/ctf-web/node-and-prototype.md +200 -0
  139. package/skills/ctf-web/server-side-2.md +337 -0
  140. package/skills/ctf-web/server-side-advanced-2.md +559 -0
  141. package/skills/ctf-web/server-side-advanced-3.md +125 -0
  142. package/skills/ctf-web/server-side-advanced-4.md +480 -0
  143. package/skills/ctf-web/server-side-advanced.md +378 -0
  144. package/skills/ctf-web/server-side-deser.md +443 -0
  145. package/skills/ctf-web/server-side-exec-2.md +799 -0
  146. package/skills/ctf-web/server-side-exec.md +457 -0
  147. package/skills/ctf-web/server-side.md +629 -0
  148. package/skills/ctf-web/sql-injection.md +790 -0
  149. package/skills/ctf-web/web3.md +374 -0
  150. package/skills/ctf-writeup/SKILL.md +90 -0
  151. package/skills/solve-challenge/SKILL.md +269 -0
  152. package/skills.json +16 -0
@@ -0,0 +1,693 @@
1
+ # CTF Reverse - Anti-Analysis Techniques & Bypasses
2
+
3
+ Comprehensive reference for anti-debugging, anti-VM, anti-DBI, and integrity-check techniques encountered in CTF challenges, with practical bypasses.
4
+
5
+ ## Table of Contents
6
+ - [Linux Anti-Debug (Advanced)](#linux-anti-debug-advanced)
7
+ - [ptrace-Based](#ptrace-based)
8
+ - [/proc Filesystem Checks](#proc-filesystem-checks)
9
+ - [Timing-Based Detection](#timing-based-detection)
10
+ - [Signal-Based Anti-Debug](#signal-based-anti-debug)
11
+ - [Syscall-Level Evasion](#syscall-level-evasion)
12
+ - [Trap-Flag Self-Check with cmovz Patcher (Hack.lu 2018)](#trap-flag-self-check-with-cmovz-patcher-hacklu-2018)
13
+ - [SIGFPE Handler for mprotect Code Mutation (Hack.lu 2018)](#sigfpe-handler-for-mprotect-code-mutation-hacklu-2018)
14
+ - [Windows Anti-Debug (Advanced)](#windows-anti-debug-advanced)
15
+ - [PEB (Process Environment Block) Checks](#peb-process-environment-block-checks)
16
+ - [NtQueryInformationProcess](#ntqueryinformationprocess)
17
+ - [Heap Flags](#heap-flags)
18
+ - [TLS Callbacks](#tls-callbacks)
19
+ - [Hardware Breakpoint Detection](#hardware-breakpoint-detection)
20
+ - [Software Breakpoint Detection (INT3 Scanning)](#software-breakpoint-detection-int3-scanning)
21
+ - [Exception-Based Anti-Debug](#exception-based-anti-debug)
22
+ - [NtSetInformationThread (Thread Hiding)](#ntsetinformationthread-thread-hiding)
23
+ - [Anti-VM / Anti-Sandbox](#anti-vm--anti-sandbox)
24
+ - [CPUID Hypervisor Bit](#cpuid-hypervisor-bit)
25
+ - [MAC Address / Hardware Fingerprinting](#mac-address--hardware-fingerprinting)
26
+ - [Timing-Based VM Detection](#timing-based-vm-detection)
27
+ - [File / Registry Artifacts](#file--registry-artifacts)
28
+ - [Resource Checks (CPU Count, RAM, Disk)](#resource-checks-cpu-count-ram-disk)
29
+ - [Anti-DBI (Dynamic Binary Instrumentation)](#anti-dbi-dynamic-binary-instrumentation)
30
+ - [Frida Detection](#frida-detection)
31
+ - [Pin/DynamoRIO Detection](#pindynamorio-detection)
32
+ - [Code Integrity / Self-Hashing](#code-integrity--self-hashing)
33
+ - [Anti-Disassembly Techniques](#anti-disassembly-techniques)
34
+ - [Opaque Predicates](#opaque-predicates)
35
+ - [Junk Bytes / Overlapping Instructions](#junk-bytes--overlapping-instructions)
36
+ - [Jump-in-the-Middle](#jump-in-the-middle)
37
+ - [Function Chunking / Scattered Code](#function-chunking--scattered-code)
38
+ - [Control Flow Flattening (Advanced)](#control-flow-flattening-advanced)
39
+ - [Mixed Boolean-Arithmetic (MBA) Identification & Simplification](#mixed-boolean-arithmetic-mba-identification--simplification)
40
+ - [Comprehensive Bypass Strategies](#comprehensive-bypass-strategies)
41
+
42
+ For CTF writeup techniques (SIGILL handler, SIGFPE strace side-channel, instruction trace inversion, call-less function chaining, parent-patched child binary dump), see [anti-analysis-ctf.md](anti-analysis-ctf.md).
43
+ - [Universal Bypass Checklist](#universal-bypass-checklist)
44
+ - [Layered Anti-Debug (Real-World Pattern)](#layered-anti-debug-real-world-pattern)
45
+ - [Quick Reference: Check to Bypass](#quick-reference-check-to-bypass)
46
+
47
+ ---
48
+
49
+ ## Linux Anti-Debug (Advanced)
50
+
51
+ ### ptrace-Based
52
+
53
+ **Self-ptrace (most common):**
54
+ ```c
55
+ if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) exit(1); // Already traced = debugger attached
56
+ ```
57
+
58
+ **Bypasses:**
59
+ ```bash
60
+ # 1. LD_PRELOAD (see patterns.md for full hook)
61
+ LD_PRELOAD=./hook.so ./binary
62
+
63
+ # 2. Patch with pwntools
64
+ python3 -c "
65
+ from pwn import *
66
+ elf = ELF('./binary', checksec=False)
67
+ elf.asm(elf.symbols.ptrace, 'xor eax, eax; ret')
68
+ elf.save('patched')
69
+ "
70
+
71
+ # 3. GDB: catch the syscall
72
+ gdb ./binary
73
+ (gdb) catch syscall ptrace
74
+ (gdb) run
75
+ # When it stops at ptrace:
76
+ (gdb) set $rax = 0
77
+ (gdb) continue
78
+
79
+ # 4. Kernel config (requires root)
80
+ echo 0 > /proc/sys/kernel/yama/ptrace_scope
81
+ ```
82
+
83
+ **Double-ptrace pattern:**
84
+ ```c
85
+ // Fork child to ptrace parent — blocks all other debuggers
86
+ pid_t child = fork();
87
+ if (child == 0) {
88
+ ptrace(PTRACE_ATTACH, getppid(), 0, 0);
89
+ // Child sits in waitpid loop, keeping parent traced
90
+ } else {
91
+ // Parent continues with real logic
92
+ }
93
+ ```
94
+ **Bypass:** Kill the watchdog child process, then attach debugger.
95
+
96
+ ### /proc Filesystem Checks
97
+
98
+ ```c
99
+ // TracerPid check
100
+ FILE *f = fopen("/proc/self/status", "r");
101
+ // Looks for "TracerPid:\t0" — non-zero means debugger
102
+
103
+ // /proc/self/exe link check (some debuggers change this)
104
+ readlink("/proc/self/exe", buf, sizeof(buf));
105
+
106
+ // /proc/self/maps — check for debugger libraries
107
+ grep("frida", "/proc/self/maps");
108
+ ```
109
+
110
+ **Bypasses:**
111
+ ```bash
112
+ # 1. LD_PRELOAD fopen/fread to fake /proc contents
113
+ # 2. Mount namespace isolation
114
+ unshare -m bash -c 'mount --bind /dev/null /proc/self/status && ./binary'
115
+
116
+ # 3. GDB: set breakpoint at fopen, change filename argument
117
+ (gdb) b fopen
118
+ (gdb) run
119
+ (gdb) set {char[20]} $rdi = "/dev/null"
120
+ (gdb) continue
121
+ ```
122
+
123
+ ### Timing-Based Detection
124
+
125
+ ```c
126
+ // rdtsc (CPU timestamp counter)
127
+ uint64_t start = __rdtsc();
128
+ // ... code ...
129
+ uint64_t delta = __rdtsc() - start;
130
+ if (delta > THRESHOLD) exit(1); // too slow = debugger
131
+
132
+ // clock_gettime
133
+ struct timespec ts1, ts2;
134
+ clock_gettime(CLOCK_MONOTONIC, &ts1);
135
+ // ... code ...
136
+ clock_gettime(CLOCK_MONOTONIC, &ts2);
137
+
138
+ // gettimeofday
139
+ struct timeval tv1, tv2;
140
+ gettimeofday(&tv1, NULL);
141
+ ```
142
+
143
+ **Bypasses:**
144
+ ```bash
145
+ # 1. Frida hook (see tools-dynamic.md for clock_gettime hook)
146
+
147
+ # 2. GDB: skip rdtsc by patching with constant
148
+ (gdb) set {unsigned char[2]} 0x401234 = {0x90, 0x90} # NOP the rdtsc
149
+
150
+ # 3. Pin tool to fix TSC reads
151
+ # 4. faketime library
152
+ LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 FAKETIME="2024-01-01" ./binary
153
+ ```
154
+
155
+ ### Signal-Based Anti-Debug
156
+
157
+ ```c
158
+ // SIGTRAP handler — INT3 under debugger is caught by debugger, not handler
159
+ signal(SIGTRAP, handler);
160
+ __asm__("int3");
161
+ // If handler runs: no debugger. If debugger catches: debugged.
162
+
163
+ // SIGALRM timeout — kill self if analysis takes too long
164
+ signal(SIGALRM, kill_handler);
165
+ alarm(5);
166
+
167
+ // SIGSEGV handler that does real work (see patterns.md for MBA pattern)
168
+ signal(SIGSEGV, real_logic_handler);
169
+ *(int*)0 = 0; // deliberate crash → handler runs real code
170
+ ```
171
+
172
+ **Bypasses:**
173
+ ```bash
174
+ # GDB: pass signals to program instead of handling them
175
+ (gdb) handle SIGTRAP nostop pass
176
+ (gdb) handle SIGALRM ignore
177
+ (gdb) handle SIGSEGV nostop pass
178
+
179
+ # For alarm-based: patch alarm() to return immediately
180
+ ```
181
+
182
+ ### Syscall-Level Evasion
183
+
184
+ ```c
185
+ // Direct syscall instead of libc — bypasses LD_PRELOAD hooks
186
+ long ret;
187
+ asm volatile("syscall" : "=a"(ret) : "a"(101), "D"(0), "S"(0), "d"(0), "r"(0));
188
+ // Syscall 101 = ptrace on x86_64
189
+ ```
190
+
191
+ **Bypass:** Must patch the binary itself or use ptrace to intercept at syscall level.
192
+ ```bash
193
+ # GDB: catch syscall
194
+ (gdb) catch syscall 101
195
+ (gdb) commands
196
+ > set $rax = 0
197
+ > continue
198
+ > end
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Windows Anti-Debug (Advanced)
204
+
205
+ ### PEB (Process Environment Block) Checks
206
+
207
+ ```c
208
+ // BeingDebugged flag (offset 0x2 in PEB)
209
+ bool debugged = NtCurrentPeb()->BeingDebugged;
210
+
211
+ // NtGlobalFlag (offset 0x68/0xBC in PEB)
212
+ // When debugger: FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_VALIDATE_PARAMETERS = 0x70
213
+ DWORD flags = *(DWORD*)((BYTE*)NtCurrentPeb() + 0xBC); // 64-bit offset
214
+ if (flags & 0x70) exit(1);
215
+ ```
216
+
217
+ **Bypass (x64dbg):**
218
+ ```text
219
+ # ScyllaHide plugin auto-patches PEB fields
220
+ # Manual: dump PEB, zero BeingDebugged and NtGlobalFlag
221
+ ```
222
+
223
+ ### NtQueryInformationProcess
224
+
225
+ ```c
226
+ // ProcessDebugPort (0x7)
227
+ DWORD_PTR debugPort = 0;
228
+ NtQueryInformationProcess(GetCurrentProcess(), 7, &debugPort, sizeof(debugPort), NULL);
229
+ if (debugPort != 0) exit(1);
230
+
231
+ // ProcessDebugObjectHandle (0x1E)
232
+ HANDLE debugObj = NULL;
233
+ NTSTATUS status = NtQueryInformationProcess(GetCurrentProcess(), 0x1E, &debugObj, sizeof(debugObj), NULL);
234
+ if (status == 0) exit(1); // STATUS_SUCCESS means debugger present
235
+
236
+ // ProcessDebugFlags (0x1F) — returns inverse: 0 = debugger present
237
+ DWORD noDebug = 0;
238
+ NtQueryInformationProcess(GetCurrentProcess(), 0x1F, &noDebug, sizeof(noDebug), NULL);
239
+ if (noDebug == 0) exit(1);
240
+ ```
241
+
242
+ **Bypass:** Hook `NtQueryInformationProcess` to return fake values, or use ScyllaHide.
243
+
244
+ ### Heap Flags
245
+
246
+ ```c
247
+ // Process heap has debug flags when debugger attached
248
+ PHEAP heap = (PHEAP)GetProcessHeap();
249
+ // Flags at offset 0x70 (64-bit): should be HEAP_GROWABLE (0x2)
250
+ // ForceFlags at offset 0x74: should be 0
251
+ if (heap->Flags != 0x2 || heap->ForceFlags != 0) exit(1);
252
+ ```
253
+
254
+ ### TLS Callbacks
255
+
256
+ **Key technique:** TLS (Thread Local Storage) callbacks execute BEFORE `main()` / entry point.
257
+
258
+ ```c
259
+ // Registered in PE header's TLS directory
260
+ void NTAPI TlsCallback(PVOID DllHandle, DWORD Reason, PVOID Reserved) {
261
+ if (Reason == DLL_PROCESS_ATTACH) {
262
+ if (IsDebuggerPresent()) {
263
+ ExitProcess(1); // Kills process before main runs
264
+ }
265
+ }
266
+ }
267
+
268
+ #pragma comment(linker, "/INCLUDE:_tls_used")
269
+ #pragma data_seg(".CRT$XLB")
270
+ PIMAGE_TLS_CALLBACK callbacks[] = { TlsCallback, NULL };
271
+ ```
272
+
273
+ **Detection in IDA/Ghidra:** Check PE TLS Directory → AddressOfCallBacks. Functions listed there run before EP.
274
+
275
+ **Bypass:** Set breakpoint on TLS callback in x64dbg (Options → Events → TLS Callbacks), or patch the TLS directory entry.
276
+
277
+ ### Hardware Breakpoint Detection
278
+
279
+ ```c
280
+ // Read debug registers via GetThreadContext
281
+ CONTEXT ctx;
282
+ ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
283
+ GetThreadContext(GetCurrentThread(), &ctx);
284
+ if (ctx.Dr0 || ctx.Dr1 || ctx.Dr2 || ctx.Dr3) exit(1);
285
+
286
+ // Also via exception handler: deliberate exception, check DR regs in handler
287
+ ```
288
+
289
+ **Bypass:**
290
+ ```bash
291
+ # x64dbg: use software breakpoints instead, or hook GetThreadContext
292
+ # Frida: hook GetThreadContext to zero DR registers
293
+ ```
294
+
295
+ ### Software Breakpoint Detection (INT3 Scanning)
296
+
297
+ ```c
298
+ // CRC / hash check over code section
299
+ unsigned char *code = (unsigned char*)function_addr;
300
+ uint32_t checksum = 0;
301
+ for (int i = 0; i < code_size; i++) {
302
+ checksum += code[i];
303
+ if (code[i] == 0xCC) exit(1); // INT3 = software breakpoint
304
+ }
305
+ if (checksum != EXPECTED_CHECKSUM) exit(1);
306
+ ```
307
+
308
+ **Bypass:** Use hardware breakpoints (DR0-DR3) instead of software breakpoints. Or hook the scanning function.
309
+
310
+ ### Exception-Based Anti-Debug
311
+
312
+ ```c
313
+ // UnhandledExceptionFilter — under debugger, filter is NOT called
314
+ SetUnhandledExceptionFilter(handler);
315
+ RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, NULL);
316
+ // If handler runs: no debugger
317
+ // If debugger catches: debugger present
318
+
319
+ // INT 2D — debugger single-step anomaly
320
+ __asm { int 2dh } // Debugger silently consumes the exception
321
+ // If execution continues: debugger present
322
+ ```
323
+
324
+ ### NtSetInformationThread (Thread Hiding)
325
+
326
+ ```c
327
+ // Hide thread from debugger — stops all debug events
328
+ typedef NTSTATUS(NTAPI *pNtSIT)(HANDLE, ULONG, PVOID, ULONG);
329
+ pNtSIT NtSIT = (pNtSIT)GetProcAddress(GetModuleHandle("ntdll"), "NtSetInformationThread");
330
+ NtSIT(GetCurrentThread(), 0x11 /*ThreadHideFromDebugger*/, NULL, 0);
331
+ // After this, debugger won't see breakpoints or exceptions from this thread
332
+ ```
333
+
334
+ **Bypass:** Hook `NtSetInformationThread` to ignore class 0x11, or patch the call.
335
+
336
+ ---
337
+
338
+ ## Anti-VM / Anti-Sandbox
339
+
340
+ ### CPUID Hypervisor Bit
341
+
342
+ ```c
343
+ int regs[4];
344
+ __cpuid(regs, 1);
345
+ if (regs[2] & (1 << 31)) { // ECX bit 31 = hypervisor present
346
+ exit(1);
347
+ }
348
+
349
+ // Hypervisor brand string
350
+ __cpuid(regs, 0x40000000);
351
+ char brand[13] = {0};
352
+ memcpy(brand, &regs[1], 12);
353
+ // "VMwareVMware", "Microsoft Hv", "KVMKVMKVM", "XenVMMXenVMM"
354
+ ```
355
+
356
+ **Bypass:** Patch `cpuid` results or use `LD_PRELOAD` to hook wrapper functions.
357
+
358
+ ### MAC Address / Hardware Fingerprinting
359
+
360
+ ```text
361
+ Known VM MAC prefixes:
362
+ VMware: 00:0C:29, 00:50:56
363
+ VirtualBox: 08:00:27
364
+ Hyper-V: 00:15:5D
365
+ Parallels: 00:1C:42
366
+ QEMU: 52:54:00
367
+ ```
368
+
369
+ ### Timing-Based VM Detection
370
+
371
+ ```c
372
+ // VM exits on privileged instructions are measurably slower
373
+ uint64_t start = __rdtsc();
374
+ __cpuid(regs, 0); // Forces VM exit
375
+ uint64_t delta = __rdtsc() - start;
376
+ if (delta > 500) { /* likely VM */ }
377
+ ```
378
+
379
+ ### File / Registry Artifacts
380
+
381
+ ```text
382
+ Files: C:\Windows\System32\drivers\vm*.sys, vbox*.dll, VBoxService.exe
383
+ Registry: HKLM\SOFTWARE\VMware, Inc.\VMware Tools
384
+ Services: VMTools, VBoxService
385
+ Processes: vmtoolsd.exe, VBoxTray.exe, qemu-ga.exe
386
+ Linux: /sys/class/dmi/id/product_name contains "VirtualBox"|"VMware"
387
+ dmesg | grep -i "hypervisor detected"
388
+ ```
389
+
390
+ ### Resource Checks (CPU Count, RAM, Disk)
391
+
392
+ ```c
393
+ // Sandboxes typically have minimal resources
394
+ SYSTEM_INFO si;
395
+ GetSystemInfo(&si);
396
+ if (si.dwNumberOfProcessors < 2) exit(1);
397
+
398
+ MEMORYSTATUSEX ms;
399
+ ms.dwLength = sizeof(ms);
400
+ GlobalMemoryStatusEx(&ms);
401
+ if (ms.ullTotalPhys < 2ULL * 1024 * 1024 * 1024) exit(1); // < 2GB RAM
402
+
403
+ // Disk size check (< 60GB = sandbox)
404
+ GetDiskFreeSpaceEx("C:\\", NULL, &total, NULL);
405
+ ```
406
+
407
+ **Bypass:** Use a VM configured with adequate resources (4+ CPUs, 8GB+ RAM, 100GB+ disk).
408
+
409
+ ---
410
+
411
+ ## Anti-DBI (Dynamic Binary Instrumentation)
412
+
413
+ ### Frida Detection
414
+
415
+ ```c
416
+ // 1. Check /proc/self/maps for frida-agent
417
+ FILE *f = fopen("/proc/self/maps", "r");
418
+ while (fgets(line, sizeof(line), f)) {
419
+ if (strstr(line, "frida") || strstr(line, "gadget")) exit(1);
420
+ }
421
+
422
+ // 2. Check for Frida's default port (27042)
423
+ int sock = socket(AF_INET, SOCK_STREAM, 0);
424
+ struct sockaddr_in addr = {.sin_family=AF_INET, .sin_port=htons(27042), .sin_addr.s_addr=inet_addr("127.0.0.1")};
425
+ if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) exit(1);
426
+
427
+ // 3. Check for inline hooks (function prologue modification)
428
+ // Compare first bytes of libc functions against expected values
429
+ unsigned char *strcmp_bytes = (unsigned char *)strcmp;
430
+ if (strcmp_bytes[0] == 0xE9 || strcmp_bytes[0] == 0xFF) exit(1); // JMP = hooked
431
+
432
+ // 4. Thread name check
433
+ // Frida creates threads with names like "gmain", "gdbus", "frida-*"
434
+ DIR *dir = opendir("/proc/self/task");
435
+ while ((entry = readdir(dir))) {
436
+ char comm_path[256];
437
+ snprintf(comm_path, sizeof(comm_path), "/proc/self/task/%s/comm", entry->d_name);
438
+ // Read comm and check for "gmain", "gdbus"
439
+ }
440
+
441
+ // 5. Named pipe detection (Windows)
442
+ // Frida creates \\.\pipe\frida-* named pipes
443
+ ```
444
+
445
+ **Frida bypass of Frida detection:**
446
+ ```javascript
447
+ // Hook the detection functions themselves
448
+ Interceptor.attach(Module.findExportByName(null, "strstr"), {
449
+ onEnter(args) {
450
+ this.haystack = Memory.readUtf8String(args[0]);
451
+ this.needle = Memory.readUtf8String(args[1]);
452
+ },
453
+ onLeave(retval) {
454
+ if (this.needle && (this.needle.includes("frida") || this.needle.includes("gadget"))) {
455
+ retval.replace(ptr(0)); // Not found
456
+ }
457
+ }
458
+ });
459
+
460
+ // Early Frida load (before anti-DBI runs)
461
+ // Use frida-gadget as early-init shared library
462
+ ```
463
+
464
+ ### Pin/DynamoRIO Detection
465
+
466
+ ```c
467
+ // Check for instrumentation libraries in /proc/self/maps
468
+ // Pin: "pin-", "pinbin", "pinatrace"
469
+ // DynamoRIO: "dynamorio", "drcov", "drrun"
470
+
471
+ // Instruction count timing — DBI adds overhead
472
+ // Execute known instruction sequence, compare execution time
473
+ ```
474
+
475
+ ---
476
+
477
+ ## Code Integrity / Self-Hashing
478
+
479
+ ```c
480
+ // CRC32 over .text section
481
+ uint32_t crc = compute_crc32(text_start, text_size);
482
+ if (crc != EXPECTED_CRC) exit(1); // Code was modified (breakpoints, patches)
483
+
484
+ // MD5/SHA256 of function bodies
485
+ unsigned char hash[32];
486
+ SHA256(function_addr, function_size, hash);
487
+ if (memcmp(hash, expected_hash, 32) != 0) exit(1);
488
+ ```
489
+
490
+ **Bypasses:**
491
+ 1. **Hardware breakpoints** (don't modify code, DR0-DR3)
492
+ 2. **Patch the comparison** to always succeed
493
+ 3. **Hook the hash function** to return expected value
494
+ 4. **Emulate** instead of debug (Unicorn/Qiling — no code modification)
495
+ 5. **Snapshot + restore:** dump memory before and after, diff to find checks
496
+
497
+ **Self-checksumming in loops:**
498
+ ```c
499
+ // Continuous integrity check in separate thread
500
+ void *watchdog(void *arg) {
501
+ while (1) {
502
+ if (compute_crc32(text_start, text_end - text_start) != saved_crc) {
503
+ memset(flag_buffer, 0, flag_len); // Destroy flag
504
+ exit(1);
505
+ }
506
+ usleep(100000);
507
+ }
508
+ }
509
+ ```
510
+ **Bypass:** Kill the watchdog thread or patch its sleep to infinite.
511
+
512
+ ---
513
+
514
+ ## Anti-Disassembly Techniques
515
+
516
+ ### Opaque Predicates
517
+
518
+ ```asm
519
+ ; Condition that always evaluates the same way but looks data-dependent
520
+ mov eax, [some_memory]
521
+ imul eax, eax ; x^2
522
+ and eax, 1 ; x^2 mod 2 is always 0 for any x
523
+ jnz fake_branch ; Never taken, but disassembler doesn't know
524
+ ; real code here
525
+ ```
526
+
527
+ **Identification:** Z3/SMT can prove branch is always/never taken.
528
+
529
+ ### Junk Bytes / Overlapping Instructions
530
+
531
+ ```asm
532
+ jmp real_code
533
+ db 0xE8 ; Looks like start of CALL to linear disassembler
534
+ real_code:
535
+ mov eax, 1 ; Real code — disassembler may misalign here
536
+ ```
537
+
538
+ **Fix:** Switch to graph-mode disassembly (Ghidra/IDA handle this well). Manual: undefine and re-analyze from correct offset.
539
+
540
+ ### Jump-in-the-Middle
541
+
542
+ ```asm
543
+ ; Jumps into the middle of a multi-byte instruction
544
+ eb 01 ; jmp +1 (skip next byte)
545
+ e8 ; fake CALL opcode — disassembler tries to decode as call
546
+ 90 ; real: NOP (landed here from jmp)
547
+ ```
548
+
549
+ ### Function Chunking / Scattered Code
550
+
551
+ Functions split into non-contiguous chunks connected by unconditional jumps. Defeats linear function boundary detection.
552
+
553
+ **Tool:** IDA's "Append function tail" or Ghidra's "Create function" at each chunk.
554
+
555
+ ### Control Flow Flattening (Advanced)
556
+
557
+ Beyond basic switch-case (see patterns.md): modern OLLVM variants use:
558
+ - **Bogus control flow:** Fake branches with opaque predicates
559
+ - **Instruction substitution:** `a + b` → `a - (-b)`, `a ^ b` → `(a | b) & ~(a & b)`
560
+ - **String encryption:** Strings decrypted at runtime, cleared after use
561
+
562
+ **Deobfuscation tools:**
563
+ - **D-810** (IDA plugin): Pattern-based deobfuscation, MBA simplification
564
+ - **GOOMBA** (Ghidra): Automated deobfuscation for OLLVM
565
+ - **Miasm**: Symbolic execution for deobfuscation
566
+ - **Arybo** / **SiMBA**: MBA expression simplification
567
+
568
+ ```bash
569
+ # D-810: install in IDA plugins directory, Edit → Plugins → D-810
570
+ # Simplifies MBA expressions: (a | b) & ~(a & b) → a ^ b
571
+ # Removes opaque predicates via pattern matching
572
+ ```
573
+
574
+ ### Mixed Boolean-Arithmetic (MBA) Identification & Simplification
575
+
576
+ ```python
577
+ # Common MBA patterns and their simplified forms:
578
+ # (x & y) + (x | y) == x + y
579
+ # (x ^ y) + 2*(x & y) == x + y
580
+ # (x | y) - (x & ~y) == y
581
+ # ~(~x & ~y) == x | y (De Morgan's)
582
+ # (x | y) & ~(x & y) == x ^ y
583
+
584
+ # SiMBA tool for automated simplification:
585
+ # pip install simba-simplifier
586
+ from simba import simplify_mba
587
+ expr = "(a | b) + (a & b) - (~a & b)"
588
+ print(simplify_mba(expr)) # → a
589
+ ```
590
+
591
+ See [anti-analysis-ctf.md](anti-analysis-ctf.md) for CTF writeup techniques: SIGILL handler for mode switching (Hack.lu 2015), SIGFPE strace side-channel (PlaidCTF 2017), instruction trace inversion (MeePwn 2017), call-less function chaining (THC 2018), and parent-patched child binary dump via `process_vm_writev` (Google CTF Quals 2018).
592
+
593
+ ---
594
+
595
+ ## Comprehensive Bypass Strategies
596
+
597
+ ### Universal Bypass Checklist
598
+
599
+ 1. **Identify all anti-analysis checks** — search for: `ptrace`, `IsDebuggerPresent`, `rdtsc`, `cpuid`, `NtQuery`, `GetTickCount`, `CheckRemoteDebuggerPresent`, `/proc/self`, `SIGTRAP`, `alarm`
600
+ 2. **Static patching** — NOP/patch checks with pwntools or Ghidra before running
601
+ 3. **LD_PRELOAD** (Linux) — hook libc functions returning fake values
602
+ 4. **ScyllaHide** (Windows x64dbg) — patches PEB, hooks NT functions automatically
603
+ 5. **Emulation** (Unicorn/Qiling) — no debugger artifacts to detect
604
+ 6. **Kernel-level bypass** — modify `/proc/sys/kernel/yama/ptrace_scope`, use `prctl`
605
+
606
+ ### Layered Anti-Debug (Real-World Pattern)
607
+
608
+ Many CTF challenges stack multiple checks:
609
+ ```text
610
+ 1. TLS callback → IsDebuggerPresent (before main)
611
+ 2. main() → ptrace(TRACEME)
612
+ 3. Watchdog thread → timing check + /proc scan
613
+ 4. Code section → self-CRC32 integrity
614
+ 5. Signal handler → real logic in SIGSEGV handler
615
+ ```
616
+
617
+ **Approach:** Identify ALL checks before patching. Patch or hook each one systematically. Run under emulator if too many to patch individually.
618
+
619
+ ### Quick Reference: Check to Bypass
620
+
621
+ | Anti-Debug Check | Platform | Bypass |
622
+ |---|---|---|
623
+ | `ptrace(TRACEME)` | Linux | `LD_PRELOAD`, patch to `ret 0`, `catch syscall` |
624
+ | `IsDebuggerPresent` | Windows | ScyllaHide, Frida hook, PEB patch |
625
+ | `NtQueryInformationProcess` | Windows | ScyllaHide, hook ntdll |
626
+ | `rdtsc` timing | Both | NOP rdtsc, Frida time hook, Pin |
627
+ | `/proc/self/status` | Linux | Mount namespace, hook fopen |
628
+ | `alarm(N)` | Linux | `handle SIGALRM ignore` in GDB |
629
+ | `SIGTRAP` handler | Linux | `handle SIGTRAP nostop pass` |
630
+ | `SIGFPE` handler side-channel | Linux | `strace -e signal=SIGFPE` count per input |
631
+ | TLS callback | Windows | Break on TLS in x64dbg, patch |
632
+ | DR register scan | Windows | Use software BPs, hook GetThreadContext |
633
+ | INT3 scan / CRC | Both | Hardware BPs, patch CRC comparison |
634
+ | Frida detection | Both | Early-load gadget, hook strstr |
635
+ | CPUID hypervisor | Both | Patch CPUID result, bare metal |
636
+ | Thread hiding | Windows | Hook NtSetInformationThread |
637
+
638
+ ---
639
+
640
+ ### Trap-Flag Self-Check with cmovz Patcher (Hack.lu 2018)
641
+
642
+ **Pattern:** The binary checks `EFLAGS` by doing `pushf; pop edx; and edx, 0x100` (isolating the single-step Trap Flag) and using the result inside a `cmovz` so the correct instruction is overwritten only when the TF bit is clear. Single-stepping in gdb leaves TF set, the `cmovz` never fires, and the program silently runs the wrong code path without crashing.
643
+
644
+ ```asm
645
+ check_debugger:
646
+ pushf
647
+ pop edx
648
+ and edx, 0x100 ; Trap Flag only
649
+ test edx, edx
650
+ cmovz eax, ebx ; overwrite `eax` only when NOT single-stepping
651
+ mov [rip+target], eax
652
+ ```
653
+
654
+ **Bypass with hardware breakpoints:**
655
+ ```gdb
656
+ (gdb) hbreak *0x56557267 # hardware BP, no INT3, no TF side effect
657
+ (gdb) run
658
+ (gdb) # inspect EAX at the hbreak — the patched value is now written
659
+ ```
660
+
661
+ **Key insight:** `pushf; pop reg; and reg, 0x100` is the cleanest way to check TF without triggering a trap. Single-stepping changes the visible EFLAGS and can also perturb the instruction pipeline, so software breakpoints plus `stepi` both poison the check. Hardware breakpoints (`hbreak`) run the instruction normally and halt afterwards, so the check fires in "not debugging" mode. Apply the same fix to any anti-debug that reads EFLAGS, RFLAGS, or DR6.
662
+
663
+ **References:** Hack.lu CTF 2018 — Forgetful Commander, writeup 11858
664
+
665
+ ---
666
+
667
+ ### SIGFPE Handler for mprotect Code Mutation (Hack.lu 2018)
668
+
669
+ **Pattern:** The binary installs a custom `SIGFPE` handler with `sys_sigaction` and arranges for an arithmetic instruction to trap (e.g., `div` by zero). The handler runs with kernel-delivered context, calls `mprotect` on the `.text` page to make it writable, and mutates code that would otherwise stay constant. Standard static analysis misses the mutation because the FPE never fires in the normal path, and standard dynamic analysis misses it because most debuggers intercept SIGFPE before delivery.
670
+
671
+ ```c
672
+ // Handler installed at startup
673
+ void on_fpe(int sig, siginfo_t *info, void *uap) {
674
+ ucontext_t *ctx = uap;
675
+ void *page = (void *)((uintptr_t)ctx->uc_mcontext.gregs[REG_RIP] & ~0xfff);
676
+ mprotect(page, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC);
677
+ // Patch a constant used by the next check
678
+ *((uint32_t *)(page + 0x42)) = 0xDEADBEEF;
679
+ }
680
+ ```
681
+
682
+ **Bypass:**
683
+ ```bash
684
+ # Let SIGFPE reach the program, not the debugger
685
+ gdb ./challenge
686
+ (gdb) handle SIGFPE nostop noprint pass
687
+ (gdb) break *on_fpe
688
+ (gdb) run
689
+ ```
690
+
691
+ **Key insight:** Signal handlers that `mprotect` + mutate code are cross-delimited in a way decompilers cannot model. `SIGFPE` is particularly effective because it is rarely raised during normal execution, so the mutation stays dormant until the attacker hits the crafted input. When you see `sys_sigaction(SIGFPE,...)` or `signal(SIGFPE,...)` in a binary that also calls `mprotect`, trace the handler with `strace -e signal=SIGFPE` and annotate the mutated region by diffing the `.text` pages before and after the first FPE.
692
+
693
+ **References:** Hack.lu CTF 2018 — Cheat Console, writeup 11868