Reverse Engineering ACTION REQUIRED(读完后立刻执行) 阶段门闩: (triage→static→dynamic→synthesis)。社区 RE skill 对照: 。 1. : 读取 — 确认本 skill 的操作是已授权的常规操作 2. : 确认当前任务是否命中本 skill 的适用范围 3. : 读取 ,校验工具可用性和实际路径 4. : 缺工具时调用 bootstrap,不要猜路径 5. : 按 re-agent-workflow 推进;进入工作流第一步并执行,不要停在确认状态 Decision-framework entry hook When triage cannot locate a reliable entry point, severe obfuscation blocks progress, or the analysis is stuck, keep this R0 workflow as the primary route and load the existing ADF overlay instead of creating a new PRIMARY. Follow for stage transitions and time-boxed replanning; at Synthesis or a stuck l…

) to mark the original string's position. Without it, BWT inversion produces n candidates (one per rotation). Use domain-specific constraints (binary format, XOR round structure, flag prefix) to identify the correct candidate.\n\n---\n\n## OpenType Font Ligature Exploitation for Hidden Messages (Hack The Vote 2016)\n\nFont files with custom OpenType ligatures map visible characters to hidden glyphs. The GSUB (Glyph Substitution) table defines these mappings.\n\n```python\nfrom fontTools.ttLib import TTFont\n\ndef decode_font_ligatures(font_path, encoded_text):\n \"\"\"Extract ligature substitution table and decode message\"\"\"\n font = TTFont(font_path)\n\n # Extract GSUB table for ligature substitutions\n gsub = font['GSUB']\n\n # Navigate to ligature lookup\n ligature_map = {}\n for lookup in gsub.table.LookupList.Lookup:\n for subtable in lookup.SubTable:\n if hasattr(subtable, 'ligatures'):\n for glyph_name, ligatures in subtable.ligatures.items():\n for lig in ligatures:\n # Map: input sequence -> output glyph\n input_seq = [glyph_name] + lig.Component\n output = lig.LigGlyph\n ligature_map[tuple(input_seq)] = output\n\n print(\"Ligature mappings found:\")\n for inp, out in ligature_map.items():\n print(f\" {inp} -> {out}\")\n\n # Alternative: convert TTF to XML for manual analysis\n # font.saveXML('font_dump.xml')\n # Search for \u003cLigatureSubst> entries\n\n# Command-line approach:\n# pip install fonttools\n# ttx font.otf # converts to XML\n# grep -A5 'LigatureSubst' font.ttx\n```\n\n**Key insight:** Custom fonts with GSUB ligature tables create a cipher where displayed characters differ from their glyph mappings. The `fonttools` library's `ttx` command dumps the font to XML, making ligature substitution tables easily readable. Each ligature maps an input character sequence to a different output glyph.\n\n---\n\n## GLSL Shader VM with Self-Modifying Code (ApoorvCTF 2026)\n\n**Pattern (Draw Me):** A WebGL2 fragment shader implements a Turing-complete VM on a 256x256 RGBA texture. The texture is both program memory and display output.\n\n**Texture layout:**\n- **Row 0:** Registers (pixel 0 = instruction pointer, pixels 1-32 = general purpose)\n- **Rows 1-127:** Program memory (RGBA = opcode, arg1, arg2, arg3)\n- **Rows 128-255:** VRAM (display output)\n\n**Opcodes:** NOP(0), SET(1), ADD(2), SUB(3), XOR(4), JMP(5), JNZ(6), VRAM-write(7), STORE(8), LOAD(9). 16 steps per frame.\n\n**Self-modifying code:** Phase 1 (decryption) uses STORE opcode to XOR-patch program memory that Phase 2 (drawing) then executes. The decryption overwrites SET instructions with correct pixel color values before the drawing code runs.\n\n**Why GPU rendering fails:** The GPU runs all pixels in parallel per frame, but the shader tracks only ONE write target per pixel per frame. With multiple VRAM writes per frame, only the last survives — losing 75%+ of pixels. Similarly, STORE patches conflict during parallel decryption.\n\n**Solve via sequential emulation:**\n```python\nfrom PIL import Image\nimport numpy as np\n\nimg = Image.open('program.png').convert('RGBA')\nstate = np.array(img, dtype=np.int32).copy()\nregs = [0] * 33\n\n# Phase 1: Trace decryption — apply all STORE patches sequentially\nx, y = start_x, start_y\nwhile True:\n r, g, b, a = state[y][x]\n opcode = int(r)\n if opcode == 1: regs[g] = b & 255 # SET\n elif opcode == 4: regs[g] = regs[b] ^ regs[a] # XOR\n elif opcode == 8: # STORE — patches program memory\n tx, ty = regs[g], regs[b]\n state[ty][tx] = [regs[a], regs[a+1], regs[a+2], regs[a+3]]\n elif opcode == 5: break # JMP to drawing phase\n x += 1\n if x > 255: x, y = 0, y + 1\n\n# Phase 2: Execute drawing code — all VRAM writes preserved\nvram = np.zeros((128, 256), dtype=np.uint8)\n# ... trace with opcode 7 writing to vram[ty][tx] = color\nImage.fromarray(vram, mode='L').save('output.png')\n```\n\n**Key insight:** GLSL shaders are Turing-complete but GPU parallelism causes write conflicts. Self-modifying code (STORE patches) compounds the problem — patches from parallel executions overwrite each other. Sequential emulation in Python recovers the full output. The program.png file IS the bytecode.\n\n**Detection:** WebGL/shader challenge with a PNG \"program\" file, challenge says \"nothing renders\" or output is garbled. Look for custom opcode tables in GLSL source.\n\n---\n\n## Instruction Counter as Cryptographic State (MetaCTF Flash 2026)\n\n**Pattern (Who's Counting?):** Hand-written assembly binary uses a dedicated register (e.g., `r12`) as an instruction counter that increments after nearly every instruction. The counter value feeds into XOR, ROL, and multiply transformations on each input byte, making the entire transformation path-dependent on the number of instructions executed before reaching each byte.\n\n**Identification:**\n- Hand-written assembly (no compiler patterns, unusual register usage)\n- A register that only increments (`inc r12` or `add r12, 1`) appearing after most instructions\n- Transformations that reference this counter register (`xor rax, r12`, `rol al, cl` where `cl` derives from counter)\n- Sequential byte processing loop where state carries forward\n\n**Solving approach:**\n```python\n# Byte-by-byte brute force with emulation\n# Since each byte's transformation depends on the counter (which depends\n# on all prior instructions), state is path-dependent.\n\nfrom unicorn import *\nfrom unicorn.x86_const import *\n\ndef try_byte(known_prefix, candidate_byte):\n \"\"\"Emulate binary with known prefix + candidate, check output.\"\"\"\n uc = Uc(UC_ARCH_X86, UC_MODE_64)\n # Map code, stack, data segments\n uc.mem_map(CODE_BASE, 0x10000)\n uc.mem_write(CODE_BASE, binary_code)\n uc.mem_map(STACK_BASE, 0x10000)\n uc.mem_map(DATA_BASE, 0x10000)\n\n # Write input: known_prefix + candidate\n test_input = known_prefix + bytes([candidate_byte])\n uc.mem_write(DATA_BASE, test_input + b'\\x00' * (64 - len(test_input)))\n\n # Set up registers (rsp, rdi pointing to input, r12 = 0)\n uc.reg_write(UC_X86_REG_RSP, STACK_BASE + 0x8000)\n uc.reg_write(UC_X86_REG_R12, 0) # instruction counter starts at 0\n\n try:\n uc.emu_start(CODE_BASE + ENTRY_OFFSET, CODE_BASE + EXIT_OFFSET)\n # Read transformed output, compare against expected\n output = uc.mem_read(OUTPUT_ADDR, len(test_input))\n return output[:len(test_input)] == expected[:len(test_input)]\n except:\n return False\n\n# Recover flag byte by byte\nflag = b''\nfor pos in range(FLAG_LEN):\n for b in range(256):\n if try_byte(flag, b):\n flag += bytes([b])\n print(f\"Position {pos}: {chr(b)} -> {flag}\")\n break\n```\n\n**Key insight:** When a register acts as an instruction counter feeding into byte transformations, the transformation of byte N depends on the exact number of instructions executed while processing bytes 0 through N-1. This makes analytical inversion impractical because the counter value at each byte position depends on the execution path through all prior bytes. Byte-by-byte brute force with full emulation (Unicorn or GDB scripting) is the most reliable approach -- try all 256 values for each position, keeping the state from the correct prefix.\n\n**When to recognize:** Binary has no standard library calls, uses unusual registers consistently, and shows a register that only increments. The transformation per byte involves operations (XOR, rotate, multiply) that reference this counter. Challenge name hints at \"counting\" or \"instructions\".\n\n**Alternative approaches:**\n- GDB scripting: set breakpoint after each byte's transformation, compare output\n- Static analysis: count instructions manually to compute counter values, then invert transforms algebraically (error-prone due to counter accumulation)\n\n**References:** MetaCTF Flash CTF 2026 \"Who's Counting?\"\n\n---\n\n## Thread Race Condition with Signed Integer Overflow (Codegate 2017)\n\n**Pattern (Hunting):** A combat-simulation binary uses thread-unsafe skill selection. The attack thread checks `skill_id \u003c= 4` using signed comparison, then sleeps briefly before applying damage. During the sleep, switch to a different skill. The fireball skill uses `cdqe` (sign-extend EAX to RAX), converting `0xFFFFFFFF` (icesword damage) to `-1` as a signed 64-bit value. Subtracting `-1` from the boss's HP (`0x7FFFFFFFFFFFFFFF`) causes signed overflow to a negative value, killing the boss.\n\n```python\n# Race condition exploit:\n# Thread A: select fireball (skill_id=2, passes \u003c= 4 check)\n# Thread A: sleeps for animation\n# Main: switch to icesword (skill_id=5, damage=0xFFFFFFFF)\n# Thread A: wakes, reads damage from icesword slot\n# cdqe: 0xFFFFFFFF -> 0xFFFFFFFFFFFFFFFF (-1 signed)\n# boss_hp -= (-1) -> boss_hp = 0x7FFFFFFFFFFFFFFF + 1 = negative -> dead\n\nimport time, threading\ndef race():\n select_skill(2) # fireball - passes bounds check\n time.sleep(0.001)\n select_skill(5) # icesword - race into damage calculation\n```\n\n**Key insight:** `cdqe` (Convert Doubleword to Quadword Extension) sign-extends 32-bit EAX into 64-bit RAX. When the attack code reads a 32-bit damage value and sign-extends it, `0xFFFFFFFF` becomes `-1`. Subtracting a negative number adds to HP, but if HP is already at `INT64_MAX`, the addition overflows to negative, killing the target.\n\n---\n\n## ESP32/Xtensa Firmware Reversing with ROM Symbol Map (Insomni'hack 2017)\n\n**Pattern (Internet of Fail):** ESP32 firmware (Xtensa architecture) with no native IDA support. Use radare2 with the ESP32 ROM linker script (`esp32.rom.ld`) to map function addresses to names. Cross-reference with public ESP32 HTTP server source code to identify the password-checking logic, composed of ~20 conditional XOR functions operating on a global state variable.\n\n```bash\n# Load ESP32 firmware in radare2\nr2 -a xtensa -b 32 firmware.bin\n\n# Apply ROM symbol map from ESP-IDF\n# esp32.rom.ld maps addresses like:\n# 0x40000000 = ets_printf\n# 0x400013A0 = cache_Read_Enable\n# Load as flags: . esp32.rom.ld.r2\n\n# Identify HTTP request handler by cross-referencing\n# with esp-idf/examples/protocols/http_server\n# Look for URI handler registration patterns\n```\n\n**Key insight:** ESP32's Xtensa architecture lacks mainstream RE tool support, but the ESP-IDF SDK provides ROM linker scripts mapping every ROM function address to its name. Loading these as symbols in radare2 immediately resolves hundreds of function calls. Cross-referencing with public ESP-IDF example code identifies application-level patterns (HTTP handlers, WiFi callbacks) even in stripped firmware.\n\n---\n\n## Batch Crackme Automation via objdump Pattern Extraction (DEF CON 2017)\n\nSolve hundreds of identical-structure crackmes by scripting `objdump` to extract comparison values and arithmetic operations, computing keys without execution.\n\n```bash\n# Simple variant: extract CMP immediates directly\nobjdump -M intel -d $binary | grep -P \"cmp\\s+rdi\" | \\\n grep -oP \"0x\\w{1,2}\" | xxd -r -p\n\n# Complex variant: parse add/sub/cmp chains and reverse-compute\n# Each binary: series of add/sub rdi,N then cmp rdi,target\n# Reverse: start from target, undo operations in reverse order\npython3 \u003c\u003c'EOF'\nimport subprocess, re, glob\nfor binary in sorted(glob.glob(\"crackmes/*\")):\n asm = subprocess.check_output([\"objdump\", \"-M\", \"intel\", \"-d\", binary]).decode()\n ops = re.findall(r'(add|sub)\\s+rdi,(0x\\w+)', asm)\n target = int(re.search(r'cmp\\s+rdi,(0x\\w+)', asm).group(1), 16)\n # Reverse operations\n for op, val in reversed(ops):\n val = int(val, 16)\n target = (target - val) if op == 'add' else (target + val)\n print(chr(target & 0xff), end='')\nEOF\n```\n\n**Key insight:** Mass crackme challenges (100s-1000s of binaries) have identical structure with per-binary constants. Script `objdump` disassembly parsing to extract immediates and arithmetic sequences, then reverse-compute the key algebraically. No execution or emulation needed.\n\n---\n\n## Fork + Pipe + Dead Branch Anti-Analysis (RCTF 2017)\n\nBinary uses fork/pipe IPC where the parent writes data and exits, child reads from pipe and continues. Key validation is in a dead branch (always-false comparison) that requires binary patching to reach.\n\n```bash\n# Detection: fork() + pipe() + read()/write() in main\n# The child process reads from pipe, needs to know its own PID\n\n# Dead branch pattern:\n# cmp DWORD PTR [ebp-0xc], 0x1 ; compares 0 with 1, always false\n# je real_flag_computation ; never taken\n\n# Patch: change comparison value from 0x1 to 0x0\n# Find: 83 7d f4 01 → change to: 83 7d f4 00\npython3 -c \"\ndata = open('binary','rb').read()\ndata = data.replace(b'\\x83\\x7d\\xf4\\x01', b'\\x83\\x7d\\xf4\\x00')\nopen('binary_patched','wb').write(data)\n\"\n```\n\n**Key insight:** Fork+pipe creates a parent-child relationship where the parent provides data and exits. Dead branches (comparisons that always evaluate to false) hide the real validation logic. `strace` reveals the fork/pipe/read pattern; patching the comparison constant reaches the hidden code path.\n\n---\n\n---\n\n## Time-Locked Binary with Date-Based Key (Hack.lu 2017)\n\nBinary reads the system date and only executes correctly on a specific date (e.g., December 21, 2012). The date constant appears in the binary as a Unix timestamp or structured date comparison.\n\n**Detection:** Look for comparisons against large integer constants that fall in a recognizable date range (Unix timestamps: 2012 = ~1.35B, 2017 = ~1.5B). Cultural significance helps: apocalypse dates, CTF release dates, historical events.\n\n```bash\n# Set system clock to the required date\nsudo date -s \"2012-12-21 00:00:00\"\n./binary\n\n# Or use faketime to avoid system-wide change\nLD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 FAKETIME=\"2012-12-21 00:00:00\" ./binary\n\n# Restore system time afterward\nsudo ntpdate pool.ntp.org\n```\n\n**In IDA/Ghidra:** Search for `time()` or `localtime()` calls. The struct `tm` fields to watch: `tm_year` (years since 1900), `tm_mon` (0-based), `tm_mday`.\n\n**Key insight:** Time-based keys use culturally significant dates. Always check for date comparisons in reversed code and try setting the system clock or using faketime before attempting deeper analysis.\n\n**References:** Hack.lu CTF 2017\n\n---\n\n## ARM Code in Image Pixels via UnicornJS (Hack.lu 2017)\n\nJavaScript challenge embeds ARM bytecode in image pixel data. The image is base64-encoded in the HTML/JS source. Pixel RGBA values encode ARM instructions. A bundled UnicornJS library (ARM CPU emulator in JavaScript) extracts and executes the bytecode.\n\n**Identification flow:**\n1. Find base64 blob in JS source → decode → PNG/BMP file\n2. Identify UnicornJS import (`unicorn.js`, `uc.js`, or similar) → confirms ARM emulation\n3. Pixel extraction loop: RGBA bytes concatenated in raster order form the ARM instruction stream\n4. Feed the extracted bytes to an ARM disassembler\n\n```python\nfrom PIL import Image\nimport capstone\n\nimg = Image.open('decoded.png').convert('RGBA')\npixels = list(img.getdata())\n\n# Extract ARM bytecode from pixel data (4 bytes per pixel: R, G, B, A)\narm_code = bytes([channel for pixel in pixels for channel in pixel])\n\n# Disassemble as ARM Thumb or ARM32\nmd = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB)\nfor insn in md.disasm(arm_code, 0x0):\n print(f\"0x{insn.address:04x}: {insn.mnemonic} {insn.op_str}\")\n```\n\n**Key insight:** Multi-layer obfuscation: ARM code in image pixels, base64 encoded, emulated via UnicornJS at runtime. Identify the emulator library first to know which ISA to reverse — the library name reveals the architecture.\n\n**References:** Hack.lu CTF 2017\n\n---\n\n## x86 16-bit MBR psadbw Constraint Solving (CSAW 2017)\n\nBootable MBR uses SSE2 `psadbw` (Packed Sum of Absolute Differences of Bytes) on xmm registers to validate the flag. Each iteration masks 2 input bytes, computes `psadbw` against known constants, and compares the sum to an expected value.\n\n**`psadbw` semantics:**\n```asm\npsadbw xmm0, xmm1\n; For each of 8 byte pairs: sum += |xmm0[i] - xmm1[i]|\n; Result stored as 16-bit integer in low qword of xmm0\n```\n\nThis generates sum-of-absolute-differences equations:\n```text\n|a[0] - k[0]| + |a[1] - k[1]| + ... + |a[7] - k[7]| = C\n```\n\n**Solution approach:**\n```python\nimport numpy as np\nfrom itertools import product\n\n# For each 2-byte masked group, extract the constants and expected sum\n# Equations are not purely linear (absolute value), but printable ASCII\n# constrains each byte to [0x20, 0x7e], limiting brute-force space\n\ndef solve_psadbw_group(known_constants, expected_sum, printable_range=(0x20, 0x7e)):\n \"\"\"Brute-force 2 unknown bytes given sum-of-abs-diff constraint.\"\"\"\n solutions = []\n for a, b in product(range(*printable_range), repeat=2):\n pair = [a, b]\n sad = sum(abs(pair[i] - known_constants[i]) for i in range(len(pair)))\n if sad == expected_sum:\n solutions.append(bytes([a, b]))\n return solutions\n\n# For ambiguous cases with multiple solutions: apply additional constraints\n# (flag format prefix, character frequency, subsequent iterations)\n```\n\n**Key insight:** `psadbw` creates sum-of-absolute-difference equations — not purely linear but solvable with constrained brute-force when bytes are limited to printable ASCII. Each 2-byte group is independent, keeping the search space to 95^2 = ~9000 candidates per group.\n\n**References:** CSAW CTF 2017\n\n---\n\n## TensorFlow DNN Inversion by Inverting Sigmoid Layers (N1CTF 2018)\n\n**Pattern:** Binary implements a 5-layer deep neural network with sigmoid activation. The input (flag characters) is transformed as `1.0/char_value` before feeding into the network. Extract weights and biases from the binary, then compute the inverse layer-by-layer: apply inverse-sigmoid, subtract bias, multiply by weight matrix inverse.\n\n```python\nimport numpy as np\n\ndef sigmoid_inv(x):\n return -np.log(1.0/x - 1.0)\n\n# Invert layer by layer from output to input\nv = target_output\nfor i in range(num_layers - 1, -1, -1):\n v = np.dot(sigmoid_inv(v) - biases[i], np.linalg.inv(weights[i]))\n\n# Input was 1.0/char, so flag chars are the multiplicative inverse\nflag = ''.join(chr(int(round(1.0 / v[j]))) for j in range(len(v)))\n```\n\n**Key insight:** Neural networks with invertible activation functions (sigmoid, tanh) and square weight matrices can be mathematically inverted layer-by-layer. Apply inverse-sigmoid, subtract bias, multiply by weight inverse. Watch for input transformations (e.g., 1/x) that must also be inverted.\n\n**Detection:** Binary with TensorFlow or custom DNN implementation. Look for sigmoid/tanh calls, matrix multiplications, and hardcoded float arrays (weights/biases) in `.rodata`. Square weight matrices (N x N) indicate the network is invertible.\n\n**References:** N1CTF 2018\n\n---\n\n## BPF Filter Analysis via JIT Compilation to x64 Assembly (Midnight Sun CTF 2018)\n\n**Pattern:** Binary creates a raw socket with a BPF (Berkeley Packet Filter) attached. When standard BPF disassemblers fail to produce readable output, enable the kernel's BPF JIT compiler to convert BPF bytecode to native x64 assembly, then read the compiled code from dmesg.\n\n```bash\n# Enable BPF JIT compilation\necho 1 > /proc/sys/net/core/bpf_jit_enable\n\n# Run the binary, then read JIT-compiled BPF from kernel log\ndmesg | grep -A 100 \"flen=\"\n\n# Analysis revealed: expects DNS TXT query on UDP port 3333\ndig @target -p 3333 'M4d!bKn3~l' TXT\n```\n\n**Key insight:** Linux can JIT-compile BPF filters to native x64 machine code. When standard BPF disassemblers fail or produce unreadable output, enable `bpf_jit_enable` and read the compiled assembly from dmesg. The native code is often easier to understand than BPF bytecode.\n\n**Detection:** Binary using `setsockopt` with `SO_ATTACH_FILTER`, raw socket creation (`socket(AF_PACKET, ...)`), or embedded `struct sock_fprog` structures. BPF programs appear as arrays of `struct sock_filter` (8 bytes each: opcode, jt, jf, k).\n\n**References:** Midnight Sun CTF 2018\n\n---\n\nSee also: [patterns-ctf.md](patterns-ctf.md) for Part 1, [patterns-ctf-2.md](patterns-ctf-2.md) for Part 2 (multi-layer self-decrypting binary, embedded ZIP+XOR license, stack string deobfuscation, prefix hash brute-force, CVP/LLL lattice, decision tree obfuscation, GF(2^8) Gaussian elimination).\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":34672,"content_sha256":"76cfa06f01a4e8ed5cc91d1942c59aa65e70171989cd0064cd92b55961e0e716"},{"filename":"patterns-ctf.md","content":"# CTF Reverse - Competition-Specific Patterns (Part 1)\n\n## Table of Contents\n- [Hidden Emulator Opcodes + LD_PRELOAD Key Extraction (0xFun 2026)](#hidden-emulator-opcodes--ld_preload-key-extraction-0xfun-2026)\n- [Spectre-RSB SPN Cipher — Static Parameter Extraction (0xFun 2026)](#spectre-rsb-spn-cipher--static-parameter-extraction-0xfun-2026)\n- [Image XOR Mask Recovery via Smoothness (VuwCTF 2025)](#image-xor-mask-recovery-via-smoothness-vuwctf-2025)\n- [Shellcode in Data Section via mmap RWX (VuwCTF 2025)](#shellcode-in-data-section-via-mmap-rwx-vuwctf-2025)\n- [Recursive execve Subtraction (VuwCTF 2025)](#recursive-execve-subtraction-vuwctf-2025)\n- [Byte-at-a-Time Block Cipher Attack (UTCTF 2024)](#byte-at-a-time-block-cipher-attack-utctf-2024)\n- [Mathematical Convergence Bitmap (EHAX 2026)](#mathematical-convergence-bitmap-ehax-2026)\n- [Windows PE XOR Bitmap Extraction + OCR (srdnlenCTF 2026)](#windows-pe-xor-bitmap-extraction--ocr-srdnlenctf-2026)\n- [Two-Stage Loader: RC4 Gate + VM Constraints (srdnlenCTF 2026)](#two-stage-loader-rc4-gate--vm-constraints-srdnlenctf-2026)\n- [Kernel Module Maze Solving (DiceCTF 2026)](#kernel-module-maze-solving-dicectf-2026)\n- [Multi-Threaded VM with Channel Synchronization (DiceCTF 2026)](#multi-threaded-vm-with-channel-synchronization-dicectf-2026)\n- [Backdoored Shared Library Detection via String Diffing (Hack.lu CTF 2012)](#backdoored-shared-library-detection-via-string-diffing-hacklu-ctf-2012)\n- [Custom binfmt Kernel Module with RC4 Flat Binaries (BSidesSF 2026)](#custom-binfmt-kernel-module-with-rc4-flat-binaries-bsidessf-2026)\n- [Hash-Resolved Imports / No-Import Ransomware (BSidesSF 2026)](#hash-resolved-imports--no-import-ransomware-bsidessf-2026)\n- [ELF Section Header Corruption for Anti-Analysis (BSidesSF 2026)](#elf-section-header-corruption-for-anti-analysis-bsidessf-2026)\n\n---\n\n## Hidden Emulator Opcodes + LD_PRELOAD Key Extraction (0xFun 2026)\n\n**Pattern (CHIP-8):** Non-standard opcode `FxFF` triggers hidden `superChipRendrer()` → AES-256-CBC decryption. Key derived from binary constants.\n\n**Technique:**\n1. Check all instruction dispatch branches for non-standard opcodes\n2. Hidden opcode may trigger crypto functions (OpenSSL)\n3. Use `LD_PRELOAD` hook on `EVP_DecryptInit_ex` to capture AES key at runtime:\n\n```c\n#include \u003copenssl/evp.h>\nint EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,\n ENGINE *impl, const unsigned char *key,\n const unsigned char *iv) {\n // Log key\n for (int i = 0; i \u003c 32; i++) printf(\"%02x\", key[i]);\n printf(\"\\n\");\n // Call original\n return ((typeof(EVP_DecryptInit_ex)*)dlsym(RTLD_NEXT, \"EVP_DecryptInit_ex\"))\n (ctx, type, impl, key, iv);\n}\n```\n\n```bash\ngcc -shared -fPIC -ldl -lssl hook.c -o hook.so\nLD_PRELOAD=./hook.so ./emulator rom.ch8\n```\n\n---\n\n## Spectre-RSB SPN Cipher — Static Parameter Extraction (0xFun 2026)\n\n**Pattern:** Binary uses cache side channels to implement S-boxes, but ALL cipher parameters (round keys, S-box tables, permutation) are in the binary's data section.\n\n**Key insight:** Don't try to run on special hardware. Extract parameters statically:\n- 8 S-boxes × 8 output bits, 256 entries each\n- Values `0x340` = bit 1, `0x100` = bit 0\n- 64-byte permutation table, 8 round keys\n\n```python\n# Extract from binary data section\nimport struct\nsbox = [[0]*256 for _ in range(8)]\nfor i in range(8):\n for j in range(256):\n val = struct.unpack('\u003cI', data[sbox_offset + (i*256+j)*4 : ...])[0]\n sbox[i][j] = 1 if val == 0x340 else 0\n```\n\n**Lesson:** Side-channel implementations embed lookup tables in memory. Extract statically.\n\n---\n\n## Image XOR Mask Recovery via Smoothness (VuwCTF 2025)\n\n**Pattern (Trianglification):** Image divided into triangle regions, each XOR-encrypted with `key = (mask * x - y) & 0xFF` where mask is unknown (0-255).\n\n**Recovery:** Natural images have smooth gradients. Brute-force mask (256 values per region), score by neighbor pixel differences:\n\n```python\nimport numpy as np\nfrom PIL import Image\n\nimg = np.array(Image.open('encrypted.png'))\n\ndef score_smoothness(region_pixels, mask, positions):\n decrypted = []\n for (x, y), pixel in zip(positions, region_pixels):\n key = (mask * x - y) & 0xFF\n decrypted.append(pixel ^ key)\n # Score: sum of absolute differences between adjacent pixels\n return -sum(abs(decrypted[i] - decrypted[i+1]) for i in range(len(decrypted)-1))\n\nfor region in regions:\n best_mask = max(range(256), key=lambda m: score_smoothness(region, m, positions))\n```\n\n**Search space:** 256 candidates × N regions = trivial. Smoothness is a reliable scoring metric for natural images.\n\n---\n\n## Shellcode in Data Section via mmap RWX (VuwCTF 2025)\n\n**Pattern (Missing Function):** Binary relocates data to RWX memory (mmap with PROT_READ|PROT_WRITE|PROT_EXEC) and jumps to it.\n\n**Detection:** Look for `mmap` with PROT_EXEC flag. Embedded shellcode often uses XOR with rotating key.\n\n**Analysis:** Extract data section, apply XOR key (try 3-byte rotating), disassemble result.\n\n---\n\n## Recursive execve Subtraction (VuwCTF 2025)\n\n**Pattern (String Inspector):** Binary recursively calls itself via `execve`, subtracting constants each time.\n\n**Solution:** Find base case and work backward. Often a mathematical relationship like `N * M + remainder`.\n\n---\n\n## Byte-at-a-Time Block Cipher Attack (UTCTF 2024)\n\n**Pattern (PES-128):** First output byte depends only on first input byte (no diffusion).\n\n**Attack:** For each position, try all 256 byte values, compare output byte with target ciphertext. One match per byte = full plaintext recovery without knowing the key.\n\n**Detection:** Change one input byte → only corresponding output byte changes. This means zero cross-byte diffusion = trivially breakable.\n\n---\n\n## Mathematical Convergence Bitmap (EHAX 2026)\n\n**Pattern (Compute It):** Binary classifies complex-plane coordinates by Newton's method convergence. The classification results, arranged as a grid, spell out the flag in ASCII art.\n\n**Recognition:**\n- Input file with coordinate pairs (x, y)\n- Binary iterates a mathematical function (e.g., z^3 - 1 = 0) and outputs pass/fail\n- Grid dimensions hinted by point count (e.g., 2600 = 130×20)\n- 5-pixel-high ASCII art font common in CTFs\n\n**Newton's method for z^3 - 1:**\n```python\ndef newton_converges_to_one(px, py, max_iter=50, target_count=12):\n \"\"\"Returns True if Newton's method converges to z=1 in exactly target_count steps.\"\"\"\n x, y = px, py\n count = 0\n for _ in range(max_iter):\n f_real = x**3 - 3*x*y**2 - 1.0\n f_imag = 3*x**2*y - y**3\n J_rr = 3.0 * (x**2 - y**2)\n J_ri = 6.0 * x * y\n det = J_rr**2 + J_ri**2\n if det \u003c 1e-9:\n break\n x -= (f_real * J_rr + f_imag * J_ri) / det\n y -= (f_imag * J_rr - f_real * J_ri) / det\n count += 1\n if abs(x - 1.0) \u003c 1e-6 and abs(y) \u003c 1e-6:\n break\n return count == target_count\n\n# Read coordinates and render bitmap\npoints = [(float(x), float(y)) for x, y in ...]\nbits = [1 if newton_converges_to_one(px, py) else 0 for px, py in points]\nWIDTH = 130 # 2600 / 20 rows\nfor r in range(len(bits) // WIDTH):\n print(''.join('#' if bits[r*WIDTH+c] else '.' for c in range(WIDTH)))\n```\n\n**Key insight:** The binary is a mathematical classifier, not a flag checker. The flag is in the visual pattern of classifications, not in the binary's output. Reverse-engineer the math, apply to all coordinates, and visualize as bitmap.\n\n---\n\n## Windows PE XOR Bitmap Extraction + OCR (srdnlenCTF 2026)\n\n**Pattern (Artistic Warmup):** Binary renders input text, compares rendered bitmap against expected pixel data stored XOR'd with constant in `.rdata`. No need to compute — extract expected pixels directly.\n\n**Attack:**\n1. Reverse the core check function to identify rendering and comparison logic\n2. Find the expected pixel blob in `.rdata` (look for large data block referenced near comparison)\n3. XOR with constant (e.g., 0xAA) to recover expected rendered DIB\n4. Save as image and OCR to recover flag text\n\n```python\nimport numpy as np\nfrom PIL import Image\n\nwith open(\"binary.exe\", \"rb\") as f:\n data = f.read()\n\n# Extract from .rdata section (offsets from reversing)\nblob_offset = 0xC3620 # .rdata offset to XOR'd blob\nblob_size = 0x15F90 # 450 * 50 * 4 (BGRA)\nblob = np.frombuffer(data[blob_offset:blob_offset + blob_size], dtype=np.uint8)\nexpected = blob ^ 0xAA # XOR with constant key\n\n# Reshape as BGRA image (dimensions from reversing)\nimg = expected.reshape(50, 450, 4)\nchannel = img[:, :, 0] # Take one channel (grayscale text)\nImage.fromarray(channel, \"L\").save(\"target.png\")\n\n# OCR with charset whitelist\nimport subprocess\nresult = subprocess.run(\n [\"tesseract\", \"target.png\", \"stdout\", \"-c\",\n \"tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_\"],\n capture_output=True, text=True)\nprint(result.stdout)\n```\n\n**Key insight:** When a binary renders text and compares pixels, the expected pixel data is the flag rendered as an image. Extract it directly from the binary data section without needing to understand the rendering logic. OCR with charset whitelist improves accuracy for CTF flag characters.\n\n---\n\n## Two-Stage Loader: RC4 Gate + VM Constraints (srdnlenCTF 2026)\n\n**Pattern (Cornflake v3.5):** Two-stage malware loader — stage 1 uses RC4 username gate, stage 2 downloaded from C2 contains VM-based password validation.\n\n**Stage 1 — RC4 username recovery:**\n```python\ndef rc4(key, data):\n s = list(range(256))\n j = 0\n for i in range(256):\n j = (j + s[i] + key[i % len(key)]) & 0xFF\n s[i], s[j] = s[j], s[i]\n i = j = 0\n out = bytearray()\n for b in data:\n i = (i + 1) & 0xFF\n j = (j + s[i]) & 0xFF\n s[i], s[j] = s[j], s[i]\n out.append(b ^ s[(s[i] + s[j]) & 0xFF])\n return bytes(out)\n\n# Key from binary strings, ciphertext from stored hex\nusername = rc4(b\"s3cr3t_k3y_v1\", bytes.fromhex(\"46f5289437bc009c17817e997ae82bfbd065545d\"))\n```\n\n**Stage 2 — VM constraint extraction:**\n1. Download stage 2 from C2 endpoint (e.g., `/updates/check.php`)\n2. Reverse VM bytecode interpreter (typically 15-20 opcodes)\n3. Extract linear equality constraints over flag characters\n4. Solve constraint system (Z3 or manual)\n\n**Key insight:** Multi-stage loaders often use simple crypto (RC4) for the first gate and more complex validation (custom VM) for the second. The VM memory may be uninitialized (all zeros), drastically simplifying constraint extraction since memory-dependent operations become constants.\n\n---\n\n## Kernel Module Maze Solving (DiceCTF 2026)\n\n**Pattern (Explorer):** Rust kernel module implements a 3D maze via `/dev/challenge` ioctls. Navigate the maze, avoid decoy exits (status=2), find the real exit (status=1), read the flag.\n\n**Ioctl enumeration:**\n| Command | Description |\n|---------|-------------|\n| `0x80046481-83` | Get maze dimensions (3 axes, 8-16 each) |\n| `0x80046485` | Get status: 0=playing, 1=WIN, 2=decoy |\n| `0x80046486` | Get wall bitfield (6 directions) |\n| `0x80406487` | Get flag (64 bytes, only when status=1) |\n| `0x40046488` | Move in direction (0-5) |\n| `0x6489` | Reset position |\n\n**DFS solver with decoy avoidance:**\n```c\n// Minimal static binary using raw syscalls (no libc) for small upload size\n// gcc -nostdlib -static -Os -fno-builtin -o solve solve.c -Wl,--gc-sections && strip solve\n\nint visited[16][16][16];\nint bad[16][16][16]; // decoy positions across resets\n\nvoid dfs(int fd, int x, int y, int z) {\n if (visited[x][y][z] || bad[x][y][z]) return;\n visited[x][y][z] = 1;\n\n int status = ioctl_get_status(fd);\n if (status == 1) { read_flag(fd); exit(0); }\n if (status == 2) { bad[x][y][z] = 1; return; } // decoy — mark bad\n\n int walls = ioctl_get_walls(fd);\n int dx[] = {1,-1,0,0,0,0}, dy[] = {0,0,1,-1,0,0}, dz[] = {0,0,0,0,1,-1};\n int opp[] = {2,3,0,1,5,4}; // opposite directions for backtracking\n\n for (int dir = 0; dir \u003c 6; dir++) {\n if (!(walls & (1 \u003c\u003c dir))) continue; // wall present\n ioctl_move(fd, dir);\n dfs(fd, x+dx[dir], y+dy[dir], z+dz[dir]);\n ioctl_move(fd, opp[dir]); // backtrack\n }\n}\n// After decoy hit: reset via ioctl 0x6489, clear visited, re-run DFS\n```\n\n**Remote deployment:** Upload binary via base64 chunks over netcat shell, decode, execute.\n\n**Key insight:** For kernel module challenges, injecting test binaries into initramfs and probing ioctls dynamically is faster than static RE of stripped kernel modules. Keep solver binary minimal (raw syscalls, no libc) for fast upload.\n\n---\n\n## Multi-Threaded VM with Channel Synchronization (DiceCTF 2026)\n\n**Pattern (locked-in):** Custom stack-based VM runs 16 concurrent threads verifying a 30-char flag. Threads communicate via futex-based channels. Pipeline: input → XOR scramble → transformation → base-4 state machine → final check.\n\n**Analysis approach:**\n1. **Identify thread roles** by tracing channel read/write patterns in GDB\n2. **Extract constants** (XOR scramble values, lookup tables) via breakpoints on specific opcodes\n3. **Watch for inverted logic:** validity check returns 0 for valid, non-zero for blocked (opposite of intuition)\n4. **Detect futex quirks:** `unlock_pi` on unowned mutex returns EPERM=1, which can change all computations\n\n**BFS state space search for constrained state machines:**\n```python\nfrom collections import deque\n\ndef solve_flag(scramble_vals, lookup_table, initial_state, target_state):\n \"\"\"BFS through state machine to find valid flag bytes.\"\"\"\n flag = [None] * 30\n # Known prefix/suffix from flag format\n flag[0:5] = list(b'dice{')\n flag[29] = ord('}')\n\n # For each unknown position, try all printable ASCII\n states = {initial_state}\n for pos in range(28, 4, -1): # processed in reverse\n next_states = {}\n for state in states:\n for ch in range(32, 127):\n transformed = transform(ch, scramble_vals[pos])\n digits = to_base4(transformed)\n new_state = apply_digits(state, digits, lookup_table)\n if new_state is not None: # valid path exists\n next_states.setdefault(new_state, []).append((state, ch))\n states = set(next_states.keys())\n\n # Trace back from target_state to recover flag\n```\n\n**Key insight:** Multi-threaded VMs require tracing data flow across thread boundaries. Channel-based communication creates a pipeline — identify each thread's role (input, transform, validate, output) by watching which channels it reads/writes. Constants that affect computation may come from unexpected sources (futex return values, thread IDs).\n\n---\n\n## Backdoored Shared Library Detection via String Diffing (Hack.lu CTF 2012)\n\n**Pattern (Zombie Lockbox):** A setuid binary uses `strcmp` for password validation. The expected password is visible via `strings` and works under GDB (which drops suid), but fails when run normally. The binary links against a non-standard libc that patches function behavior based on suid status.\n\n**Detection steps:**\n1. Check for non-standard library paths with `ldd`:\n```bash\nldd ./binary\n# Suspicious: libc.so.6 => /lib/libc/libc.so.6 (non-standard path)\n# Normal: libc.so.6 => /lib32/libc.so.6\n```\n\n2. Diff strings between the suspicious and system libc:\n```bash\nstrings /lib/libc/libc.so.6 > suspicious_strings\nstrings /lib32/libc-2.15.so > normal_strings\ndiff suspicious_strings normal_strings\n```\n\n3. Disassemble the patched function (e.g., `puts`) to find injected code:\n```bash\ngdb /lib/libc/libc.so.6\n(gdb) disas puts\n# Look for unexpected calls or branches\n# Injected code may check suid status (getuid/geteuid syscalls)\n# and swap the expected password at runtime\n```\n\n**Key insight:** When a binary behaves differently under GDB vs. normal execution, check `ldd` for non-standard library paths. Suid binaries drop privileges under debuggers, so a backdoored libc can detect this via `getuid`/`geteuid` syscalls and change program behavior accordingly. The `strings | diff` approach quickly reveals injected data without full disassembly.\n\n---\n\n---\n\n## Custom binfmt Kernel Module with RC4 Flat Binaries (BSidesSF 2026)\n\n**Pattern (Private Binary):** A custom Linux kernel module (`.ko`) registers a `binfmt` handler for non-standard binary formats. When a file with a specific magic number is executed, the kernel module intercepts it, decrypts the contents in memory, and jumps to the entry point.\n\n**Reverse engineering approach:**\n1. **Analyze the `.ko`:** Look for `register_binfmt()` call — it registers a `struct linux_binfmt` with a `load_binary` callback\n2. **Find the magic number:** The `load_binary` function checks the file's first bytes against a specific magic number to identify its format\n3. **Extract the encryption key:** Look for `movabs` instructions loading 8-byte constants — these are often RC4 key bytes\n4. **Identify the encryption scheme:** Common choices are RC4, XOR, or AES-ECB. RC4 is identifiable by the S-box initialization loop (256-byte array, swap pattern)\n5. **Decrypt the flat binary:** Apply the recovered key to the encrypted file contents, skipping any header\n\n```python\nfrom Crypto.Cipher import ARC4\n\n# Extract RC4 key from kernel module (found via movabs instructions)\nkey = bytes([0x41, 0x42, 0x43, ...]) # Key bytes from .ko disassembly\n\nwith open('encrypted.bin', 'rb') as f:\n header = f.read(HEADER_SIZE) # Skip binfmt header\n encrypted = f.read()\n\ncipher = ARC4.new(key)\ndecrypted = cipher.decrypt(encrypted)\n\n# The decrypted output is a flat binary (no ELF headers)\n# Load at the fixed virtual address specified in the kernel module\n# Disassemble with: objdump -b binary -m i386:x86-64 -D decrypted.bin\n# Or in Ghidra: import as \"Raw Binary\", set base address from .ko\n```\n\n**Detection in kernel module:**\n- `register_binfmt` / `unregister_binfmt` calls\n- `vm_mmap()` or `vm_brk()` for memory allocation at fixed addresses\n- Direct jump to mapped memory (entry point execution)\n- S-box initialization pattern (RC4): loop 0-255, swap `S[i]` with `S[j]`\n\n**Key insight:** The flat binary has no ELF headers, so standard tools won't recognize it. You must extract the load address from the kernel module (look for the `vm_mmap` call's address argument) and import the decrypted blob at that address in your disassembler. RC4 keys in kernel modules are often stored as immediate values in `mov` or `movabs` instructions rather than in data sections.\n\n**References:** BSidesSF 2026 \"Private Binary\"\n\n---\n\n## Hash-Resolved Imports / No-Import Ransomware (BSidesSF 2026)\n\n**Pattern (Ran Somewhere):** Malware binary has zero visible imports — all API calls are resolved at runtime by hashing symbol names and comparing against pre-computed hash values. The binary uses `dlopen` + a custom hash table to find libc and libcrypto functions.\n\n**Identification:**\n- `readelf -d` shows no dynamic symbols or very few (just `dlopen`/`dlsym`)\n- Strings reveal no standard API names\n- Disassembly shows hash computation loops followed by indirect calls\n- RC4-encrypted embedded strings (RSA public key, file paths, passphrases)\n\n**Analysis shortcut — LD_PRELOAD key extraction:**\n\nRather than reversing the full hash resolution and key derivation, hook the crypto functions that the malware ultimately calls:\n\n```c\n// hook_crypto.c — captures AES key used by the ransomware\n#define _GNU_SOURCE\n#include \u003cdlfcn.h>\n#include \u003copenssl/evp.h>\n#include \u003cstdio.h>\n\nint EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,\n ENGINE *impl, const unsigned char *key,\n const unsigned char *iv) {\n if (key) {\n FILE *f = fopen(\"/tmp/aes_key.bin\", \"wb\");\n fwrite(key, 1, 32, f); // AES-256\n fclose(f);\n fprintf(stderr, \"[HOOK] AES key captured\\n\");\n }\n typedef int (*orig_t)(EVP_CIPHER_CTX*, const EVP_CIPHER*, ENGINE*,\n const unsigned char*, const unsigned char*);\n orig_t orig = (orig_t)dlsym(RTLD_NEXT, \"EVP_CipherInit_ex\");\n return orig(ctx, type, impl, key, iv);\n}\n```\n\n```bash\n# Compile and run\ngcc -shared -fPIC -o hook.so hook_crypto.c -ldl\n# Run in Docker container (ransomware may be destructive!)\ndocker run --rm -v $(pwd):/work -w /work ubuntu:22.04 \\\n bash -c \"LD_PRELOAD=./hook.so ./ransomware; xxd /tmp/aes_key.bin\"\n```\n\n**Hash resolution patterns:**\n- **SipHash variant:** Two 64-bit seeds, iterative mixing with symbol name bytes\n- **DJB2/FNV variants:** Simpler hash functions with recognizable constants (`5381`, `0xcbf29ce484222325`)\n- **ROR13-based:** Windows malware favorite: `hash = (hash >> 13) | (hash \u003c\u003c 19); hash += c`\n\n**Decryption after key capture:**\n```python\nfrom Crypto.Cipher import AES\n\nkey = open('/tmp/aes_key.bin', 'rb').read()\niv = open('/tmp/aes_iv.bin', 'rb').read() # Also hookable\ncipher = AES.new(key, AES.MODE_CBC, iv)\n\nwith open('flag.txt.enc', 'rb') as f:\n ct = f.read()\npt = cipher.decrypt(ct)\n# Remove PKCS7 padding\npt = pt[:-pt[-1]]\nprint(pt.decode())\n```\n\n**Key insight:** When a binary resolves all imports via hashing, don't waste time reversing the hash function and building a rainbow table. Instead, let the malware resolve everything itself by running it in a sandboxed environment with `LD_PRELOAD` hooks on the functions you care about (OpenSSL crypto functions, file I/O, network calls). The AES key is deterministic across runs — if it works once, it works always.\n\n**Safety:** Always run suspected ransomware in a Docker container or VM. Mount only copies of the encrypted files, never originals.\n\n**References:** BSidesSF 2026 \"Ran Somewhere\"\n\n---\n\n## ELF Section Header Corruption for Anti-Analysis (BSidesSF 2026)\n\n**Pattern (stubborn-elf):** An ELF binary has deliberately corrupted section header table entries, causing standard analysis tools (`readelf`, `objdump`, IDA, Ghidra) to crash or produce errors. However, the **program headers** (which the OS loader uses) are intact, so the binary executes normally. The flag is appended after the corrupted sections, marked with magic bytes.\n\n```python\nimport sys\n\n# Standard tools fail on corrupted section headers\n# Manual parsing bypasses section headers entirely\n\nwith open(\"stubborn_elf\", \"rb\") as f:\n data = f.read()\n\n# Search for magic marker appended after ELF sections\nmagic = b\"\\xDE\\xAD\\xBE\\xEF\\xCA\\xFE\\xBA\\xBE\"\nidx = data.find(magic)\nif idx >= 0:\n # Data after magic is XOR-encrypted\n encrypted = data[idx + len(magic):]\n decrypted = bytes(b ^ 0x42 for b in encrypted)\n print(decrypted.decode(errors='ignore'))\n```\n\n**Key insight:** ELF execution requires **program headers** (PT_LOAD segments), NOT section headers. Section headers are metadata for debuggers and analysis tools — they're optional at runtime. Corrupting `e_shoff`, `e_shnum`, or `e_shstrndx` in the ELF header breaks tools but not execution. When tools fail, parse the binary manually or patch the ELF header to zero out section header references before loading in a disassembler.\n\n**Recovery approach:**\n```bash\n# Patch section header offset to 0 (removes section table)\nprintf '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00' | dd of=binary bs=1 seek=40 conv=notrunc\n# Now Ghidra/IDA can load it using program headers only\n\n# Or use readelf -l (program headers only, ignores sections)\nreadelf -l stubborn_elf\n```\n\n**When to recognize:** `readelf -S` crashes or shows garbage. `file` command identifies it as ELF. `readelf -l` (lowercase L, program headers) works fine. The binary runs normally despite tool failures.\n\n**References:** BSidesSF 2026 \"stubborn-elf\"\n\n---\n\nSee also: [patterns-ctf-2.md](patterns-ctf-2.md) for Part 2 (multi-layer self-decrypting binary, embedded ZIP+XOR license, stack string deobfuscation, prefix hash brute-force, CVP/LLL lattice, decision tree obfuscation, GF(2^8) Gaussian elimination), [patterns-ctf-3.md](patterns-ctf-3.md) for Part 3 (Z3 boolean circuit, sliding window popcount, keyboard LED Morse code, C++ destructor-hidden validation, VM sequential key-chain brute-force, BWT inversion, OpenType font ligature exploitation, GLSL shader VM with self-modifying code).\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":24249,"content_sha256":"41edf048db36c3cb6ab1264f226df920adfa27923844a9ec5b40664ffe655c27"},{"filename":"patterns.md","content":"# CTF Reverse - Patterns & Techniques\n\n## Table of Contents\n- [Custom VM Reversing](#custom-vm-reversing)\n - [Analysis Steps](#analysis-steps)\n - [Common VM Patterns](#common-vm-patterns)\n - [RVA-Based Opcode Dispatching](#rva-based-opcode-dispatching)\n - [State Machine VMs (90K+ states)](#state-machine-vms-90k-states)\n - [Custom VM Reverse Engineering via Fuzzing and Instruction Set Discovery (hxp CTF 2017)](#custom-vm-reverse-engineering-via-fuzzing-and-instruction-set-discovery-hxp-ctf-2017)\n- [Anti-Debugging Techniques](#anti-debugging-techniques)\n - [Common Checks](#common-checks)\n - [Bypass Technique](#bypass-technique)\n - [LD_PRELOAD Hook](#ld_preload-hook)\n - [pwntools Binary Patching (Crypto-Cat)](#pwntools-binary-patching-crypto-cat)\n- [Nanomites](#nanomites)\n - [Linux (Signal-Based)](#linux-signal-based)\n - [Windows (Debug Events)](#windows-debug-events)\n - [Analysis](#analysis)\n- [Self-Modifying Code](#self-modifying-code)\n - [Pattern: XOR Decryption](#pattern-xor-decryption)\n- [Known-Plaintext XOR (Flag Prefix)](#known-plaintext-xor-flag-prefix)\n - [Variant: XOR with Position Index](#variant-xor-with-position-index)\n- [Mixed-Mode (x86-64 / x86) Stagers](#mixed-mode-x86-64--x86-stagers)\n- [LLVM (Low Level Virtual Machine) Obfuscation (Control Flow Flattening)](#llvm-low-level-virtual-machine-obfuscation-control-flow-flattening)\n - [Pattern](#pattern)\n - [De-obfuscation](#de-obfuscation)\n- [S-Box / Keystream Generation](#s-box--keystream-generation)\n - [Fisher-Yates Shuffle (Xorshift32)](#fisher-yates-shuffle-xorshift32)\n - [Xorshift64* Keystream](#xorshift64-keystream)\n - [Identifying Patterns](#identifying-patterns)\n- [SECCOMP/BPF Filter Analysis](#seccompbpf-filter-analysis)\n - [BPF Analysis](#bpf-analysis)\n- [Exception Handler Obfuscation](#exception-handler-obfuscation)\n - [RtlInstallFunctionTableCallback](#rtlinstallfunctiontablecallback)\n - [Vectored Exception Handlers (VEH)](#vectored-exception-handlers-veh)\n- [Memory Dump Analysis](#memory-dump-analysis)\n - [When Binary Dumps Memory](#when-binary-dumps-memory)\n - [Known Plaintext Attack](#known-plaintext-attack)\n- [Byte-Wise Uniform Transforms](#byte-wise-uniform-transforms)\n- [x86-64 Gotchas](#x86-64-gotchas)\n - [Sign Extension](#sign-extension)\n - [Loop Boundary State Updates](#loop-boundary-state-updates)\n- [Custom Mangle Function Reversing](#custom-mangle-function-reversing)\n- [Position-Based Transformation Reversing](#position-based-transformation-reversing)\n- [Hex-Encoded String Comparison](#hex-encoded-string-comparison)\n- [Signal-Based Binary Exploration](#signal-based-binary-exploration)\n- [Malware Anti-Analysis Bypass via Patching](#malware-anti-analysis-bypass-via-patching)\n- [Multi-Stage Shellcode Loaders](#multi-stage-shellcode-loaders)\n- [Timing Side-Channel Attack](#timing-side-channel-attack)\n- [Multi-Thread Anti-Debug with Decoy + Signal Handler Mixed Boolean-Arithmetic (ApoorvCTF 2026)](#multi-thread-anti-debug-with-decoy--signal-handler-mixed-boolean-arithmetic-apoorvctf-2026)\n- [INT3 Patch + Coredump Brute-Force Oracle (Pwn2Win 2016)](#int3-patch--coredump-brute-force-oracle-pwn2win-2016)\n- [Signal Handler Chain + LD_PRELOAD Oracle (Nuit du Hack 2016)](#signal-handler-chain--ld_preload-oracle-nuit-du-hack-2016)\n- [printf Format String VM Decompilation to Z3 (SECCON 2017)](#printf-format-string-vm-decompilation-to-z3-seccon-2017)\n\n---\n\n## Custom VM Reversing\n\n### Analysis Steps\n1. Identify VM structure: registers, memory, instruction pointer\n2. Reverse `executeIns`/`runvm` function for opcode meanings\n3. Write a disassembler to parse bytecode\n4. Decompile disassembly to understand algorithm\n\n### Common VM Patterns\n```c\nswitch (opcode) {\n case 1: *R[op1] *= op2; break; // MUL\n case 2: *R[op1] -= op2; break; // SUB\n case 3: *R[op1] = ~*R[op1]; break; // NOT\n case 4: *R[op1] ^= mem[op2]; break; // XOR\n case 5: *R[op1] = *R[op2]; break; // MOV\n case 7: if (R0) IP += op1; break; // JNZ\n case 8: putc(R0); break; // PRINT\n case 10: R0 = getc(); break; // INPUT\n}\n```\n\n### RVA-Based Opcode Dispatching\n- Opcodes are RVAs pointing to handler functions\n- Handler performs operation, reads next RVA, jumps\n- Map all handlers by following RVA chain\n\n### State Machine VMs (90K+ states)\n```java\n// BFS for valid path\nvar agenda = new ArrayDeque\u003cState>();\nagenda.add(new State(0, \"\"));\nwhile (!agenda.isEmpty()) {\n var current = agenda.remove();\n if (current.path.length() == TARGET_LENGTH) {\n println(current.path);\n continue;\n }\n for (var transition : machine.get(current.state).entrySet()) {\n agenda.add(new State(transition.getValue(),\n current.path + (char)transition.getKey()));\n }\n}\n```\n\n**Key insight:** Custom VMs appear when the challenge bundles a bytecode blob alongside a dispatcher loop. Reverse the opcode switch table first, then write a disassembler to lift the bytecode before attempting to understand the algorithm.\n\n### Custom VM Reverse Engineering via Fuzzing and Instruction Set Discovery (hxp CTF 2017)\n\nMethodical black-box approach to reversing unknown VM bytecode when static analysis of the dispatch loop is too complex:\n\n**Step 1: Determine instruction alignment.**\nDump the bytecode as bit strings at various widths (6-11 bits) to identify instruction alignment. Look for repeating patterns that suggest opcode boundaries.\n\n**Step 2: Fuzz with random bytes.**\nSend single instructions and observe effects on registers/memory to map opcodes. Reduce to minimal programs: find the shortest input that produces each observable effect.\n\n**Step 3: Build the instruction set.**\nExample discovered ISA (variable-length 6-11 bit):\n```text\n000 xxxxxxxx jmpz 001 xxxxxxxx jmp 010 xxxxxxxx call\n011 xxxxxxxx label 1000 xxxxxxx loadram 1001 xxxxxxx saveram\n110 xxxxxxxx loadi 11100 xxxxxx shl 11101 xxxxxx shr\n111100 not 111101 and 111110 or 111111 setif\n```\n\n**Step 4: Build assembler/disassembler.**\nWrite tools to assemble and disassemble the discovered ISA, then disassemble the challenge bytecode to understand its algorithm.\n\n**Step 5: Implement missing primitives.**\nIf the ISA lacks expected operations, synthesize them from available instructions. Example: implementing XTEA decryption using only AND/OR/NOT (no native XOR or ADD):\n```python\n# XOR from AND/OR/NOT: XOR(a, b) = (a OR b) AND NOT(a AND b)\n# ADD via full-adder chains using AND/OR/NOT for carry propagation\ndef xor_from_primitives(a, b):\n return (a | b) & ~(a & b)\n\ndef add_from_primitives(a, b, bits=32):\n carry = 0\n result = 0\n for i in range(bits):\n ai = (a >> i) & 1\n bi = (b >> i) & 1\n sum_bit = xor_from_primitives(xor_from_primitives(ai, bi), carry)\n carry = (ai & bi) | (carry & xor_from_primitives(ai, bi))\n result |= (sum_bit \u003c\u003c i)\n return result\n```\n\n**Key insight:** When static analysis of a VM's dispatch loop is too complex, black-box fuzzing can map the ISA faster. Send single instructions and observe state changes. Variable-length instruction sets require testing multiple bit widths. Once the ISA is known, complex algorithms (XTEA) can be implemented even with minimal primitives (AND/OR/NOT).\n\n**References:** hxp CTF 2017\n\n---\n\n## Anti-Debugging Techniques\n\n### Common Checks\n- `IsDebuggerPresent()` (Windows)\n- `ptrace(PTRACE_TRACEME)` (Linux)\n- `/proc/self/status` TracerPid\n- Timing checks (`rdtsc`, `time()`)\n- Registry checks (Windows)\n\n### Bypass Technique\n1. Identify `test` instructions after debug checks\n2. Set breakpoint at the `test`\n3. Modify register to bypass conditional\n\n```bash\n# In radare2\ndb 0x401234 # Break at test\ndc # Run\ndr eax=0 # Clear flag\ndc # Continue\n```\n\n### LD_PRELOAD Hook\n```c\n#define _GNU_SOURCE\n#include \u003cdlfcn.h>\n#include \u003csys/ptrace.h>\n\nlong int ptrace(enum __ptrace_request req, ...) {\n long int (*orig)(enum __ptrace_request, pid_t, void*, void*);\n orig = dlsym(RTLD_NEXT, \"ptrace\");\n // Log or modify behavior\n return orig(req, pid, addr, data);\n}\n```\n\nCompile: `gcc -shared -fPIC -ldl hook.c -o hook.so`\nRun: `LD_PRELOAD=./hook.so ./binary`\n\n**Key insight:** Anti-debugging checks are the first obstacle in most reversing challenges. Look for `ptrace`, `IsDebuggerPresent`, or timing checks early in `main()` and patch or hook them before attempting deeper analysis.\n\n### pwntools Binary Patching (Crypto-Cat)\nPatch out anti-debug calls directly using pwntools — replaces function with `ret` instruction:\n```python\nfrom pwn import *\n\nelf = ELF('./challenge', checksec=False)\nelf.asm(elf.symbols.ptrace, 'ret') # Replace ptrace() with immediate return\nelf.save('patched') # Save patched binary\n```\n\nOther common patches:\n```python\nelf.asm(addr, 'nop') # NOP out an instruction\nelf.asm(addr, 'xor eax, eax; ret') # Return 0 (bypass checks)\nelf.asm(addr, 'mov eax, 1; ret') # Return 1 (force success)\n```\n\n---\n\n## Nanomites\n\n### Linux (Signal-Based)\n- `SIGTRAP` (`int 3`) → Custom operation\n- `SIGILL` (`ud2`) → Custom operation\n- `SIGFPE` (`idiv 0`) → Custom operation\n- `SIGSEGV` (null deref) → Custom operation\n\n### Windows (Debug Events)\n- `EXCEPTION_DEBUG_EVENT` → Main handler\n- Parent modifies child via `PTRACE_POKETEXT`\n- Magic markers: `0x1337BABE`, `0xDEADC0DE`\n\n### Analysis\n1. Check for `fork()` + `ptrace(PTRACE_TRACEME)`\n2. Find `WaitForDebugEvent` loop\n3. Map EAX values to operations\n4. Log operations to reconstruct algorithm\n\n**Key insight:** Nanomites hide the real computation inside signal/exception handlers that only fire under a debugger parent. If the binary forks and the child calls `ptrace(TRACEME)`, the parent is the real CPU -- log its POKE operations to reconstruct the algorithm.\n\n---\n\n## Self-Modifying Code\n\n### Pattern: XOR Decryption\n```asm\nlea rax, next_block\nmov dl, [rcx] ; Input char\nxor_loop:\n xor [rax+rbx], dl\n inc rbx\n cmp rbx, BLOCK_SIZE\n jnz xor_loop\njmp rax ; Execute decrypted\n```\n\n**Solution:** Known opcode at block start reveals XOR key (flag char).\n\n**Key insight:** Self-modifying code decrypts the next block using each input character as a key. A known-good opcode at the start of each decrypted block (e.g., function prologue) reveals the correct key byte, recovering the flag one character at a time.\n\n---\n\n## Known-Plaintext XOR (Flag Prefix)\n\n**Pattern:** Encrypted bytes given; flag format known (e.g., `0xL4ugh{`).\n\n**Approach:**\n1. Assume repeating XOR key.\n2. Use known prefix (and any hint phrase) to recover key bytes.\n3. Try small key lengths and validate printable output.\n\n```python\nenc = bytes.fromhex(\"...\") # ciphertext\nknown = b\"0xL4ugh{say_yes_to_me\"\nfor klen in range(2, 33):\n key = bytearray(klen)\n ok = True\n for i, b in enumerate(known):\n if i >= len(enc):\n break\n ki = i % klen\n v = enc[i] ^ b\n if key[ki] != 0 and key[ki] != v:\n ok = False\n break\n key[ki] = v\n if not ok:\n continue\n pt = bytes(enc[i] ^ key[i % klen] for i in range(len(enc)))\n if all(32 \u003c= c \u003c 127 for c in pt):\n print(klen, key, pt)\n```\n\n**Note:** Challenge hints often appear verbatim in the flag body (e.g., \"say_yes_to_me\").\n\n### Variant: XOR with Position Index\n**Pattern:** `cipher[i] = plain[i] ^ key[i % k] ^ i` (or `^ (i & 0xff)`).\n\n**Symptoms:**\n- Repeating-key XOR almost fits known prefix but breaks at later positions\n- XOR with known prefix yields a \"key\" that changes by +1 per index\n\n**Fix:** Remove index first, then recover key with known prefix.\n```python\nenc = bytes.fromhex(\"...\")\nknown = b\"0xL4ugh{say_yes_to_me\"\nfor klen in range(2, 33):\n key = bytearray(klen)\n ok = True\n for i, b in enumerate(known):\n if i >= len(enc):\n break\n ki = i % klen\n v = (enc[i] ^ i) ^ b # strip index XOR\n if key[ki] != 0 and key[ki] != v:\n ok = False\n break\n key[ki] = v\n if not ok:\n continue\n pt = bytes((enc[i] ^ i) ^ key[i % klen] for i in range(len(enc)))\n if all(32 \u003c= c \u003c 127 for c in pt):\n print(klen, key, pt)\n```\n\n---\n\n## Mixed-Mode (x86-64 / x86) Stagers\n\n**Pattern:** 64-bit ELF jumps into a 32-bit blob via far return (`retf`/`retfq`), often after anti-debug.\n\n**Identification:**\n- Bytes `0xCB` (retf) or `0xCA` (retf imm16), sometimes preceded by `0x48` (retfq)\n- 32-bit disasm shows SSE ops (`psubb`, `pxor`, `paddb`) in a tight loop\n- Computed jumps into the 32-bit region\n\n**Gotchas:**\n- `retf` pops **6 bytes**: 4-byte EIP + 2-byte CS (not 8)\n- 32-bit blob may rely on inherited **XMM state** and **EFLAGS**\n- Missing XMM/flags transfer when switching emulators yields wrong output\n\n**Bypass/Emulation Tips:**\n1. Create a UC_MODE_32 emulator, copy memory + GPRs, **EFLAGS**, and **XMM regs**\n2. Run 32-bit block, then copy memory + regs back to 64-bit\n3. If anti-debug uses `fork/ptrace` + patching, emulate parent to log POKEs and apply them in child\n\n---\n\n## LLVM (Low Level Virtual Machine) Obfuscation (Control Flow Flattening)\n\n### Pattern\n```c\nwhile (1) {\n if (i == 0xA57D3848) { /* block */ }\n if (i != 0xA5AA2438) break;\n i = 0x39ABA8E6; // Next state\n}\n```\n\n### De-obfuscation\n1. GDB script to break at `je` instructions\n2. Log state variable values\n3. Map state transitions\n4. Reconstruct true control flow\n\n**Key insight:** Control flow flattening replaces structured if/else/loops with a single dispatcher switch. The state variable is the key -- trace its values at runtime to reconstruct the original control flow graph without fighting the obfuscation statically.\n\n---\n\n## S-Box / Keystream Generation\n\n### Fisher-Yates Shuffle (Xorshift32)\n```python\ndef gen_sbox():\n sbox = list(range(256))\n state = SEED\n for i in range(255, -1, -1):\n state = ((state \u003c\u003c 13) ^ state) & 0xffffffff\n state = ((state >> 17) ^ state) & 0xffffffff\n state = ((state \u003c\u003c 5) ^ state) & 0xffffffff\n j = state % (i + 1) if i > 0 else 0\n sbox[i], sbox[j] = sbox[j], sbox[i]\n return sbox\n```\n\n### Xorshift64* Keystream\n```python\ndef gen_keystream():\n ks = []\n state = SEED_64\n mul = 0x2545f4914f6cdd1d\n for _ in range(256):\n state ^= (state >> 12)\n state ^= (state \u003c\u003c 25)\n state ^= (state >> 27)\n state = (state * mul) & 0xffffffffffffffff\n ks.append((state >> 56) & 0xff)\n return ks\n```\n\n### Identifying Patterns\n- Xorshift32: shifts 13, 17, 5 (no multiplication constant)\n- Xorshift64*: shifts 12, 25, 27, then multiply by `0x2545f4914f6cdd1d`\n- Other common constant: `0x9e3779b97f4a7c15` (golden ratio)\n\n**Key insight:** Recognize S-box generation by the Fisher-Yates shuffle pattern (loop counting down from 255, swap with PRNG-chosen index) and keystream generators by the xorshift constants. Once the PRNG family is identified, the algorithm is fully determined by its seed.\n\n---\n\n## SECCOMP/BPF Filter Analysis\n\n```bash\nseccomp-tools dump ./binary\n```\n\n### BPF Analysis\n- `A = sys_number` followed by comparisons\n- `mem[N] = A`, `A = mem[N]` for memory ops\n- Map to constraint equations, solve with z3\n\n```python\nfrom z3 import *\nflag = [BitVec(f'c{i}', 32) for i in range(14)]\ns = Solver()\ns.add(flag[0] >= 0x20, flag[0] \u003c 0x7f)\n# Add constraints from filter\nif s.check() == sat:\n m = s.model()\n print(''.join(chr(m[c].as_long()) for c in flag))\n```\n\n**Key insight:** SECCOMP (Secure Computing Mode) filters encode flag validation as BPF bytecode operating on syscall arguments. Dump the filter with `seccomp-tools`, translate the comparisons and memory operations into z3 constraints, and solve for the flag without ever running the binary.\n\n---\n\n## Exception Handler Obfuscation\n\n### RtlInstallFunctionTableCallback\n- Dynamic exception handler registration\n- Handler installs new handler, modifies code\n- Use x64dbg with exception handler breaks\n\n### Vectored Exception Handlers (VEH)\n- `AddVectoredExceptionHandler` installs handler\n- Handler decrypts code at exception address\n- Step through, dump decrypted code\n\n**Key insight:** Exception-handler-based obfuscation hides the real control flow inside SEH/VEH handlers that trigger on deliberate faults. Set breakpoints inside the exception handlers rather than on the faulting instructions to follow the actual execution path.\n\n---\n\n## Memory Dump Analysis\n\n### When Binary Dumps Memory\n- Check for `/proc/self/maps` reads\n- Check for `/proc/self/mem` reads\n- Heap data often appended to dump\n\n### Known Plaintext Attack\n```python\nprologue = bytes([0xf3, 0x0f, 0x1e, 0xfa, 0x55, 0x48, 0x89, 0xe5])\nencrypted = data[func_offset:func_offset+8]\npartial_key = bytes(a ^ b for a, b in zip(encrypted, prologue))\n```\n\n**Key insight:** When a binary reads `/proc/self/mem` or `/proc/self/maps`, it is dumping its own memory -- possibly after encrypting it. Use known function prologues (`endbr64; push rbp; mov rbp, rsp`) as known plaintext to recover the XOR key from the encrypted dump.\n\n---\n\n## Byte-Wise Uniform Transforms\n\n**Pattern:** Output buffer depends on each input byte independently (no cross-byte coupling).\n\n**Detection:**\n- Change one input position → only one output position changes\n- Fill input with a single byte → output buffer becomes constant\n\n**Solve:**\n1. For each byte value 0..255, run the program with that byte repeated\n2. Record output byte → build mapping and inverse mapping\n3. Apply inverse mapping to static target bytes to recover the flag\n\n---\n\n## x86-64 Gotchas\n\n### Sign Extension\n```python\nesi = 0xffffffc7 # NOT -57\n\n# For XOR: low byte only\nesi_xor = esi & 0xff # 0xc7\n\n# For addition: full 32-bit with overflow\nr12 = (r13 + esi) & 0xffffffff\n```\n\n### Loop Boundary State Updates\nAssembly often splits state updates across loop boundaries:\n```asm\n jmp loop_middle ; First iteration in middle!\n\nloop_top: ; State for iterations 2+\n mov r13, sbox[a & 0xf]\n ; Uses OLD 'a', not new!\n\nloop_middle:\n ; Main computation\n inc a\n jne loop_top\n```\n\n**Key insight:** Decompilers often get x86-64 sign extension and loop boundary state updates wrong. Always verify decompiled output against the raw assembly for operations involving `movsx`/`cdqe`, and check whether loop variables update before or after their use in each iteration.\n\n---\n\n## Custom Mangle Function Reversing\n\n**Pattern (Flag Appraisal):** Binary mangles input 2 bytes at a time with intermediate state, compares to static target.\n\n**Approach:**\n1. Extract static target bytes from `.rodata` section\n2. Understand mangle: processes pairs with running state value\n3. Write inverse function (process in reverse, undo each operation)\n4. Feed target bytes through inverse → recovers flag\n\n**Key insight:** When a binary mangles input in pairs with running state and compares to a static target, extract the target from `.rodata` and write the inverse function. Process the target bytes in reverse order, undoing each operation, to recover the original input.\n\n---\n\n## Position-Based Transformation Reversing\n\n**Pattern (PascalCTF 2026):** Binary transforms input by adding/subtracting position index.\n\n**Reversing:**\n```python\nexpected = [...] # Extract from .rodata\nflag = ''\nfor i, b in enumerate(expected):\n if i % 2 == 0:\n flag += chr(b - i) # Even: input = output - i\n else:\n flag += chr(b + i) # Odd: input = output + i\n```\n\n---\n\n## Hex-Encoded String Comparison\n\n**Pattern (Spider's Curse):** Input converted to hex, compared against hex constant.\n\n**Quick solve:** Extract hex constant from strings/Ghidra, decode:\n```bash\necho \"4d65746143...\" | xxd -r -p\n```\n\n---\n\n## Signal-Based Binary Exploration\n\n**Pattern (Signal Signal Little Star):** Binary uses UNIX signals as a binary tree navigation mechanism.\n\n**Identification:**\n- Multiple `sigaction()` calls with `SA_SIGINFO`\n- `sigaltstack()` setup (alternate signal stack)\n- Handler decodes embedded payload, installs next pair of signals\n- Two types: Node (installs children) vs Leaf (prints message + exits)\n\n**Solving approach:**\n1. Hook `sigaction` via `LD_PRELOAD` to log signal installations\n2. DFS through the binary tree by sending signals\n3. At each stage, observe which 2 signals are installed\n4. Send one, check if program exits (leaf) or installs 2 more (node)\n5. If wrong leaf, backtrack and try sibling\n\n```c\n// LD_PRELOAD interposer to log sigaction calls\nint sigaction(int signum, const struct sigaction *act, ...) {\n if (act && (act->sa_flags & SA_SIGINFO))\n log(\"SET %d SA_SIGINFO=1\\n\", signum);\n return real_sigaction(signum, act, oldact);\n}\n```\n\n---\n\n## Malware Anti-Analysis Bypass via Patching\n\n**Pattern (Carrot):** Malware with multiple environment checks before executing payload.\n\n**Common checks to patch:**\n| Check | Technique | Patch |\n|-------|-----------|-------|\n| `ptrace(PTRACE_TRACEME)` | Anti-debug | Change `cmp -1` to `cmp 0` |\n| `sleep(150)` | Anti-sandbox timing | Change sleep value to 1 |\n| `/proc/cpuinfo` \"hypervisor\" | Anti-VM | Flip `JNZ` to `JZ` |\n| \"VMware\"/\"VirtualBox\" strings | Anti-VM | Flip `JNZ` to `JZ` |\n| `getpwuid` username check | Environment | Flip comparison |\n| `LD_PRELOAD` check | Anti-hook | Skip check |\n| Fan count / hardware check | Anti-VM | Flip `JLE` to `JGE` |\n| Hostname check | Environment | Flip `JNZ` to `JZ` |\n\n**Ghidra patching workflow:**\n1. Find check function, identify the conditional jump\n2. Click on instruction → `Ctrl+Shift+G` → modify opcode\n3. For `JNZ` (0x75) → `JZ` (0x74), or vice versa\n4. For immediate values: change operand bytes directly\n5. Export: press `O` → choose \"Original File\" format\n6. `chmod +x` the patched binary\n\n**Server-side validation bypass:**\n- If patched binary sends system info to remote server, patch the data too\n- Modify string addresses in data-gathering functions\n- Change format strings to embed correct values directly\n\n---\n\n## Multi-Stage Shellcode Loaders\n\n**Pattern (I Heard You Liked Loaders):** Nested shellcode with XOR decode loops and anti-debug.\n\n**Debugging workflow:**\n1. Break at `call rax` in launcher, step into shellcode\n2. Bypass ptrace anti-debug: step to syscall, `set $rax=0`\n3. Step through XOR decode loop (or break on `int3` if hidden)\n4. Repeat for each stage until final payload\n\n**Flag extraction from `mov` instructions:**\n```python\n# Final stage loads flag 4 bytes at a time via mov ebx, value\n# Extract little-endian 4-byte chunks\nvalues = [0x6174654d, 0x7b465443, ...] # From disassembly\nflag = b''.join(v.to_bytes(4, 'little') for v in values)\n```\n\n---\n\n## Timing Side-Channel Attack\n\n**Pattern (Clock Out):** Validation time varies per correct character (longer sleep on match).\n\n**Exploitation:**\n```python\nimport time\nfrom pwn import *\n\nflag = \"\"\nfor pos in range(flag_length):\n best_char, best_time = '', 0\n for c in string.printable:\n io = remote(host, port)\n start = time.time()\n io.sendline((flag + c).ljust(total_len, 'X'))\n io.recvall()\n elapsed = time.time() - start\n if elapsed > best_time:\n best_time = elapsed\n best_char = c\n io.close()\n flag += best_char\n```\n\n---\n\n## Multi-Thread Anti-Debug with Decoy + Signal Handler Mixed Boolean-Arithmetic (ApoorvCTF 2026)\n\n**Pattern (A Golden Experience Requiem):** Multi-threaded binary with layered anti-analysis: Thread 1 performs decoy operations (fake AES + deliberate crash via `ud2`), Thread 2 does the real flag computation in a SIGSEGV signal handler using Mixed Boolean Arithmetic (MBA), Thread 3 erases memory to prevent post-mortem analysis.\n\n**Thread layout:**\n| Thread | Purpose | Trap |\n|--------|---------|------|\n| Thread 1 | Decoy: AES-looking operations → `ud2` crash | Analysts waste time reversing fake crypto |\n| Thread 2 | Real flag: SIGSEGV handler with MBA transforms | Hidden in signal handler, not main code path |\n| Thread 3 | Memory eraser: zeros out flag data after computation | Prevents memory dumping |\n| Main | rdtsc-based anti-debug timing check | Penalizes debugger-attached execution |\n\n**Solving approach — pure Python emulation of MBA logic:**\n```python\n# MBA helpers (extracted from assembly)\ndef mba_add(a, b): return (a + b) & 0xff\ndef mba_xor(a, b): return (a ^ b) & 0xff\n\ndef mba_transform(i):\n \"\"\"Position-dependent transform from signal handler.\"\"\"\n val = (i * 7 + 0x3f) & 0xff\n rotated = ((i \u003c\u003c 3) | (i >> 5)) & 0xff\n return mba_xor(val, rotated)\n\n# S-box (SHA-256 initial hash values repurposed)\nSBOX = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,\n 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]\n\ndef sbox_lookup(i):\n idx = i & 7\n shift = ((i >> 3) & 3) * 8\n return (SBOX[idx] >> shift) & 0xff\n\n# Two interleaved rodata arrays (even indices → array1, odd → array2)\nrodata1 = bytes.fromhex(\"39407691b717c97879013adf3a2adea11c2b04e0\")\nrodata2 = bytes.fromhex(\"bb19b025e37eaa786c4116e7aeea00c9c623940d\")\n\nflag = []\nfor i in range(40): # flag length\n t = mba_transform(i)\n s = sbox_lookup(i)\n mem = rodata1[i // 2] if i % 2 == 0 else rodata2[i // 2]\n flag.append(chr(t ^ s ^ mem))\n\nprint(''.join(flag))\n```\n\n**Key insight:** The real flag logic is in the signal handler (SIGSEGV/SIGILL), not the main thread. Thread 1's AES-like code and `ud2` crash are intentional misdirection. The `rdtsc` timing check detects debuggers and corrupts output. Bypass by extracting the MBA logic from assembly and reimplementing in Python — never run the binary under a debugger.\n\n**Detection indicators:**\n- Multiple `pthread_create` calls with different handler functions\n- `signal(SIGSEGV, handler)` or `sigaction` setup\n- `ud2` instruction (deliberate illegal instruction)\n- `rdtsc` instructions for timing checks\n- SHA-256 constants (0x6a09e667...) used as lookup tables, not for hashing\n\n---\n\n## INT3 Patch + Coredump Brute-Force Oracle (Pwn2Win 2016)\n\nInstead of reversing complex transformation logic, patch a byte to `0xCC` (INT3) after the transform, enable core dumps, brute-force each character by running the binary and extracting the transformed result from the coredump via `strings`.\n\n```bash\n# Patch byte at transform output point to 0xCC\nprintf '\\xcc' | dd of=binary bs=1 seek=$((0x400ebb)) conv=notrunc\nulimit -c unlimited\n# Brute-force each position:\nfor c in $(seq 32 126); do\n echo -ne \"$(printf '\\\\x%02x' $c)$known_suffix\" | ./binary 2>/dev/null\n strings core | grep -q \"$expected\" && echo \"Found: $c\"\ndone\n```\n\n**Key insight:** Use INT3/SIGTRAP as a breakpoint oracle -- the coredump captures computed state at the crash point. Avoids full reverse engineering of the transformation.\n\n---\n\n## Signal Handler Chain + LD_PRELOAD Oracle (Nuit du Hack 2016)\n\nBinary uses Unix signals for flow control: `main()` sends SIGINT to itself 1024 times, each handler checks one password character, then calls `signal()` to install the next handler. Bypass: LD_PRELOAD a custom `signal()` that logs when it's called (indicating correct character), brute-force each position.\n\n```c\n// LD_PRELOAD library:\n#include \u003csignal.h>\nsighandler_t signal(int sig, sighandler_t handler) {\n write(2, \"CORRECT\\n\", 8); // signal() called = char was correct\n return SIG_DFL;\n}\n```\n\n**Key insight:** Signal-handler-chain anti-reversing can be defeated by hooking `signal()` via LD_PRELOAD. The call to `signal()` (to install the next handler) acts as a side-channel confirming the current character.\n\n---\n\n### printf Format String VM Decompilation to Z3 (SECCON 2017)\n\nA \"virtual machine\" implemented entirely via `%hhn` format strings. Format string `%hhn` writes the count of printed characters (mod 256) to a pointed-to byte. A sequence of `%Nc%hhn` instructions implements arbitrary byte-to-memory writes, effectively creating a bytecode VM.\n\n**Step 1: Identify instruction types.**\nCount unique format patterns to determine the instruction set:\n```bash\n# Normalize numbers and count unique patterns\nsed -e 's/[[:digit:]]\\+/1/g' program.fs | sort | uniq -c | sort -nr\n```\n\n**Step 2: Write a decompiler.**\nConvert format patterns to C-style pseudocode. Each `%N...%hhn` pair maps to a memory write: extract the write address (from the argument pointer) and value (from the character count).\n\n**Step 3: Recognize the algorithm.**\nThe pseudocode typically reveals a linear equation system over bytes. Map memory addresses to symbolic variables.\n\n**Step 4: Generate Z3 constraints and solve.**\n```python\nfrom z3 import *\n\nflag_len = 32 # adjust based on decompiled output\nflag = [BitVec(f'f{i}', 8) for i in range(flag_len)]\ns = Solver()\n\n# Constrain to printable ASCII\nfor f in flag:\n s.add(f >= 0x20, f \u003c= 0x7e)\n\n# Add constraints from decompiled format string operations\n# e.g., flag[3] + flag[7] == 0xAB (mod 256)\n# These come from the write sequences: each %hhn accumulates\n# character counts and writes the result to a target byte\ns.add((flag[0] + flag[1]) & 0xFF == 0x9A) # example constraint\ns.add((flag[2] ^ flag[3]) & 0xFF == 0x3F) # example constraint\n# ... (add all constraints from decompilation)\n\nif s.check() == sat:\n m = s.model()\n print(bytes([m[f].as_long() for f in flag]))\n```\n\n**Decompilation approach in detail:**\n1. Extract the write address and value from each `%N...%hhn` pair\n2. Map memory addresses to symbolic variables (flag bytes)\n3. Build an equation system from the write sequences\n4. Solve with Z3\n\n**Key insight:** Format string `%hhn` writes the count of printed characters (mod 256) to a pointed-to byte. A sequence of `%Nc%hhn` instructions implements arbitrary byte-to-memory writes, effectively creating a bytecode VM. Decompile by: (1) extract the write address and value from each `%N...%hhn` pair, (2) map memory addresses to symbolic variables, (3) build an equation system from the write sequences, (4) solve with Z3.\n\n**References:** SECCON 2017\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":29980,"content_sha256":"be64443fcbd3d83d4a4f30ee4947310014a9bb0a26aace1126fd9a29ceb6b9c3"},{"filename":"platforms-hardware.md","content":"# CTF Reverse - Hardware and Advanced Architecture Reversing\n\nHD44780 LCD GPIO reconstruction, RISC-V advanced extensions and debugging, ARM64/AArch64 reversing and exploitation.\n\n## Table of Contents\n- [HD44780 LCD Controller GPIO Reconstruction (32C3 2015)](#hd44780-lcd-controller-gpio-reconstruction-32c3-2015)\n- [RISC-V (Advanced)](#risc-v-advanced)\n - [Custom Extensions](#custom-extensions)\n - [Privileged Modes](#privileged-modes)\n - [RISC-V Debugging](#risc-v-debugging)\n- [ARM64/AArch64 Reversing and Exploitation](#arm64aarch64-reversing-and-exploitation)\n- [MIPS64 Cavium OCTEON Coprocessor 2 Crypto (SEC-T CTF 2017)](#mips64-cavium-octeon-coprocessor-2-crypto-sec-t-ctf-2017)\n- [EFM32 ARM Microcontroller MMIO AES (SEC-T CTF 2017)](#efm32-arm-microcontroller-mmio-aes-sec-t-ctf-2017)\n- [MBR/Bootloader Reversing with QEMU + GDB (Square CTF 2017)](#mbrbootloader-reversing-with-qemu--gdb-square-ctf-2017)\n\n---\n\n## HD44780 LCD Controller GPIO Reconstruction (32C3 2015)\n\nRecover text displayed on an HD44780 LCD from raw Raspberry Pi GPIO recordings:\n\n1. **Identify signal lines:** Map GPIO pins to HD44780 signals (RS, CLK, D4-D7 for 4-bit mode)\n2. **Clock edge detection:** Sample data lines on falling clock edges (1->0 transition)\n3. **Nibble assembly:** Combine two 4-bit samples into one 8-bit command/data byte\n4. **DRAM address mapping:** HD44780 uses non-contiguous addressing for multi-line displays:\n - Line 0: 0x00-0x27\n - Line 1: 0x40-0x67\n - Line 2: 0x14-0x3B\n - Line 3: 0x54-0x7B\n\n```python\ndisplay = [' '] * 80 # 4 lines x 20 chars\ncursor = 0\n\nfor timestamp, gpio_state in sorted(gpio_log):\n if falling_edge(gpio_state, CLK_PIN):\n nibble = extract_data_bits(gpio_state)\n byte = assemble_nibble(nibble) # Two nibbles per byte\n if rs_high(gpio_state): # RS=1: data write\n display[dram_to_position(cursor)] = chr(byte)\n cursor += 1\n else: # RS=0: command (set cursor, clear, etc.)\n cursor = parse_command(byte)\n```\n\n**Key insight:** GPIO pin-to-signal mapping is rarely documented; identify CLK by finding the pin with most transitions, RS by correlation with data patterns (alternating command/data phases).\n\n---\n\n## RISC-V (Advanced)\n\nBeyond basic disassembly (see [tools.md](tools.md#risc-v-binary-analysis-ehax-2026)):\n\n### Custom Extensions\n\n```text\nBitmanip extensions (Zbb, Zbc, Zbs):\n clz, ctz, cpop -> count leading/trailing zeros, popcount\n orc.b, rev8 -> byte-level bit manipulation\n andn, orn, xnor -> negated logic operations\n clmul, clmulh, clmulr -> carry-less multiplication (crypto)\n bset, bclr, binv, bext -> single-bit operations\n\nCrypto extensions (Zk*):\n aes32esi, aes32dsmi -> AES round operations\n sha256sig0, sha512sum0 -> SHA hash acceleration\n sm3p0, sm4ed -> Chinese crypto standards\n```\n\n### Privileged Modes\n\n```text\nMachine mode (M): Highest privilege, firmware/bootloader\nSupervisor mode (S): OS kernel\nUser mode (U): Applications\n\nCSR registers to watch:\n mstatus/sstatus -> privilege level, interrupt enable\n mtvec/stvec -> trap handler address\n mepc/sepc -> exception return address\n mcause/scause -> trap cause\n satp -> page table root (virtual memory)\n```\n\n### RISC-V Debugging\n\n```bash\n# OpenOCD + GDB for hardware debugging\nopenocd -f interface/jlink.cfg -f target/riscv.cfg\n\n# GDB for RISC-V\nriscv64-unknown-elf-gdb binary\n(gdb) target remote :3333\n\n# QEMU with GDB server\nqemu-riscv64 -g 1234 -L /usr/riscv64-linux-gnu/ ./binary\nriscv64-linux-gnu-gdb -ex 'target remote :1234' ./binary\n```\n\n---\n\n## ARM64/AArch64 Reversing and Exploitation\n\nAArch64 (ARM 64-bit) appears in mobile apps, cloud servers (AWS Graviton), Apple Silicon, and CTF challenges. Key differences from x86-64 affect both reversing and exploitation.\n\n**Setup and emulation:**\n\n```bash\n# Install cross-toolchain and emulator\napt install gcc-aarch64-linux-gnu gdb-multiarch qemu-user-static\n\n# Run AArch64 binary on x86 host\nqemu-aarch64-static -L /usr/aarch64-linux-gnu/ ./arm64_binary\n\n# Debug with GDB\nqemu-aarch64-static -g 12345 -L /usr/aarch64-linux-gnu/ ./arm64_binary &\ngdb-multiarch -ex 'set arch aarch64' -ex 'target remote :1234' ./arm64_binary\n\n# With library preloading (for challenges that ship libc)\nqemu-aarch64-static -g 12345 -E LD_PRELOAD=./libc.so.6 -L ./lib ./arm64_binary\n```\n\n**AArch64 calling convention (key differences from x86-64):**\n\n```text\nRegisters:\n x0-x7 -- function arguments AND return values (x0 = first arg / return)\n x8 -- indirect result location (struct returns)\n x9-x15 -- caller-saved temporaries\n x19-x28 -- callee-saved (preserved across calls)\n x29 (fp) -- frame pointer\n x30 (lr) -- link register (return address, NOT on stack by default)\n sp -- stack pointer (must be 16-byte aligned)\n xzr -- zero register (reads as 0, writes discarded)\n\nKey exploitation differences:\n - Return address in LR (x30), not on stack -- pushed only if function calls others\n - No RIP-relative addressing like x86 -- uses ADRP+ADD pairs for PC-relative loads\n - Fixed 4-byte instruction width -- no variable-length gadget tricks\n - NOP = 0xD503201F (not 0x90)\n - BLR x8 / BR x30 -- indirect calls/jumps use register operands\n```\n\n**Common AArch64 patterns in Ghidra/IDA:**\n\n```text\n# PC-relative address loading (equivalent to x86 LEA):\nADRP x0, #0x411000 ; Load page address (4KB aligned)\nADD x0, x0, #0x8 ; Add page offset -> x0 = 0x411008\n\n# Function prologue:\nSTP x29, x30, [sp, #-0x30]! ; Push fp + lr, decrement sp\nMOV x29, sp ; Set frame pointer\n\n# Function epilogue:\nLDP x29, x30, [sp], #0x30 ; Pop fp + lr, increment sp\nRET ; Branch to x30 (lr)\n\n# Switch/jump table:\nADR x1, jump_table\nLDRB w2, [x1, x0] ; Load offset byte\nADD x1, x1, w2, SXTB ; Sign-extend and add\nBR x1 ; Indirect branch\n```\n\n**ROP on AArch64:**\n\n```python\nfrom pwn import *\n\n# AArch64 gadgets differ from x86:\n# - \"pop {x0}; ret\" equivalent: LDP x0, x1, [sp], #0x10; RET\n# - Prologue gadgets: LDP x29, x30, [sp, #0x20]; ... RET\n# - system() call: x0 = pointer to \"/bin/sh\", BLR to system\n\ncontext.arch = 'aarch64'\nelf = ELF('./arm64_binary')\n\n# Common gadget pattern in AArch64 libc:\n# LDP X19, X20, [SP,#var_s10]\n# LDP X29, X30, [SP+var_s0],#0x20\n# RET\n# Controls x19, x20, x29, x30 and advances sp by 0x20\n```\n\n**Key insight:** AArch64's fixed instruction width and register-based return address (`lr`/`x30`) make ROP gadgets more constrained than x86. Look for `LDP` (load pair) gadgets that pop multiple registers from the stack. The `STP`/`LDP` instruction pairs that save/restore callee-saved registers in function prologues/epilogues are the primary gadget source.\n\n**When to recognize:** `file` shows \"ELF 64-bit LSB ... ARM aarch64\". Ghidra auto-detects but may need manual processor selection for raw binaries. Use `qemu-aarch64-static` for emulation on x86 hosts.\n\n**Tools:** radare2 (`r2 -AA -a arm -b 64`), Ghidra (auto-detect), `aarch64-linux-gnu-objdump -d`, Unicorn Engine (`UC_ARCH_ARM64`)\n\n**References:** Google CTF 2016 \"Forced Puns\", Insomni'hack 2018 \"onecall\"\n\n---\n\n## MIPS64 Cavium OCTEON Coprocessor 2 Crypto (SEC-T CTF 2017)\n\nCavium OCTEON network processors implement hardware AES and SHA256 via MIPS Coprocessor 2 (CP2) using `dmtc2` (move to CP2) and `dmfc2` (move from CP2) instructions. These look like ordinary register moves to a disassembler but drive the hardware crypto engine.\n\n**Key CP2 register layout (OCTEON):**\n```text\nAES key registers:\n 0x0104 – AES key quadword 0\n 0x0105 – AES key quadword 1\n 0x0106 – AES key quadword 2\n 0x0107 – AES key quadword 3\n\nSHA256 hash registers:\n 0x400E–0x4012 – SHA256 intermediate hash words\n 0x404F – SHA256 control/result\n\ndmtc2 rN, 0x0104 ; load 64 bits of AES key into CP2 register 0x104\ndmtc2 rN, 0x0105 ; ...next quadword\n```\n\n**Approach:**\n1. Disassemble in IDA/Ghidra — `dmtc2`/`dmfc2` with selector in 0x100-0x40FF range indicates OCTEON CP2\n2. Cross-reference the Cavium OCTEON Hardware Reference Manual for register semantics\n3. Trace the key loading sequence to recover the AES or HMAC key material\n\n**Key insight:** Hardware crypto accelerators on MIPS appear as CP2 register writes (`dmtc2`/`dmfc2`). Identify the base register address and cross-reference vendor documentation.\n\n**References:** SEC-T CTF 2017\n\n---\n\n## EFM32 ARM Microcontroller MMIO AES (SEC-T CTF 2017)\n\nSilicon Labs EFM32 Cortex-M binary — a flat binary loaded at 0x1000 in Thumb mode.\n\n**IDA setup:**\n```text\nProcessor: ARM Little-endian (ARMv7-M)\nLoad address: 0x1000\nSet T register = 1 (force Thumb mode decoding)\n```\n\n**AES accelerator MMIO layout (EFM32 AES peripheral at 0x400E0000):**\n```text\n0x400E0000 + 0x000 CTRL – enable, decrypt mode\n0x400E0000 + 0x004 CMD – start/stop\n0x400E0000 + 0x010 KEYLA – key low word 0\n0x400E0000 + 0x014 KEYLB – key low word 1\n0x400E0000 + 0x018 KEYLC – key low word 2\n0x400E0000 + 0x01C KEYLD – key low word 3\n```\n\nThe binary loads two separate values, XORs them together, then writes the result as the AES key. Decrypt the embedded ciphertext block with the composed key in ECB mode.\n\n```python\nfrom Crypto.Cipher import AES\n\nkey_part_a = bytes.fromhex(\"...\") # extracted from IDA .data section\nkey_part_b = bytes.fromhex(\"...\") # second value\nkey = bytes(a ^ b for a, b in zip(key_part_a, key_part_b))\n\ncipher = AES.new(key, AES.MODE_ECB)\nplaintext = cipher.decrypt(ciphertext)\n```\n\n**Key insight:** Hardware AES accelerators on microcontrollers appear as MMIO register writes at a specific base address — cross-reference the vendor reference manual (EFM32 Reference Manual for Silicon Labs peripherals).\n\n**References:** SEC-T CTF 2017\n\n---\n\n## MBR/Bootloader Reversing with QEMU + GDB (Square CTF 2017)\n\nBoot a floppy/disk image in QEMU with the GDB stub enabled, then attach GDB for full source-level debugging of 16-bit real mode or 32-bit protected mode bootloader code.\n\n```bash\n# Boot with GDB stub on port 1234; -S pauses execution at start\nqemu-system-x86_64 -fda disk.img -s -S\n\n# In another terminal, attach GDB\ngdb -ex \"set architecture i8086\" \\\n -ex \"target remote :1234\" \\\n -ex \"break *0x7c00\" \\\n -ex \"continue\"\n\n# Common MBR entry point is 0x7c00 (BIOS loads MBR here)\n# Step through bootloader, inspect registers and memory:\n(gdb) x/20i $pc\n(gdb) info registers\n(gdb) x/16xb 0x7c00\n```\n\nTo bypass a password check: identify the conditional jump after the comparison and NOP it out in the image file, or patch the comparison to always succeed.\n\n```bash\n# Find the comparison offset in the image and patch it\npython3 -c \"\ndata = open('disk.img', 'rb').read()\n# Replace JNZ (0x75) with JMP-short-always or NOP\ndata = data[:offset] + b'\\x90\\x90' + data[offset+2:]\nopen('disk_patched.img', 'wb').write(data)\n\"\n```\n\n**Key insight:** QEMU's `-s` flag exposes a GDB stub on port 1234 for full debugging of MBR/bootloader code — workflow identical to userland debugging.\n\n**References:** Square CTF 2017\n\n---\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":11148,"content_sha256":"123b5cc066bc09d7cd25312347aec79acd4476d8cec154ae951432f97912d2dc"},{"filename":"platforms.md","content":"# CTF Reverse - Platform-Specific Reversing\n\nmacOS/iOS, embedded/IoT firmware, kernel driver, and automotive reverse engineering.\n\n## Table of Contents\n- [macOS / iOS Reversing](#macos--ios-reversing)\n - [Mach-O Binary Format](#mach-o-binary-format)\n - [Code Signing & Entitlements](#code-signing--entitlements)\n - [Objective-C Runtime RE](#objective-c-runtime-re)\n - [Swift Binary Reversing](#swift-binary-reversing)\n - [iOS App Analysis](#ios-app-analysis)\n - [dyld / Dynamic Linking](#dyld--dynamic-linking)\n- [Embedded / IoT Firmware RE](#embedded--iot-firmware-re)\n - [Firmware Extraction](#firmware-extraction)\n - [Firmware Unpacking](#firmware-unpacking)\n - [Architecture-Specific Notes](#architecture-specific-notes)\n - [RTOS Analysis](#rtos-analysis)\n- [Kernel Driver Reversing](#kernel-driver-reversing)\n - [Linux Kernel Modules](#linux-kernel-modules)\n - [eBPF Programs](#ebpf-programs)\n - [Windows Kernel Drivers](#windows-kernel-drivers)\n- [Automotive / CAN Bus RE](#automotive--can-bus-re)\n\n---\n\n## macOS / iOS Reversing\n\n### Mach-O Binary Format\n\n```bash\n# File identification\nfile binary # \"Mach-O 64-bit executable arm64\" or \"x86_64\"\notool -l binary # Load commands (segments, dylibs, entry point)\notool -L binary # Linked dynamic libraries\n\n# Universal (fat) binaries — multiple architectures in one file\nlipo -info universal_binary # List architectures\nlipo universal_binary -thin arm64 -output binary_arm64 # Extract one arch\n\n# Segments and sections\notool -l binary | grep -A5 \"segment\\|section\"\n# Key segments: __TEXT (code), __DATA (globals), __LINKEDIT (symbols)\n# Key sections: __text (instructions), __cstring (C strings), __objc_methname\n```\n\n**Key Mach-O concepts:**\n- Load commands drive the dynamic linker (`dyld`)\n- `LC_MAIN` → entry point (replaces `LC_UNIXTHREAD`)\n- `LC_LOAD_DYLIB` → shared library dependencies\n- `LC_CODE_SIGNATURE` → code signing blob\n- `__DATA_CONST.__got` → Global Offset Table\n- `__DATA.__la_symbol_ptr` → Lazy symbol pointers (like PLT)\n\n### Code Signing & Entitlements\n\n```bash\n# Check code signature\ncodesign -dvvv binary\ncodesign --verify binary\n\n# Extract entitlements (capability permissions)\ncodesign -d --entitlements - binary\n# Key entitlements: com.apple.security.app-sandbox, com.apple.security.network.client\n\n# Remove code signature (for patching)\ncodesign --remove-signature binary\n\n# Re-sign (ad-hoc, for testing)\ncodesign -f -s - binary\n```\n\n**CTF relevance:** Patched binaries need re-signing to run on macOS. Ad-hoc signing (`-s -`) works for local testing.\n\n### Objective-C Runtime RE\n\n```bash\n# Dump Objective-C class info\nclass-dump binary > classes.h\n# Shows: @interface, @protocol, method signatures with types\n\n# Runtime inspection with lldb\n(lldb) expression -l objc -O -- [NSClassFromString(@\"ClassName\") new]\n(lldb) expression -l objc -O -- [[ClassName alloc] init]\n\n# Method swizzling detection (anti-tamper)\n# Look for: method_exchangeImplementations, class_replaceMethod\n```\n\n**Objective-C in disassembly:**\n```text\n# objc_msgSend(receiver, selector, ...) is THE dispatch mechanism\n# RDI = self (receiver), RSI = selector (char* method name)\n\n# In Ghidra/IDA, look for:\nobjc_msgSend(obj, \"checkPassword:\", input)\n# Selector strings are in __objc_methname section\n# Cross-reference selectors to find implementations\n```\n\n**class-dump alternatives:**\n- `dsdump` — faster, supports Swift + Objective-C\n- `otool -oV binary` — dump Objective-C segments\n- Ghidra: Enable \"Objective-C\" analyzer in Analysis Options\n\n### Swift Binary Reversing\n\n```bash\n# Detect Swift\nstrings binary | grep \"swift\"\notool -l binary | grep \"swift\" # __swift5_* sections\n\n# Swift demangling\nswift demangle 's14MyApp0A8ClassC10checkInput6resultSbSS_tF'\n# → MyApp.MyAppClass.checkInput(result: String) -> Bool\n\n# xcrun swift-demangle \u003c mangled_names.txt\n```\n\n**Swift in disassembly:**\n```text\n# Swift uses value witness tables (VWT) for type operations\n# Protocol witness tables (PWT) for dynamic dispatch (like vtables)\n\n# Key runtime functions to watch:\nswift_allocObject → heap allocation\nswift_release → reference count decrement\nswift_bridgeObjectRetain → bridged (ObjC ↔ Swift) retain\nswift_once → lazy initialization (like dispatch_once)\n\n# String layout:\n# Small strings (≤15 bytes): inline in 16-byte buffer, tagged pointer\n# Large strings: heap-allocated, pointer + length + flags\n\n# Array\u003cT>: pointer to ContiguousArrayStorage (header + elements)\n# Dictionary\u003cK,V>: hash table with open addressing\n```\n\n**Ghidra for Swift:** Enable \"Swift\" language module. Swift metadata sections (`__swift5_types`, `__swift5_proto`) contain type descriptors that Ghidra can parse.\n\n### iOS App Analysis\n\n```bash\n# Extract IPA (iOS app package)\nunzip app.ipa -d extracted/\nls extracted/Payload/*.app/\n\n# Check if encrypted (App Store encryption / FairPlay DRM)\notool -l extracted/Payload/*.app/binary | grep -A4 \"LC_ENCRYPTION_INFO\"\n# cryptid = 1 means encrypted, 0 means decrypted\n\n# Decrypt with frida-ios-dump (requires jailbroken device)\n# Or use Clutch / bfdecrypt on device\nfrida-ios-dump -H jailbroken_ip -p 22 \"App Name\"\n\n# Analyze decrypted binary\nclass-dump decrypted_binary > headers.h\n```\n\n**Jailbreak detection and bypass:**\n```javascript\n// Common jailbreak checks:\n// 1. Check for Cydia/Sileo\n// 2. Check /private/var/lib/apt\n// 3. fork() succeeds (sandboxed apps can't fork)\n// 4. Open /etc/apt, /bin/sh with write\n// 5. Check for substrate/substitute libraries\n\n// Frida bypass:\nvar paths = [\"/Applications/Cydia.app\", \"/bin/sh\", \"/etc/apt\",\n \"/private/var/lib/apt\", \"/usr/bin/ssh\"];\nInterceptor.attach(Module.findExportByName(null, \"access\"), {\n onEnter(args) {\n this.path = Memory.readUtf8String(args[0]);\n },\n onLeave(retval) {\n if (paths.some(p => this.path && this.path.includes(p))) {\n retval.replace(-1); // File not found\n }\n }\n});\n```\n\n### dyld / Dynamic Linking\n\n```bash\n# DYLD environment variables (for analysis, blocked in hardened runtime)\nDYLD_PRINT_LIBRARIES=1 ./binary # Print loaded dylibs\nDYLD_INSERT_LIBRARIES=hook.dylib ./binary # Inject dylib (like LD_PRELOAD)\n# Note: SIP (System Integrity Protection) blocks this for system binaries\n\n# Inspect dyld shared cache (contains all system frameworks)\ndyld_shared_cache_util -list /System/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e\n```\n\n---\n\n## Embedded / IoT Firmware RE\n\n### Firmware Extraction\n\n```bash\n# binwalk — firmware analysis and extraction\nbinwalk firmware.bin # Identify embedded filesystems, compressed data\nbinwalk -e firmware.bin # Extract all identified components\nbinwalk -Me firmware.bin # Recursive extraction (matryoshka)\nbinwalk --dd='.*' firmware.bin # Extract everything raw\n\n# Manual extraction by signature\nstrings firmware.bin | head -50 # Look for version strings, filesystem markers\nhexdump -C firmware.bin | grep \"hsqs\" # SquashFS magic\nhexdump -C firmware.bin | grep \"UBI#\" # UBI magic\n```\n\n**Hardware extraction methods (physical access):**\n```text\nUART: Serial console — often gives root shell or bootloader access\n Tools: USB-UART adapter, baudrate detection (usually 115200)\n Identify: 4 pins (GND, TX, RX, VCC), use multimeter\n\nJTAG: Direct CPU debug — read/write flash, halt CPU, set breakpoints\n Tools: OpenOCD, J-Link, Bus Pirate\n Identify: 10/14/20-pin header, use JTAGulator for auto-detection\n\nSPI Flash: Direct chip read — dump entire firmware\n Tools: flashrom, CH341A programmer\n Identify: 8-pin SOIC chip (Winbond, Macronix, etc.)\n\neMMC: Embedded MMC — common in routers, phones\n Tools: eMMC reader, direct solder to test pads\n```\n\n### Firmware Unpacking\n\n```bash\n# SquashFS (most common in routers)\nunsquashfs -d output/ squashfs-root.sqfs\n# If custom compression: try different compressors (-comp xz|lzma|lzo|gzip)\n\n# JFFS2\njefferson -d output/ jffs2.img\n\n# UBI/UBIFS\nubireader_extract_images firmware.ubi\nubireader_extract_files ubifs.img\n\n# CPIO (initramfs)\ncpio -idv \u003c initramfs.cpio\n\n# Device tree blob\ndtc -I dtb -O dts -o output.dts device_tree.dtb\n\n# Kernel extraction\nbinwalk -e firmware.bin\n# Look for: zImage, uImage, vmlinux\n# Extract vmlinux from compressed: vmlinux-to-elf tool\n```\n\n### Architecture-Specific Notes\n\n**ARM (most common in IoT):**\n```bash\n# Cross-toolchain\napt install gcc-arm-linux-gnueabihf gdb-multiarch\n\n# QEMU emulation\nqemu-arm -L /usr/arm-linux-gnueabihf/ ./arm_binary\nqemu-arm -g 1234 ./arm_binary # Start GDB server on port 1234\ngdb-multiarch -ex 'target remote :1234' ./arm_binary\n\n# ARM vs Thumb: ARM instructions are 4 bytes, Thumb are 2 bytes\n# LSB of function pointer indicates mode: 0=ARM, 1=Thumb\n# Ghidra: Right-click → Processor Options → ARM/Thumb mode\n```\n\n**ARM64/AArch64:** See [platforms-hardware.md](platforms-hardware.md#arm64aarch64-reversing-and-exploitation) for AArch64 calling convention, ROP gadgets, and qemu-aarch64-static emulation.\n\n**MIPS (routers, embedded):**\n```bash\n# Big-endian vs little-endian — check ELF header or file command\nfile binary # \"MIPS, MIPS32 rel2 (MIPS-II), big-endian\" or \"little-endian\"\n\n# Emulation\nqemu-mips -L /usr/mips-linux-gnu/ ./mips_binary # Big-endian\nqemu-mipsel -L /usr/mipsel-linux-gnu/ ./mipsel_binary # Little-endian\n\n# Key MIPS patterns:\n# Branch delay slots — instruction AFTER branch always executes\n# $gp (global pointer) — used for PIC, points to .got\n# lui + addiu pair — loads 32-bit constant (upper 16 + lower 16)\n```\n\n**RISC-V:** See main [tools.md](tools.md#risc-v-binary-analysis-ehax-2026) for Capstone disassembly and [platforms-hardware.md](platforms-hardware.md#risc-v-advanced) for advanced extensions and debugging.\n\n### RTOS Analysis\n\n```text\nFreeRTOS:\n - Tasks (like threads): xTaskCreate → function pointer + stack\n - Strings: \"IDLE\", \"Tmr Svc\", task names\n - xQueueSend/xQueueReceive → inter-task communication\n - Look for vTaskDelay() for timing, xSemaphoreTake() for sync\n\nZephyr:\n - k_thread_create → kernel thread creation\n - k_msgq_put/k_msgq_get → message queues\n - CONFIG_* symbols reveal kernel configuration\n\nBare metal (no OS):\n - Interrupt vector table at address 0x0 or 0x08000000 (STM32)\n - main loop pattern: while(1) { read_input(); process(); output(); }\n - Peripheral registers at memory-mapped addresses (check datasheet)\n```\n\n---\n\n## Kernel Driver Reversing\n\n### Linux Kernel Modules\n\n```bash\n# Identify kernel module\nfile module.ko # \"ELF 64-bit LSB relocatable\"\nmodinfo module.ko # Module info (description, author, license)\n\n# List module symbols\nnm module.ko | grep -v \" U \" # Exported symbols\n\n# Strings for quick recon\nstrings module.ko | grep -i \"flag\\|secret\\|ioctl\\|device\"\n\n# Find ioctl handler\n# Key pattern: .unlocked_ioctl = my_ioctl_handler in file_operations struct\n# In Ghidra: find struct with function pointers, identify by position\n\n# Load in Ghidra\n# Language: x86:LE:64:default\n# Base address: doesn't matter for .ko (relocatable)\n# Look for init_module / cleanup_module entry points\n```\n\n**Common kernel module CTF patterns:**\n```c\n// Device creation (creates /dev/challenge)\nalloc_chrdev_region(&dev, 0, 1, \"challenge\");\ncdev_init(&cdev, &fops);\n\n// ioctl handler (main interface)\nlong my_ioctl(struct file *f, unsigned int cmd, unsigned long arg) {\n switch (cmd) {\n case CUSTOM_CMD_1: /* operation */ break;\n case CUSTOM_CMD_2: /* operation */ break;\n }\n}\n\n// copy_from_user / copy_to_user — data transfer with userspace\ncopy_from_user(kernel_buf, (void __user *)arg, size);\ncopy_to_user((void __user *)arg, kernel_buf, size);\n```\n\n**Debugging kernel modules:**\n```bash\n# QEMU + GDB for kernel debugging\nqemu-system-x86_64 -kernel bzImage -initrd initrd.cpio -s -S \\\n -append \"console=ttyS0 nokaslr\" -nographic\n\n# In another terminal\ngdb vmlinux\n(gdb) target remote :1234\n(gdb) lx-symbols # Load module symbols (requires scripts)\n(gdb) add-symbol-file module.ko 0x\u003cloaded_address>\n```\n\n### eBPF Programs\n\n```bash\n# Dump eBPF programs from running system\nbpftool prog list\nbpftool prog dump xlated id \u003cN> # Disassemble\nbpftool prog dump jited id \u003cN> # JIT'd machine code\n\n# eBPF bytecode analysis\n# eBPF has 11 registers (r0-r10), 64-bit\n# r0 = return value, r1-r5 = arguments, r10 = frame pointer\n# Instructions are 8 bytes each\n\n# Disassemble .o file containing eBPF\nllvm-objdump -d ebpf_prog.o\n\n# Key eBPF patterns:\n# bpf_map_lookup_elem → read from map\n# bpf_map_update_elem → write to map\n# bpf_probe_read → read kernel memory\n# bpf_trace_printk → debug output\n```\n\n### Windows Kernel Drivers\n\n```bash\n# .sys files are PE format — load in IDA/Ghidra as normal PE\n# Entry point: DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING)\n\n# Key patterns:\n# IoCreateDevice → creates device object\n# IRP_MJ_DEVICE_CONTROL → ioctl handler\n# MmMapIoSpace → memory-mapped I/O\n# ObReferenceObjectByHandle → get kernel object from handle\n# ZwCreateFile/ZwReadFile → kernel-mode file operations\n```\n\n---\n\n## Automotive / CAN Bus RE\n\n```bash\n# CAN bus interface setup\nsudo ip link set can0 type can bitrate 500000\nsudo ip link set up can0\n\n# Capture CAN traffic\ncandump can0 # Live capture\ncandump -l can0 # Log to file\ncansniffer can0 # Filter/highlight changes\n\n# Replay CAN messages\ncanplayer -I logfile.log can0\ncansend can0 7DF#0201000000000000 # Send single frame (OBD-II request)\n\n# UDS (Unified Diagnostic Services) — common in automotive CTF\n# Service 0x27: Security Access (seed-key authentication)\n# Service 0x2E: Write Data By Identifier\n# Service 0x31: Routine Control\n\n# Decode CAN frames\n# ID: 11-bit or 29-bit identifier\n# DLC: Data Length Code (0-8 bytes)\n# Data: up to 8 bytes payload\n```\n\n**CTF automotive patterns:**\n- Seed-key bypass: Reverse the key derivation algorithm from ECU firmware\n- CAN message replay: Capture legitimate command, replay to unlock feature\n- Firmware extraction from ECU via UDS/KWP2000\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":14279,"content_sha256":"a0d87958d7430f7bb7095703340a359f0f8b102760ea0a0381fe48534acdaa48"},{"filename":"references/ai-assisted-re.md","content":"# AI 辅助逆向工程\n\n> LLM 驱动反编译 / 多 Agent 验证 / 神经语义恢复\n> 2025-2026 最大范式转变\n\n## 核心工具与模型\n\n### LLM4Decompile\n- 首个将 LLM 用于二进制→源码反编译的开源框架\n- 支持 x86/ARM/MIPS 多架构\n- 输入: 汇编代码 → 输出: C 源码\n- 训练数据: 百万级 源码-汇编 对\n\n### Decaf (2026)\n- **编译器反馈验证**: 将 LLM 生成的源码→编译→对比原始二进制\n- 效果: 反编译率 26% → 83.9% (ExeBench Real -O2)\n- 关键洞察: 反馈循环比更大模型更有效\n\n### Constraint-Guided Multi-Agent (2026)\n- 三级验证管道:\n 1. 语法正确性 (解析)\n 2. 可编译性 (GCC)\n 3. 行为等价性 (LLM 生成测试用例)\n- 84-97% 可重执行率,每次仅 $0.03-0.05\n\n### REMEND (2026)\n- 专项: 从二进制提取数学方程\n- 89.8-92.4% 准确率 (跨 3 ISA × 3 优化级别 × 2 语言)\n- 速度: 0.132s/函数, 仅 12M 参数\n\n### Glaurung\n- 开源 Ghidra 替代,Rust 内核 + Python 绑定\n- **AI 原生架构**: LLM Agent 嵌入每个分析层\n- 证据制品: plain/rich/JSON/JSONL 多格式输出供 LLM 消费\n- 支持: ELF/PE/Mach-O、x86/ARM/RISC-V、IOC 检测、熵分析\n\n## 工作流:AI 增强二进制分析\n\n### 1. LLM 辅助快速侦察\n\n```text\n□ strings 提取 → LLM 语义分类(URL/密钥/路径/协议)\n□ 导入表分析 → LLM 推断功能(加密=OpenSSL? 网络=libcurl?)\n□ 反汇编片段 → LLM 识别模式(密码算法、反调试、虚拟机检测)\n□ 错误消息 → LLM 推断上下文(\"Invalid license\" → 授权逻辑位置)\n```\n\n### 2. 神经反编译\n\n```bash\n# LLM4Decompile\npython llm4decompile.py --binary target.so --arch arm64 --output target.c\n\n# 验证结果(重编译 + 对比)\ngcc -O2 -o target_recompiled target.c -fPIC -shared\n# → 验证输出行为等价性\n```\n\n### 3. Multi-Agent 验证\n\n```text\nAgent 1 (语法): 检查生成的 C 代码是否可以 parse\n ↓ 失败 → 反馈错误信息给 LLM 重试\nAgent 2 (编译): GCC 编译 → 检查 warnings/errors\n ↓ 失败 → 反馈编译错误给 LLM\nAgent 3 (行为): LLM 生成输入 → 运行原始和重编译版本 → 对比输出\n ↓ 不一致 → 反馈差异给 LLM → 迭代修正\n```\n\n### 4. LLM 辅助静态分析\n\n```text\n□ 函数重命名: 输入反编译伪代码 → LLM 建议语义化名称\n□ 类型恢复: 分析上下文 → LLM 推断结构体/类定义\n□ 算法识别: 汇编片段 → LLM 识别密码算法(AES/TEA/RC4/自定义)\n□ 协议逆向: 网络包序列 → LLM 推断协议格式\n□ 注释生成: 反编译代码 → LLM 生成中文/英文注释\n```\n\n### 5. macOS/iOS 私有框架逆向 (MOTIF)\n\n```text\n问题: macOS 私有框架无文档,类型信息缺失\n方案: LLM 分析使用模式 → 推断方法签名和参数类型\n效果: ObjC 签名恢复 15% → 86% (vs 静态分析)\n```\n\n## LLM Prompt 模板\n\n### 函数语义分析\n\n```\nYou are a reverse engineering expert. Analyze this decompiled function:\n\n[伪代码]\n\n1. What does this function do? (one sentence)\n2. Suggest a meaningful function name.\n3. What are the input parameters and their likely types?\n4. What is the return value?\n5. What external APIs/functions does it depend on?\n6. Any security-relevant operations (crypto, auth, network, file I/O)?\n```\n\n### 算法识别\n\n```\nAnalyze this assembly/disassembly for cryptographic operations:\n\n[汇编代码]\n\n1. Is this a known cryptographic algorithm? (AES/DES/RC4/TEA/ChaCha20/custom?)\n2. Identify the key schedule and round structure.\n3. What is the key size?\n4. Are there any hardcoded constants that identify the algorithm?\n```\n\n### 协议格式推断\n\n```\nGiven this network packet sequence, infer the protocol structure:\n\n[hex dump]\n\n1. Identify magic bytes and length fields.\n2. Propose a struct definition for the packet header.\n3. What field(s) appear to be checksums/CRCs?\n4. Is this a known protocol or custom?\n```\n\n## 工具选型\n\n| 场景 | 推荐工具 | 成本 |\n|------|---------|------|\n| 快速反编译 | LLM4Decompile | 免费 (本地 GPU) |\n| 高精度反编译 | Constraint-Guided Multi-Agent | ~$0.05/二进制 |\n| 数学函数提取 | REMEND | 免费 |\n| 全平台 RE | Glaurung (Rust) | 免费开源 |\n| LLM 交互 | Claude API / GPT-4 / DeepSeek | ~$0.01-0.10/次 |\n\n## 局限性\n\n- **复杂控制流**: 虚拟化/混淆代码仍困难(控制流平坦化、VMProtect)\n- **间接调用**: 虚函数表、函数指针难以恢复\n- **内联函数**: 编译器内联后边界模糊\n- **浮点运算**: 向量化指令的语义恢复有待提升\n- **上下文窗口**: 大函数 (>1000 行) 超出 LLM 上下文限制\n\nSource: Decaf (2026), REMEND (2026), Constraint-Guided Multi-Agent Decompilation (2026), LLM4Decompile, Glaurung\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4782,"content_sha256":"f8fabe6926483dd9eae681e85edf2584856b5950054f7318b53230ca4dbd3cb2"},{"filename":"references/nonpe-format-cookbook.md","content":"# 非 PE / 多格式 Agent 响应菜谱 U–AV + AW–DN\n\n> 与 PE 反调试菜谱 A–T(../anti-analysis.md)并列:按**文件类型**给出「触发 → 动作一行 → Evidence」。 \n> **不是**第二套主流程。Triage 识别类型后跳转到对应 skill + 本表。 \n> 默认 **授权隔离 lab / 已授权样本与设备**。格机、BYOVD、反射注入等写**检测与取证**,不写未授权破坏/利用教程。 \n> 绕过或还原失败也 MUST 记 Evidence;禁止静默当「无害」。\n>\n> §1–§8 / U–AV = 原始规则(Issue #65)。§9–§23 / AW–DN = 扩展规则(Issue #87,去重后 + 语义增强 + edge-case 补丁)。\n\n## 0. 路由速查\n\n| 类型线索 | 主 skill | 本表章节 |\n|----------|----------|----------|\n| .bat / .cmd / 批处理 | malware-analysis | §1, §19 |\n| .ps1 / PowerShell | malware-analysis | §2, §20 |\n| Office 宏 / VBA / XLM / .docm/.xlsm | malware-analysis | §3 (含 DD OLE 提取, DJ XLM 宏) |\n| .docx/.xlsx/.pptx OOXML 外链 / DDE / .rtf OLE | malware-analysis | §10 (含 DK RTF) |\n| Web/前端 JS 混淆、JSVMP | js-reverse | §4, §21 (含 DE/DF) |\n| .sys / 内核驱动 | reverse-engineering/kernel-driver-reverse.md + cre | §5 |\n| .dll 侧重点 | malware-analysis / re-agent-workflow | §6(与 A–T 去重) |\n| APK / Magisk / 隐藏图标 | apk-reverse | §7–§8, §23 |\n| .pdf / PDF 文档 | malware-analysis | §9 |\n| .wasm / WebAssembly | reverse-engineering | §11 |\n| .jar/.class / Java 字节码 | reverse-engineering | §12 |\n| .exe(AutoIt) / .au3 | malware-analysis | §13 |\n| .hta / HTML Application | malware-analysis | §14 |\n| .wsf/.jse/.vbe | malware-analysis | §15 |\n| .msi / Windows Installer | malware-analysis | §16 |\n| .reg / 注册表脚本 | malware-analysis | §17 |\n| .vbs / VBScript | malware-analysis | §18 |\n| Xposed/LSPosed 模块 | apk-reverse | §22 |\n| ELF / Linux 二进制 | reverse-engineering | → elf-analysis.md, anti-analysis.md |\n| Mach-O / macOS/iOS | reverse-engineering | → platforms.md |\n| Python 字节码 | reverse-engineering | → languages.md |\n\n## 1. BAT/CMD(U V W)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **U** | 大量 SET 单字符变量 + %a%%b% 拼接,或 ^ 续行拆命令 | 逐行展开 SET;还原后命令列表;可用 batch 脱混淆工具;**禁止**未还原就当「无动作」 | E-batch-deobf | P0 |\n| **V** | 文本打开乱码,HEX 头 FF FE(UTF-16 LE BOM) | 确认 BOM → 转 UTF-8 再解析;或 chcp 65001 + type | E-batch-encoding | P2 |\n| **W** | 大量 REM/::、冗余 GOTO/标签淹没真实逻辑 | 去注释;梳 GOTO 真路径;隔离执行抓 cmd 实际命令日志 | E-batch-deadcode | P1 |\n\n## 2. PowerShell(X Z)\n\n> 编号保留提出者习惯:**无补丁 Y**。\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **X** | 多层 FromBase64String / Gzip / Compress / 嵌套 -replace | **逐层**解码;每层结果单独记;工具可选(PowerDecode 等),无工具则手工/脚本 | E-ps-decode-layer-N | P0 |\n| **Z** | 字符串倒序、碎片 + 拼接后 Invoke-Expression/IEX | 还原完整串;对 IEX 下断或脚本块日志;明文命令入 Evidence | E-ps-string-restore | P1 |\n\n## 3. VBA 宏 / XLM(AA AB AC DD DJ)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **AA** | olevba/OLEDump 仅见 P-Code、源码流空(VBA Stomping) | P-Code 反编译工具;不全则 Word/Excel 宏调试观察;写清限制 | E-vba-pcode | P0 |\n| **AB** | 大量 Chr() 拼接或 Base64 串,疑 shellcode/嵌套脚本 | 立即窗口/脚本还原串;解码后判类型;动态盯 CreateObject/Shell | E-vba-str-decode | P1 |\n| **AC** | 无意义 If 1=2、或 InsertLines/DeleteLines 自修改 | 静跟真分支;动态 bp 自修改 API 并 dump 改后宏 | E-vba-selfmod | P2 |\n| **DD** | olevba/oledump 检出 VBA 宏项目(vbaProject.bin);扩展名 .docm/.xlsm/.pptm | oledump.py 检查 OLE 流结构;olevba 提取 VBA 源码检测可疑 API;检查 AutoOpen/Workbook_Open 等自动执行宏 | E-office-vba | P0 |\n| **DJ** | .xls/.xlsm 含 Excel 4.0/XLM 宏(隐藏在单元格公式中,非 VBA 流);olevba 检出 XLM 宏标记 | olevba --xlm 提取 XLM 宏公式;检查隐藏工作表中的 EXEC/CALL/REGISTER 函数;XLMMacroDeobfuscator 动态仿真还原 | E-office-xlm | P0 |\n\n## 4. JavaScript(AD AE AF)→ 主路径 js-reverse\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **AD** | 自定义字节码数组 + while/switch 解释器(JSVMP) | 找 VM 入口与 opcode 分发;动态日志轨迹;AST+动态双轨;见 js-reverse DeepDive | E-js-vmp | P0 |\n| **AE** | while(1){switch} + 大字符串数组下标 | AST/Babel 重构;数组下标还原字符串;wakaru 等可选;**勿**整份粘贴 PE ollvm-deobfuscation 长文 | E-js-deobf | P0 |\n| **AF** | debugger、劫持 console、performance.now 差、DevTools 检测 | 停用断点/固定时间源/无头浏览器;patch 检测点;授权页面 | E-js-anti-debug | P1 |\n\n## 5. SYS 内核驱动(AG AH AI)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **AG** | DriverEntry 很短,逻辑不在入口 | 扫 MajorFunction[] 非空槽;优先 IRP_MJ_DEVICE_CONTROL/CREATE;地址列表入证 | E-driver-irp-handlers | P0 |\n| **AH** | 存在 DeviceIoControl / IOCTL 分发 | 建控制码→处理函数表;标 METHOD_* 与缓冲方向;用户态通信面 | E-driver-ioctl | P0 |\n| **AI** | 样本加载/投放知名脆弱驱动或异常签名驱动(BYOVD 模式) | 对照 LOLDrivers 等**公开**列表;记驱动名/哈希/签名;分析**调用意图**;**不**展开 exploit 步骤 | E-driver-byovd | P1 |\n\n详见 kernel-driver-reverse.md 流程;本表只补 agent 动作锚点。\n\n## 6. DLL(AJ–AQ)— 与 A–T / #72 去重\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **AJ** | DLL 分析只看了导出/EP,忽略 TLS 或 DllMain | **TLS 回调 + DllMain 都必须看**;动态断点顺序仍遵循四级火箭(TLS→EP/DllMain→API→ExitProcess) | E-dll-tls-dllmain | P0 |\n| **AK** | 导出名前良后恶、错名、或导出与行为不符 | 导出表与实际调用交叉;异常导出列表 | E-exports-anomaly | P0 |\n| **AL** | 无导出或导出极少,仍被加载 | 从入口、字符串、xrefs、调用方定位;不要因「无导出」放弃 | E-dll-noexport | P0 |\n| **AM** | 静态 IAT 缺 DLL、运行时才用 | **See A–T 补丁 R**(Delay-Load / E-delay-import),此处不双写长文 | E-delay-import | P0 指针 |\n| **AN** | 需还原导出函数参数与调用约定 | 交叉引用 + 动态看寄存器/栈;标注 stdcall/fastcall 等 | E-dll-export-abi | P1 |\n| **AO** | 疑 DLL 劫持/侧加载 | 查应用目录同名 DLL、搜索路径、KnownDLLs;合法程序+异常 DLL 组合 | E-dll-sideload | P1 |\n| **AP** | 无文件映射/反射加载线索 | 内存特征、加载器行为、无路径模块;授权环境取证 | E-dll-reflective | P1 |\n| **AQ** | 仅因导出名「不像恶意」降风险 | **禁止**只凭导出名判安全;结合段权限、入口、字符串、动态行为 | E-dll-export-priority | P1 |\n\nDLL/SYS 硬门仍:E-imports + E-exports(见 re-agent-workflow)。\n\n## 7. Android 格机 / 持久化(AR AS AT)→ apk-reverse\n\n> **仅授权样本、镜像或测试设备。** 动作是检测、提取 IOC 与持久化路径,不是实施破坏。\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **AR** | Magisk 模块/脚本含删库、刷写、批量 rm 系统分区等**格机特征命令** | 特征命令表 + 模块路径;标高危破坏能力;不执行格机命令 | E-android-wiper-cmd | P0 |\n| **AS** | 循环 curl|sh / 远程拉脚本、非常规 C2 URL | 提 URL;分析下载体是否含格机命令;记临时路径 | E-android-wiper-backdoor | P0 |\n| **AT** | /data/adb/service.d、post-fs-data.d、可疑 /system/priv-app 等 | 列持久化脚本/APK;内容摘要入证 | E-android-persistence | P1 |\n\n## 8. Android 透明/隐藏图标(AU AV)→ apk-reverse\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **AU** | LAUNCHER 图标全透明/空 label、Theme.NoDisplay、无 LAUNCHER category、组件 disabled | aapt dump badging + manifest;反编译查图标像素;异常项入证 | E-android-hidden-icon-manifest | P0 |\n| **AV** | 已装但桌面无图标,后台流量/自启/高危权限/动态恢复图标 | pm list vs 桌面;dumpsys package;广播与 device_admin;行为入证 | E-android-hidden-icon-behavior | P1 |\n\n---\n\n> **以下 §9–§23 为 Issue #87 扩展规则(AW–DC)。**\n> 已去除与现有文件重复的 ELF(→ elf-analysis.md)、Mach-O(→ platforms.md)、Python(→ languages.md)章节。\n\n## 9. PDF 恶意文档(AW AX AY AZ)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **AW** | pdfid 检出 /JS、/JavaScript、/OpenAction、/AA、/Launch 计数 >0(含 hex 编码名称如 /4A#61#76#61... 的混淆计数) | pdfid -e 统计(对比 plain vs obfuscated 计数);pdf-parser 提取可疑对象;peepdf 交互分析 + JS 仿真 | E-pdf-autoaction | P0 |\n| **AX** | pdfid 检出 /EmbeddedFile >0;对象流含 FlateDecode/ASCIIHexDecode 级联过滤器链;或 /Annot 对象中隐藏编码载荷 | pdf-parser 提取流数据;peepdf 解码多层级联过滤器(含 AES 加密流 security handler r5/r6);检查 Annotation 对象;file 识别解码结果类型 | E-pdf-embedded | P0 |\n| **AY** | 提取的 PDF JS 含大量 eval、unescape、String.fromCharCode、atob | peepdf JS 仿真环境执行跟踪;逐层解码 Base64/Hex/ROT13;CyberChef 辅助 | E-pdf-js-deobf | P1 |\n| **AZ** | PDF 结构异常:/JBIG2Decode、XREF 表被操纵、对象编号跳跃 | pdfid -d 重命名可疑关键字;检查已知 CVE 利用模式;提取 exploit 触发条件 | E-pdf-exploit | P1 |\n\n## 10. Office OOXML / DDE / RTF(BA BB DK)→ 与 §3 VBA 互补\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **BA** | docx/xlsx/pptx ZIP 解压后 word/_rels/ 或 xl/_rels/ 中含可疑外部关系(含 remote template injection) | 检查 *.rels 外部链接;检查 vbaData.xml;提取嵌入 OLE 对象;检查协议处理器滥用(ms-msdt: / search-ms: / ms-officecmd:) | E-office-ooxml | P0 |\n| **BB** | 文档含 DDEAUTO 或 DDEEXEC 域代码,通过域执行外部命令 | olevba --dde 扫描;提取 DDE 命令参数;检查是否指向 PowerShell/外部 exe | E-office-dde | P0 |\n| **DK** | .rtf 文件含嵌入 OLE 对象(非 OOXML、非经典 OLE 复合文档) | rtfobj 提取嵌入 OLE 对象;oleobj 分析对象类型;检查 Equation Editor 漏洞利用(CVE-2017-11882 等);file 识别提取物类型 | E-rtf-ole | P0 |\n\n## 11. WebAssembly(BC BD BE)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **BC** | 文件以 \\x00asm 魔术字节开头;或 JS 代码含 WebAssembly 实例化逻辑 | wasm2wat 转文本;检查 import 段识别宿主环境导入函数;wasm-decompile 生成伪代码;检查 Emscripten 胶水签名(__wasm_call_ctors)判断是否由 JS 编译而来 | E-wasm-struct | P0 |\n| **BD** | WASM 函数数量多但逻辑简单、函数体被拆分为微小函数;或存在无意义 block/loop 嵌套 | diswasm 评估函数最小化级别;JEB Pro / IDA WASM 插件深度分析;动态追踪执行日志 | E-wasm-obfuscation | P1 |\n| **BE** | WASM 模块通过 JS 导入/导出函数与浏览器交互,存在 WebSocket、fetch、WebGL 调用 | 同时分析 JS 胶水代码和 WASM 模块;浏览器 DevTools 追踪数据交换;提取网络通信 URL/域名 | E-wasm-c2 | P1 |\n\n## 12. Java JAR/Class(BF BG BH BI)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **BF** | JD-GUI/jadx 打开 JAR 时类名/方法名为无意义短字符(a.a.a / _0x 前缀 / 数字类名);或大量 while/switch 控制流混淆 | 识别混淆器类型(ProGuard / Allatori / ZKM);Java Deobfuscator 静态反混淆;高强度时动态调试追踪关键逻辑 | E-java-obfuscation | P0 |\n| **BG** | 大量 Class.forName()、Method.invoke()、Constructor.newInstance();或自定义 ClassLoader + defineClass() 从字节数组内存加载类;导入表无害但运行时动态加载恶意类 | javap -c -v 查看反射调用细节;追踪 Class.forName 参数字符串;检查 defineClass() 字节数组来源;动态对 Method.invoke 下断 | E-java-reflection | P0 |\n| **BH** | JAR 含 .so(Linux/Android)或 .dll(Windows);或 System.loadLibrary() 调用 | 提取原生库文件;file 识别格式;转入 ELF/PE 独立分析流程 | E-java-native | P1 |\n| **BI** | JAR/ZIP 解压后含嵌套 JAR/WAR/EAR;/resources、/assets 中存在高熵 .dat/.bin/.img 文件 | 递归解压所有嵌套归档;熵值分析判断加密/压缩;检查 META-INF/MANIFEST.MF 和 pom.xml | E-java-nested | P1 |\n\n## 13. AutoIt(BJ BK BL DM)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **BJ** | PE 字符串含 AutoIt / AU3 / EA05 / EA06 签名;或资源节含 AutoIt 脚本资源(注意与 AutoHotKey 区分,MITRE T1059.010 两者共用) | autoit-ripper 提取编译脚本;识别编码家族(EA05 = AutoIt3.00 / EA06 = AutoIt3.26);EA06 头部后提取 8 字节解密密钥用于解密载荷;还原源码 | E-autoit-extract | P0 |\n| **BK** | 提取脚本含大量 StringEncrypt/_StringEncrypt;或 Execute 动态执行 + 无意义变量名 | myAutToExe 静态反编译;识别反调试技术;分析混淆后控制流 | E-autoit-deobf | P1 |\n| **BL** | 脚本含 RegWrite(注册表持久化)、FileInstall(文件释放)、InetGet(网络下载)、Run/RunWait | 标记敏感 API 调用序列;分析 InetGet URL;追踪 FileInstall 释放路径 | E-autoit-malicious | P0 |\n| **DM** | AutoIt 作为 loader 执行进程空洞注入(process hollowing):CallWindowProc/EnumWindows 回调 + shellcode + 注入合法进程(regsvcs.exe 等),释放 .NET 载荷(DarkGate / Snake Keylogger / ArechClient2 模式) | 检查 DllCall/DllCallbackRegister 对 kernel32 注入 API 的调用链;提取 shellcode 数据;识别被注入目标进程;提取 .NET 载荷独立分析 | E-autoit-hollowing | P0 |\n\n## 14. HTA / HTML Application(BM BN BO)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **BM** | HTML 含 HTA:APPLICATION 标签、window.execScript 或 CreateObject 调用 | 检查 HTA:APPLICATION 属性(Application、WindowState);提取 script 标签中的 VBS/JS | E-hta-bypass | P0 |\n| **BN** | HTA 通过 mshta.exe 启动后 XMLHttpRequest / ActiveXObject 远程拉 Payload 执行 | 提取网络请求 URL;跟踪 ActiveXObject 创建(ADODB.Stream 等);还原完整下载执行链 | E-hta-download-chain | P0 |\n| **BO** | HTA 仅含单行极长混淆字符串,经 eval / execScript 执行 | 提取 Base64/Hex 编码载荷解码;CyberChef 递归检测编码类型;还原载荷 | E-hta-oneline | P1 |\n\n## 15. WSF / JSE / VBE(BP BQ BR BS)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **BP** | .wsf 含 \\\u003cjob\\> + \\\u003cscript language=\"...\"\\> 标签,混合 JScript/VBScript/Python | 按 \\\u003cscript language\\> 分割代码块;分别按对应语言规则分析 | E-wsf-multi | P0 |\n| **BQ** | .jse/.vbe 开头含 #@~^ 签名,Microsoft Script Encoder 编码 | screnc-decoder 解码;无工具时动态执行 + dump 解码脚本 | E-jse-decode | P0 |\n| **BR** | WSF 多 \\\u003cscript\\> 块 + \\\u003cpackage\\> 引用外部资源 + \\\u003ccomponent\\> 引用 COM 组件 | 建立跨块调用图;追踪 \\\u003cscript\\> 之间函数调用;还原完整执行流程 | E-wsf-call-chain | P1 |\n| **BS** | WSF 含 WshShell.SendKeys 绕过 UAC、WshShell.Run 配合 0 窗口隐藏、WScript.Sleep 延时绕过 | 检查用户模拟操作是否用于绕过安全提示;记录隐蔽执行参数 | E-wsf-anti-detect | P1 |\n\n## 16. MSI 安装包(BT BU BV)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **BT** | MSI 文件含 CustomAction 表(Binary / Script / DLL 类型自定义操作) | msiexec /a 或 lessmsi 提取内容;检查 CustomAction 表;提取自定义操作二进制文件 | E-msi-custom-action | P0 |\n| **BU** | MSI Binary 表含 VBScript/JScript 自定义操作脚本 | 从 Binary 表提取脚本二进制解码为可读脚本;按 VBS/JS 规则分析 | E-msi-script | P1 |\n| **BV** | MSI 通过 /quiet /passive /qn 静默安装;ALLUSERS=1 提权 | 记录安装命令行参数;分析 Property 表权限设置;标记静默+提权组合 | E-msi-privilege | P1 |\n\n## 17. REG 注册表脚本(BW BX BY)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **BW** | .reg 写入 HKCU\\...\\Run 或 HKLM\\...\\Run 等自动启动路径 | 提取所有路径;标记 Run 路径条目为持久化;记录完整路径和值 | E-reg-persistence | P0 |\n| **BX** | .reg 修改 HKCR\\...\\shell\\open\\command(文件关联)或 HKCR\\CLSID\\{...}\\InprocServer32(DLL 注入) | 检查 shell\\open\\command 是否为非常规 exe;检查 InprocServer32 DLL 路径 | E-reg-hijack | P0 |\n| **BY** | .reg 修改 HKLM\\...\\Policies\\System(UAC 级别)、EnableLUA、ConsentPromptBehaviorAdmin | 检查修改前默认安全配置;分析对 UAC 的影响;标记降级行为 | E-reg-uac-bypass | P1 |\n\n## 18. VBScript(BZ CA CB CC DN)\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **BZ** | .vbs/.js 同时被 VBScript 和 JScript 解析;条件编译(@_win32)或语言特性交叉执行 | 分离 VBScript/JScript 代码块;分别语法分析;识别混合执行逻辑 | E-vbs-mixed | P1 |\n| **CA** | 脚本含 CreateObject(\"WScript.Shell\") / CreateObject(\"Shell.Application\") / Scripting.FileSystemObject | 标注高危 COM 对象调用;跟踪 Run/Exec 参数;追踪 FSO 创建的文件路径 | E-vbs-com-abuse | P0 |\n| **CB** | 脚本开头 #@~^ 签名,Microsoft Script Encoder 编码(VBS 专有) | screnc-decoder 解码;无工具时动态执行 + dump 解码脚本 | E-vbs-encoded | P0 |\n| **CC** | VBA/VBScript 含 WScript.Shell.Run + cmd /c + PowerShell,后续进程注入 | 追踪 CreateObject COM 对象链;分析 Run 参数中注入特征;记录完整进程创建链 | E-vbs-inject-chain | P0 |\n| **DN** | VBScript/JScript 通过 WMI ActiveScriptEventConsumer 实现无文件持久化(无启动文件夹/注册表 Run 键) | 检查 WMI 事件订阅(__EventFilter + __FilterToConsumerBinding + ActiveScriptEventConsumer);提取绑定脚本内容;标记无文件持久化 | E-vbs-wmi-persist | P0 |\n\n## 19. BAT/CMD 高级混淆(CD–CI)→ 与 §1 U–W 互补\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **CD** | setlocal enabledelayedexpansion + !var! + 动态变量名(!var_%i%!) | 启用延迟扩展后逐条展开;Batch-Dump --expand 自动展开 | E-bat-delayed-expand | P0 |\n| **CE** | 通过 type/more/findstr 读取自身或文件的 :stream ADS 替代数据流执行 | 检查 : 后缀引用(file.bat:payload);dir /r 列 ADS;type file:stream 提取 | E-bat-ads-hidden | P0 |\n| **CF** | 大量 echo 逐行写入 .tmp/.cmd 临时文件再 call 执行 | 提取所有 echo 重定向还原临时文件内容;监控临时目录生成的脚本 | E-bat-temp-gen | P1 |\n| **CG** | for %%i in (...) do set var=%%i 累加变量;for /f 逐行解析命令输出 | 逐条展开 for 循环记录每次迭代赋值;序列化还原 for /f 结果 | E-bat-for-expand | P1 |\n| **CH** | 主批处理通过 %1 %* 接收参数,由父进程/下载器传入混淆指令 | 检查调用上下文记录传入参数;Base64 参数解码还原;还原完整调用链 | E-bat-param-call | P1 |\n| **CI** | certutil -decode / powershell -Command / echo \\| findstr 组合解码执行 | 提取 Base64/Hex 字符串解码;检查解码结果是否为可执行脚本/PE | E-bat-encoded-exec | P0 |\n\n## 20. PowerShell 高级绕过(CJ–CO, DL)→ 与 §2 X–Z 互补\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **CJ** | [Ref].Assembly.GetType('...AmsiUtils') / amsiInitFailed / GetTypes() 等 AMSI 绕过(含硬件断点绕过:CPU 调试寄存器,无内存写入/VirtualProtect) | 识别绕过模式(Patch / 注册表 / 环境变量 / 硬件断点);动态确认生效;标记绕过技术类型 | E-ps-amsi | P0 |\n| **CK** | [PSConstraintLanguage] 类型操作或通过 DefaultRunspace 修改会话状态绕过 CLM | 识别 CLM 绕过模式;标记 bypass-clm;分析绕过后执行上下文 | E-ps-clm-bypass | P0 |\n| **CL** | [ScriptBlock]::Create / $ExecutionContext.InvokeCommand 构造器;或覆盖 ScriptBlock 日志设置 | 检查脚本是否禁用日志记录;动态验证日志是否被绕过 | E-ps-sb-log-bypass | P1 |\n| **CM** | IEX (New-Object Net.WebClient).DownloadString(...) 或 [Reflection.Assembly]::Load(FromBase64...) 无文件执行 | 提取下载 URL 检查域名/IP 信誉;PS 日志捕获内存加载代码;隔离网络模拟提取载荷 | E-ps-reflect-load | P0 |\n| **CN** | 三层以上编码嵌套:外层 Base64 → Gzip → XOR → 明文(超出 §2 X 的两层范围) | 递归解码到明文或无法继续;每层记中间状态;PowerDecode 自动化;每层结果入证 | E-ps-multi-decode | P0 |\n| **CO** | Set-Alias 将 IEX 映射为单字符别名;Get-ChildItem variable: 动态获取变量值 | 展开所有别名映射替换回原始命令名;AST 分析还原变量 | E-ps-alias-decode | P1 |\n| **DL** | 脚本含 ntdll.dll EtwEventWrite 补丁(stomping)静默遥测;常与 AMSI 绕过组合使用 | 检查是否存在 EtwEventWrite 地址获取 + 内存补丁(ret 0xC3);与 CJ AMSI 绕过同时检查;标记双绕过组合 | E-ps-etw-bypass | P0 |\n\n## 21. JavaScript 高级混淆(CP CQ DE DF)→ 与 §4 AD–AF 互补\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **CP** | JS 使用 Proxy 对象拦截属性访问 + Reflect API 动态调用方法绕过静态分析 | 识别 Proxy get/set/apply 陷阱函数;追踪 Reflect.get 实际目标;标记动态拦截行为 | E-js-proxy | P1 |\n| **CQ** | JS 含 _0x... 十六进制字符串数组 + while(!![]) 死循环 + for+switch 控制流(obfuscator.io 特征) | 识别 obfuscator.io 特征(字符串数组+死循环);de4js / jsnice 自动反混淆;还原后代码入证 | E-js-obfuscator | P0 |\n| **DE** | JS 主体为大型字节码数组 + VM 解释器循环(多 while/switch),入口指向 eval/Function 构造器;业务逻辑完全不可读(§4 AD 的深化) | 识别 VM 入口函数跟踪 opcode→处理函数映射;浏览器动态执行 Hook eval 输出;JSimplifier AST 重构;记录 opcode 映射表 | E-jsvmp-deep | P0 |\n| **DF** | JS 含 eval 动态生成新代码并立即执行、document.write 重写页面、或 Function 构造器动态构造函数体 | Hook eval 和 Function 构造函数记录生成的代码;浏览器动态执行捕获自修改内容 | E-js-selfmod | P1 |\n\n## 22. Xposed/LSPosed 模块分析(CR–CX)→ apk-reverse\n\n> 分析 Xposed/LSPosed **模块本身**作为逆向目标(非工具使用场景)。\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **CR** | AndroidManifest.xml 无 android:name 入口 Activity;meta-data 指定 xposedmodule=true | 检查 assets/xposed_init 确定入口类;搜索 IXposedHookLoadPackage/ZygoteInit/CmdInit 接口实现 | E-xp-entry | P0 |\n| **CS** | 代码含 XposedHelpers.findAndHookMethod / XposedBridge.hookMethod / findClass | 提取 findAndHookMethod 第一参数(目标类)+ 第二参数(目标方法);建立目标应用清单 | E-xp-hook-targets | P0 |\n| **CT** | 模块含 DexClassLoader/PathClassLoader 动态加载;或 Runtime.exec / ProcessBuilder 执行命令 | 追踪 DexClassLoader 构造参数;提取动态加载 DEX 独立分析;检查 exec 命令参数 | E-xp-dynamic-load | P0 |\n| **CU** | Hook 目标涉及支付/生物识别/短信/通讯录/位置/加密密钥等敏感 API | 对 Hook 目标类/方法进行敏感度分类;标记支付类/生物识别类/短信通讯录类;汇总威胁等级 | E-xp-sensitive-hooks | P0 |\n| **CV** | 代码含 XposedBridge 检测规避 / Zygote 注入痕迹清除 / 自定义网络通信 | 检查 stacktrace 修改 / XposedBridge 类引用清除;检查独立网络请求(OkHttp/Socket);识别 C2 目标 | E-xp-anti-detection | P1 |\n| **CW** | 代码含 Resources 动态替换 / View 绘制拦截 / AccessibilityService 声明 | 检查 AssetManager 替换 / Resources.updateConfiguration;检查 AccessibilityService 配置;识别 UI 劫持 | E-xp-ui-hijack | P1 |\n| **CX** | AndroidManifest.xml 声明 lsposed xposedscope meta-data;或代码含包名白名单检查 | 解析 xposedscope 目标应用范围;检查动态白名单绕过(反射修改 scope);识别全局 Hook 越权 | E-xp-scope-bypass | P1 |\n\n## 23. Magisk 模块深度分析(CY–DC, DG–DI)→ 与 §7 AR–AT 互补\n\n> §7 聚焦格机/破坏行为。本节覆盖非破坏性但可疑的模块行为:安装脚本分析、文件释放、Zygisk 注入、反检测、持久化、提权、横向感染。\n\n| ID | 触发 | 动作(摘要) | Evidence | 优先 |\n|----|------|--------------|----------|------|\n| **DG** | Magisk 模块 ZIP 根目录含 config.sh / install.sh;META-INF/com/google/android/update-binary 为非标准安装器 | 提取 config.sh/install.sh 中 on_install/print_modname/set_permissions 函数;检查 update-binary 是否含额外载荷;标记 pm install / dd 块设备 / mount -o remount,rw 操作 | E-mg-install-script | P0 |\n| **DH** | ZIP 内含 system/ / vendor/ / data/ 目录结构;或 post-fs-data.sh / service.sh 等开机执行脚本 | 提取释放文件路径识别是否释放 APK 到 /system/priv-app/;检查 service.sh + post-fs-data.sh 内容识别开机自启/后台保活/C2 通信;标记所有写入系统分区操作 | E-mg-file-drop | P0 |\n| **CY** | 模块含 zygisk/ 目录(arm64-v8a.so 等原生库);或 config.sh 声明 IS_ZYGISK=true | 提取 zygisk/ 原生库分析 ZygiskModule 回调(onLoad / preAppSpecialize / postAppSpecialize);检查 JNI Hook | E-mg-zygisk | P0 |\n| **DI** | 模块脚本写入 /data/adb/service.d/ 或 /data/adb/post-fs-data.d/;或修改 crontab/init.rc(§7 AT 的深化) | 提取写入 service.d + post-fs-data.d 的脚本内容;检查卸载时自动感染其他模块的逻辑(post-uninstall.sh / 模块目录监控);检查 magisk --remove-modules 触发保护机制 | E-mg-persistence | P0 |\n| **CZ** | 模块脚本含 resetprop 修改系统属性 / magiskhide / DenyList;或集成 Shamiko(隐藏 Zygisk 本身)/ TrickyStore(篡改证书链)/ PlayIntegrityFork(伪造 Play Integrity API) | 提取所有 resetprop 调用识别被修改属性(ro.debuggable / ro.build.tags 等);检查 DenyList 隐藏自身;识别 Shamiko/TrickyStore/PlayIntegrityFork 模块级反检测 | E-mg-anti-detect | P0 |\n| **DA** | 模块脚本含 setenforce 0 / mount -o rw,remount /system / chmod 777 敏感目录 | 检查 SELinux 操作(setenforce/chcon/restorecon);检查系统分区挂载 + dm-verity 禁用;标记高危提权 | E-mg-privilege | P0 |\n| **DB** | 释放 APK/脚本含 curl/wget/HTTP 客户端;或释放 APK 申请 INTERNET + READ_CONTACTS/SMS 等敏感权限 | 提取网络请求目标 URL/IP;分析释放 APK 权限声明;识别数据外传逻辑 | E-mg-c2 | P0 |\n| **DC** | 脚本遍历 /data/adb/modules/ 目录、修改其他模块文件、或写入自身副本到其他模块 | 检查 module.prop 注入恶意指令;检查其他模块 service.sh 追加恶意代码;识别\"寄生\"逻辑 | E-mg-cross-infect | P0 |\n\n---\n\n## 24. 约束(全局)\n\n1. **不平行主流程**:阶段门闩仍以 re-agent-workflow / 各 skill 为准。 \n2. **Evidence 必记**:含失败、半还原、quality= 标注。 \n3. **与 A–T 去重**:PE 反调试不重复;AM→R;AJ 补 DLL 视角不推翻 TLS 火箭。 \n4. **工具缺失**:记 n/a + 手工等价,不假装已用商业套件。 \n5. **授权**:破坏性/注入/驱动漏洞类只做防御分析与取证表述。\n6. **扩展规则去重**:ELF → elf-analysis.md;Mach-O → platforms.md;Python → languages.md。本表不重复这些格式的规则。\n\n## 25. P0 最小勾选(类型命中时)\n\n```text\n□ bat/cmd → U(+ 需要时 V/W;高级 CD–CI)\n□ ps1 → X(+ Z;高级 CJ–CO + DL ETW)\n□ vba/xlm → AA + DD + DJ(+ AB/AC)\n□ office ooxml/rtf → BA + DK(+ BB 若疑 DDE)\n□ js 强混淆 → AD 或 AE(+ AF;高级 CP/CQ/DE/DF)\n□ sys → AG + AH(+ AI 若疑 BYOVD)\n□ dll → AJ + AK/AL;Delay-Load 走 R\n□ apk 破坏/隐藏 → AR/AS 或 AU(+ AT/AV)\n□ pdf → AW + AX(+ AY/AZ)\n□ wasm → BC(+ BD/BE)\n□ jar/class → BF + BG(+ BH/BI)\n□ autoit → BJ + BL + DM(+ BK)\n□ hta → BM + BN(+ BO)\n□ wsf/jse/vbe → BP + BQ(+ BR/BS)\n□ msi → BT(+ BU/BV)\n□ reg → BW + BX(+ BY)\n□ vbs → CA + CB + CC + DN(+ BZ)\n□ xposed 模块 → CR + CS + CT + CU(+ CV–CX)\n□ magisk 深度 → DG + DH + CY + DI + CZ + DA(+ DB/DC)\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":30309,"content_sha256":"6e5fd5f6cdef266ff0c5951d6cdddb9c4711610e0372f269425796f36c36c5ad"},{"filename":"references/ollvm-deobfuscation.md","content":"# OLLVM 反混淆 / Obfuscator-LLVM Deobfuscation\n\n> 面向 APK .so、ELF 二进制和控制流平坦化场景的 OLLVM 脱密工作流。\n> 工具与变种信息基于 2026 年社区活跃项目调研,非训练记忆。\n> 适用:Android NDK 加固、CTF 逆向、加壳 .so 分析、商业混淆器对抗。\n\n---\n\n## 0. 快速决策:我该用哪个工具?\n\n根据你的环境和对目标混淆类型的判断,直接对号入座:\n\n| 你的情况 | 首选工具 | 备选 | 说明 |\n|---------|---------|------|------|\n| 有 IDA Pro 7.5-7.7 + Hex-Rays,想一键去平坦化 | **obpo-plugin** | d810-ng | obpo 用 microcode + 数据流 + 混合执行,效果最强,但是云插件(需联网,核心闭源) |\n| 有 IDA Pro(任意较新版本),想本地一站式反混淆 | **d810-ng** | D-810 原版 | 本地、开源、集成 Z3,支持 OLLVM/Tigress/Hodur/Approov 多变种 |\n| 有 Binary Ninja | **ollvm-breaker** | — | 针对 Android .so 实战(libvdog 等加固样本) |\n| 无 IDA/BN,纯脚本,目标 x86/x64 | **ollvm-unflattener** (Miasm) | angr deflat | 基于 Miasm 符号执行,BFS 多层处理 |\n| 无 IDA/BN,纯脚本,目标 x86/x64 | **ollvm-unflattener** (Miasm) | angr deflat | 基于 Miasm 符号执行,BFS 多层处理 |\n| 纯 Python 符号执行,CTF 场景 | **angr** Deobfuscator | Triton | 不依赖 GUI,脚本化 |\n| 目标是 ARM64 .so,无 IDA | **deollvm** (Unicorn) | angr | 基于 Unicorn 的 ARM64 deflat |\n| 遇到 BR 混淆(间接分支) | **DeObfBR** | 设置数据段只读 | Goron/Arkari 风格的 BR 混淆可被数据段只读简单对抗 |\n| 遇到 Tigress 混淆 | d810-ng `UnflattenerSwitchCase`/`UnflattenerTigressIndirect` | — | d810-ng 内置 Tigress 专用 unflattener |\n\n> **核心建议:** 优先用 **d810-ng**(本地、维护活跃、变种覆盖广)。云服务可用时 **obpo-plugin** 效果最好。两者都失败再上 **angr/Miasm** 符号执行做定制化处理。\n\n---\n\n## 1. 现代 OLLVM 变种生态(2026 社区调研)\n\nOLLVM 早已不只是 2017 年那个原始仓库。以下是目前活跃的混淆器分支,**脱密前必须先判断目标是哪个变种**,因为不同变种的对抗手段差异很大:\n\n### 1.1 混淆器分支谱系\n\n| 变种 | 基准 LLVM | 相比原始 OLLVM 的新增特性 | 对抗要点 |\n|------|----------|----------------------|---------|\n| **Obfuscator** (原始) | 3.3~4.0 | sub + bcf + fla(三大基础 pass) | 标准工具均可处理 |\n| **Hikari** | 6~8 | Anti Class Dump、Function Call Obfuscate、Function Wrapper、Indirect Branching、Split BB、String Encryption | 需先解密字符串 + 修复间接跳转 |\n| **Hikari-LLVM15** | 15~19 | + Anti Debugging、Anti Hook、Constant Encryption | 已闭源;Constant Encryption 增加静态分析难度 |\n| **goron** | 7~10 | Indirect Branch/Call/GlobalVariable | ⚠️ Goron 风格间接混淆可被「设置数据段只读」简单对抗 |\n| **Arkari** (komimoe/Hikari) | 14~latest | 基于 goron,持续维护 | 同 goron,数据段只读即可部分对抗 |\n| **Pluto** | 14 | MBA Obfuscation、Random CF、Split BB、**Trap Angr**(专门坑 angr) | ⚠️ Trap Angr pass 会让 angr 符号执行失效,需换工具或绕陷阱 |\n| **Polaris** (原 Pluto) | 16 | Alias Access、Indirect Branch/Call、String Encryption、Merge Function、Linear MBA、Dirty Bytes Insertion、Function Splitting、Junk Insertion | 综合 Hikari+Pluto,最棘手,需分层处理 |\n| **O-MVLL** | open-obfuscator | Python 驱动 pass manager;Anti Hooking、Arithmetic(MBA)、BB Duplicate、CF Breaking、Function Outline、Indirect Branch/Call、Opaque Constants | 现代 Android 加固常用,Python 配置易定制 |\n| **amice** (Rust) | Rust 实现 | 全套 + VM Flatten、Instruction Virtualization、Delayed Offset Loading、Parameter Aggregation | 含 VM 化,需 VM handler 还原而非单纯 deflat |\n| **VMP 系** (SmallVmp/VMPilot/xVMP/VMPacker) | — | 指令虚拟化 | **不属于 OLLVM 范畴**,需 VM 逆向,参考 VM 专用工具 |\n\n### 1.2 关键判断线索\n\n- **Trap Angr**(Pluto/Polaris):如果 angr 跑着跑着爆炸或路径爆炸,怀疑目标用了 Trap Angr pass → 改用 d810-ng 或 Unicorn 动态方法\n- **Goron/Arkari 间接跳转**:如果分发器用间接跳转(BR x8 而非 switch),先尝试把相关数据段设为只读,间接跳转目标常变成可静态求解\n- **Constant Encryption**(Hikari-LLVM15/Polaris/O-MVLL):常量在运行期解密,纯静态看不到真实值 → 需要 Unicorn 动态执行解密 stub\n- **VM Flatten**(amice):控制流变成 VM dispatch loop,**不要当普通 fla 处理**,需要先识别 VM handler 表\n\n---\n\n## 2. OLLVM 混淆类型检测\n\nOLLVM 三大核心 pass 的识别特征:\n\n### 2.1 控制流平坦化 (Control Flow Flattening / `fla`)\n\n**IDA 视图特征:**\n- 函数入口先跳转到唯一的分发器(dispatcher)块\n- 主逻辑被拆成多个基本块,每个块末尾跳回分发器\n- 分发器通过**状态变量**(state variable)决定下一个要执行的块\n- 巨大的 `switch` 结构,各 case 之间无逻辑关联\n\n```\nOriginal: OLLVM flattened:\n block_A entry -> dispatcher\n block_B ↓\n block_C state_machine:\n switch(state):\n 0 → block_A\n 1 → block_B\n 2 → block_C\n```\n\n**变种形态(d810-ng 识别的多种 dispatcher):**\n- O-LLVM:switch / if-chain + 状态变量\n- Tigress:`m_jtbl`(switch-case)或 `m_ijmp`(间接跳转,需 `goto_table_info` 配置)\n- Hodur (PlugX):嵌套 `while(1)` 状态机,`jnz state, #CONST`,**无 switch 分发器**\n- Approov:`while(v8 != C)`,状态常量集中在 `0xF6000–0xF6FFF`\n\n### 2.2 虚假控制流 (Bogus Control Flow / `bcf`)\n\n- 每个真实分支间插入**不可达假分支**\n- 假分支用**不透明谓词**保护(条件恒真/恒假,但静态分析无法直接证明)\n- 大量死代码膨胀函数体积\n\n```c\n// 经典不透明谓词:x(x+1) 必为偶数,编译器证明不了\nif (x * (x + 1) % 2 == 0) {\n // 真实逻辑\n} else {\n // 不可达垃圾代码\n}\n```\n\n### 2.3 指令替换 (Instruction Substitution / `sub`) → MBA\n\n- 简单算术/位运算替换为等价复杂表达式(MBA, Mixed Boolean-Arithmetic)\n\n```\na + b → (a ^ b) + 2*(a & b)\na ^ b → (a | b) - (a & b)\na - b → a + (~b) + 1\n```\n\n### 2.4 快速分类表\n\n| 混淆类型 | IDA 特征 | 主要对抗手段 |\n|---------|---------|------------|\n| fla (平坦化) | 巨大 switch + 分发器 | obpo / d810-ng / deflat |\n| bcf (虚假控制流) | 不可达分支 + 死代码 | d810-ng opaque predicate removal / 符号执行 |\n| sub/MBA | 复杂算术表达式 | d810-ng MBA simplifier / SiMBA (Z3) |\n| fla + bcf + sub | 全上,极大膨胀 | **分层去混淆(先 bcf 再 fla 再 sub)** |\n\n---\n\n## 3. 主流工具详解(社区活跃项目)\n\n### 3.1 obpo-plugin — 最强效果,云插件\n\n> [obpo-project/obpo-plugin](https://github.com/obpo-project/obpo-plugin) · 629⭐ · 2026-06 活跃\n\n基于 Hex-Rays **microcode** 的伪代码优化器,使用**数据流跟踪 + 程序切片 + 混合执行(concolic)**重建平坦化控制流。效果是社区公认最强之一。\n\n**关键特性:**\n- 在 microcode 层操作,直接优化反编译输出(不是改 ASM)\n- 支持 IDA 7.5.0 / 7.6.0 / 7.7.0 + Hex-Rays\n- 架构:ARM, ARM64, x86, x86_64, PowerPC, PowerPC64, MIPS(7.6/7.5)\n- **云插件**:目标函数二进制会上传到 obpo-server 处理(核心闭源,插件免费开源)\n- 服务器自费维护,超时 600s,**禁止多线程/恶意调用**\n\n**安装与使用:**\n```text\n1. 下载 obpo_plugin.py 和 obpoplugin 目录\n2. 复制到 IDA plugins 路径\n3. 重启 IDA,打开目标二进制\n4. 在 CFG 中定位分发块(dispatcher),通常长这样:\n [截图参考仓库 assets/dispatchblock.png]\n5. 右键 → OBPO → Mark and process function\n6. 处理完成后刷新反编译器\n7. 可根据反编译变化继续标记新的分发块(迭代处理嵌套 fla)\n```\n\n**适用场景与限制:**\n- ✅ 标准和嵌套 fla,效果好\n- ⚠️ 需要联网,敏感样本(内部未公开漏洞、商业机密)慎用——二进制会上传\n- ⚠️ 服务器可能宕机,依赖作者维护\n- ❌ 不能解决所有混淆(作者明确声明)\n\n### 3.2 d810-ng — 本地一站式首选\n\n> [w00tzenheimer/d810-ng](https://github.com/w00tzenheimer/d810-ng) · 223⭐ · 2026-06-26 更新\n\nD-810 的现代维护/重构版(Next Generation)。本地运行、开源、集成 **Z3 SMT** 求解器,变种覆盖最广。\n\n**核心能力(按 d810-ng README 整理):**\n\n*指令级优化:*\n| 类别 | 说明 |\n|------|------|\n| MBA simplification | `(a+b)-2*(a&b) => a^b`,Z3 验证的 DSL 规则 |\n| Hacker's Delight | 位运算等价(来自 Hacker's Delight 一书) |\n| O-LLVM patterns | Obfuscator-LLVM 专用 MBA 模式 |\n| Constant folding | 22 条常量简化规则 |\n| Predicate simplification | 不透明谓词去除(setz/setnz/lnot/smod) |\n| Z3 rules | 模板匹配失败时用 SMT 求解 |\n| Hodur-specific | PlugX (Hodur) 恶意软件的 MBA 模式 |\n\n*控制流 Unflattener(按目标混淆分类):*\n| Unflattener | 目标 | 说明 |\n|------------|------|------|\n| `Unflattener` | O-LLVM | 标准 switch/if-chain + 状态变量 |\n| `UnflattenerSwitchCase` | Tigress | Tigress switch-case 分发(`m_jtbl`) |\n| `UnflattenerTigressIndirect` | Tigress | Tigress 间接跳转(`m_ijmp`),需 `goto_table_info` 配置 |\n| `HodurUnflattener` | Hodur (PlugX) | 嵌套 `while(1)` + `jnz state, #CONST`,无 switch |\n| `BadWhileLoop` | Approov | `while(v8 != C)`,状态常量在 0xF6000–0xF6FFF |\n| `UnflattenerFakeJump` | 通用 | 去除恒真/恒假的条件跳转 |\n| `SingleIterationLoopUnflattener` | 残留 | 清理 `INIT == CHECK` 且 `UPDATE != CHECK` 的单次循环 |\n| `UnflattenControlFlowRule` (实验) | 通用 | 基于 path emulation 的 CFG unflattener |\n\n**安装与使用:**\n```text\n1. clone d810-ng\n2. 安装依赖(含 Z3)\n3. 复制到 IDA plugins 目录\n4. IDA 中按 Ctrl-Shift-D 加载插件\n5. 在 GUI 中勾选要应用的规则集\n6. 对目标函数应用\n```\n\n**为什么选 d810-ng 而非原版 D-810:**\n- 原版 D-810 已较少维护\n- d810-ng 有 CI 测试、重构代码、新增 Tigress/Hodur/Approov 专用 unflattener\n- 集成 Z3,模板匹配失败时回退到 SMT 求解,成功率更高\n\n### 3.3 ollvm-unflattener — Miasm 符号执行,纯脚本\n\n> [cdong1012/ollvm-unflattener](https://github.com/cdong1012/ollvm-unflattener) · 265⭐ · 2026-06 活跃\n\n基于 **Miasm** 符号执行引擎,不依赖 IDA/BN,纯 Python 命令行。\n\n**特性:**\n- 用 Miasm 符号执行恢复原始控制流(区别于 MODeflattener 的纯静态方法)\n- **BFS 多层处理**:自动跟随目标函数的调用,递归去混淆\n- 支持 Windows/Linux x86/x64\n- 输出去混淆后的新二进制\n\n**安装与使用:**\n```bash\ngit clone https://github.com/cdong1012/ollvm-unflattener.git\ncd ollvm-unflattener\npip install -r requirements.txt # miasm, graphviz, keystone-engine\n\n# 基本用法\npython unflattener -i \u003cinput.bin> -o \u003coutput.bin> -t \u003cfunction_addr> -a\n# -a: 自动跟随调用做多层处理\n```\n\n**适用:** 无 IDA、目标 x86/x64、需要批量脚本化处理。\n\n### 3.4 ollvm-breaker — Binary Ninja 实战\n\n> [amimo/ollvm-breaker](https://github.com/amimo/ollvm-breaker) · 441⭐\n\n使用 **Binary Ninja** 去平坦化,仓库自带 Android 加固样本 `libvdog.so` 作为测试用例,已修复 JNI_OnLoad、crazy::GetPackageName、prevent_attach_one 等函数。\n\n**适用:** Binary Ninja 用户、Android .so 实战。\n\n### 3.5 deollvm — ARM64 Unicorn\n\n> [GeT1t/deollvm](https://github.com/GeT1t/deollvm) · 34⭐ · 2026-04\n\n基于 **Unicorn** 的 ARM64 OLLVM deflat。无 IDA 时处理 ARM64 .so 的备选。\n\n### 3.6 DeObfBR — BR 混淆专项\n\n> [Mrack/DeObfBR](https://github.com/Mrack/DeObfBR) · 96⭐ · 2026-06-25\n\n专门去除 **BR 混淆**(间接分支混淆,Goron/Arkari 风格)。\n\n**⚠️ 简易对抗技巧(来自 awesome-ollvm):** Goron/Arkari 风格的间接相关混淆,可以通过**设置数据段为只读**来简单对抗——间接跳转目标常依赖运行期可写的数据段,设只读后变成可静态求解。\n\n### 3.7 angr — 符号执行通用框架\n\n```python\nimport angr\n\nproj = angr.Project(\"target.so\", auto_load_libs=False)\ncfg = proj.analyses.CFGFast()\nfunc = proj.kb.functions[0x12345]\n\n# 内置 Deobfuscator\ndeob = proj.analyses.Deobfuscator(func=func)\ndeob.normalize()\n```\n\n**⚠️ Pluto/Polaris 的 Trap Angr pass:** 这两个变种专门写了 trap 来坑 angr 符号执行。如果 angr 路径爆炸或异常,怀疑目标用了 Trap Angr → 改用 d810-ng 或 Unicorn 动态方法。\n\n---\n\n## 4. 完整脱密工作流(按场景)\n\n### 4.1 通用决策树\n\n```\n目标二进制\n ↓\n1. 识别 OLLVM 变种(看 1.2 节线索)\n ├── 原始 OLLVM / Hikari / O-MVLL → 标准 fla/bcf/sub\n ├── Pluto / Polaris → 注意 Trap Angr,避开 angr\n ├── Goron / Arkari → 先试数据段只读,再处理 BR\n ├── Tigress → d810-ng Tigress unflattener\n ├── Hodur (PlugX) → d810-ng HodurUnflattener\n └── amice (含 VM) → 不是单纯 fla,需 VM handler 还原\n ↓\n2. 选择工具(看第 0 节决策表)\n ├── 有 IDA + 可联网 + 非敏感样本 → obpo-plugin\n ├── 有 IDA + 本地 → d810-ng\n ├── 有 Binary Ninja → ollvm-breaker\n ├── 无 GUI + x86/x64 → ollvm-unflattener (Miasm)\n ├── 无 GUI + ARM64 → deollvm (Unicorn) / angr\n └── 纯符号执行 / CTF → angr\n ↓\n3. 分层去混淆(顺序很重要)\n a) 先去除不透明谓词 (bcf) → d810-ng opaque predicate removal\n b) 再去除控制流平坦化 (fla) → unflattener\n c) 最后简化 MBA (sub) → d810-ng MBA simplifier / SiMBA\n ↓\n4. 验证\n ├── 函数体积显著减小?\n ├── CFG 从星形/放射状变为链形/树形?\n └── Frida hook 关键函数验证逻辑正确?\n```\n\n### 4.2 Android NDK .so 脱密专项\n\nAndroid NDK 编译的 .so 经 OLLVM 加固是 APK 逆向最常见的场景。\n\n**Step 1 — 提取 .so:**\n```bash\nadb pull /data/app/~~/lib/arm64/libnative.so\n# 或从 APK 直接解压:unzip target.apk -d out/ ; find out -name \"*.so\"\n```\n\n**Step 2 — 识别 OLLVM 与变种:**\n```bash\nreadelf -a libnative.so | grep -E \"Size|text\" # .text 异常大但函数少 → 大概率 OLLVM\n# IDA 打开看函数特征:\n# 巨大 switch → fla\n# 不可达分支 → bcf\n# 复杂算术 → sub/MBA\n# 间接跳转 BR x8 → Goron/Arkari,试数据段只读\n# while(1) + jnz state → Hodur,用 d810-ng HodurUnflattener\n```\n\n**Step 3 — 脱密(分层):**\n```\na) bcf: d810-ng opaque predicate removal (或 obpo 自动处理)\nb) fla: d810-ng Unflattener / obpo-plugin / deollvm(ARM64)\nc) sub: d810-ng MBA simplifier\n```\n\n**Step 4 — Frida 动态验证:**\n```javascript\n// Trace OLLVM 状态变量,辅助 deflat 确定状态变量地址\nconst target = Module.findBaseAddress(\"libnative.so\");\nconsole.log(\"[+] libnative.so @\", target);\n\n// 在分发器入口下 hook,观察 state 变化序列\nInterceptor.attach(target.add(0x1234), { // dispatcher offset\n onEnter(args) {\n // 读取状态变量(需根据反编译确定寄存器/栈位置)\n console.log(\"[state]\", this.context.x8); // 假设 state 在 x8\n }\n});\n```\n\n### 4.3 CTF 场景快速脱密\n\nCTF 通常时间紧,优先用最快路径:\n\n```python\n#!/usr/bin/env python3\n\"\"\"CTF OLLVM quick deflat with angr\"\"\"\nimport angr\n\nproj = angr.Project(\"challenge\", auto_load_libs=False)\ncfg = proj.analyses.CFGFast()\n\n# 找最大的几个函数(最可能是被混淆的)\nfuncs = sorted(cfg.functions.values(), key=lambda f: f.size, reverse=True)[:5]\nfor func in funcs:\n print(f\"[*] {func.name} @ {hex(func.addr)} size={hex(func.size)}\")\n try:\n deob = proj.analyses.Deobfuscator(func=func)\n deob.normalize()\n print(f\" [+] deobfuscated\")\n except Exception as e:\n print(f\" [-] failed: {e}\")\n # angr 失败 → 怀疑 Trap Angr → 换 d810-ng / Unicorn\n```\n\n---\n\n## 5. MBA 表达式简化\n\n### 5.1 常见 OLLVM MBA 模式\n\n```python\n# 这些等式是 OLLVM sub pass 生成表达式的化简目标\n\"(a | b) + (a & b)\" # → a + b\n\"(a | b) - (a & b)\" # → a ^ b\n\"(a ^ b) + 2*(a & b)\" # → a + b\n\"(a | b) & ~(a & b)\" # → a ^ b\n\"~(~a & ~b)\" # → a | b (De Morgan)\n```\n\n### 5.2 工具选择\n\n| 工具 | 方式 | 适用 |\n|------|------|------|\n| **d810-ng MBA simplifier** | IDA 内批量,Z3 验证 | 首选,集成在反编译流程 |\n| **SiMBA** (`pip install simba-simplifier`) | 命令行/库 | 纯表达式化简,批量处理 |\n| **Arybo** | 符号位向量 | 大量 MBA 表达式 |\n| **Z3 直接求解** | SMT | 最通用,模板匹配都失败时 |\n\n```python\n# SiMBA 示例\nfrom simba import simplify_mba\nexprs = [\"(a | b) + (a & b)\", \"(a ^ b) + 2*(a & b)\"]\nfor e in exprs:\n print(f\"{e} → {simplify_mba(e)}\")\n```\n\n---\n\n## 6. 完整脱密案例脚本\n\n```bash\n#!/bin/bash\n# OLLVM deobfuscation pipeline (2026 community tools)\n# 适用标准 OLLVM / Hikari / O-MVLL 加固的 ELF/.so\n\nBINARY=$1\n\necho \"[*] Stage 0: 基本分析与变种识别\"\nfile $BINARY\nreadelf -h $BINARY 2>/dev/null | head -5\necho \" → 在 IDA 中确认变种(参考第 1 节)\"\n\necho \"[*] Stage 1: d810-ng 本地反混淆(首选)\"\necho \" IDA → Ctrl-Shift-D 加载 d810-ng\"\necho \" 勾选: MBA + Opaque predicate + Unflattener\"\necho \" Apply to target functions\"\necho \" 保存 IDB\"\n\necho \"[*] Stage 2: obpo-plugin(如 d810-ng 效果不足且可联网)\"\necho \" IDA → 右键 dispatcher → OBPO → Mark and process\"\necho \" ⚠️ 敏感样本勿用(二进制上传云服务)\"\n\necho \"[*] Stage 3: 无 IDA 备选(x86/x64)\"\necho \" python unflattener -i $BINARY -o deobf.bin -t \u003cfunc_addr> -a\"\n\necho \"[*] Stage 4: ARM64 .so 无 IDA 备选\"\necho \" deollvm (Unicorn) 或 angr Deobfuscator\"\n\necho \"[+] Done. 在 IDA 中重新分析验证。\"\n```\n\n---\n\n## 7. 常见陷坑(社区实战总结)\n\n| 问题 | 原因 | 解决办法 |\n|------|------|---------|\n| angr 路径爆炸/异常退出 | Pluto/Polaris 的 **Trap Angr** pass | 换 d810-ng 或 Unicorn 动态方法 |\n| obpo-plugin 联不上 | 服务器自费维护,可能宕机 | 转用本地 d810-ng;可在 obpo 仓库提 issue |\n| Goron/Arkari 间接跳转 deflat 失败 | 分发器用 BR x8 而非 switch | 先把数据段设只读,再用 DeObfBR |\n| d810-ng 处理后函数仍乱 | OLLVM 自定义了 pass 参数/seed | 先符号执行去不透明谓词,再 unflatten |\n| 嵌套 fla(多层平坦化)一次没清干净 | obpo/d810-ng 单次只清一层 | **迭代处理**:每次标记新出现的 dispatcher |\n| ARM64 .so 用 deflat 报错 | 老 deflat 脚本只支持 x86 | 用 d810-ng / obpo(支持 ARM64)/ deollvm |\n| Hikari 字符串看不到 | String Encryption pass | 用 Unicorn 模拟解密 stub,dump 解密后字符串 |\n| amice 目标 deflat 完全无效 | 含 VM Flatten / Instruction Virtualization | **不是 OLLVM fla**,需 VM handler 还原(参考 VM 逆向) |\n| Hodur(PugX) 样本没有 switch 分发器 | 嵌套 while(1) + jnz state | 用 d810-ng **HodurUnflattener**,别用普通 Unflattener |\n| Approov 样本状态常量看不出规律 | 常量集中在 0xF6000–0xF6FFF | 用 d810-ng **BadWhileLoop** unflattener |\n| 敏感样本误用 obpo | 二进制上传云服务 | 涉密/未公开漏洞样本**只用本地工具**(d810-ng/angr) |\n| Frida hook OLLVM 函数卡死 | 状态变量被改导致无限循环 | 在分发器入口加条件断点限制执行次数 |\n\n---\n\n## 8. 工具速查表(2026 社区活跃度)\n\n| 工具 | 平台 | 方式 | Stars/价 | 最近更新 | 开源 | 备注 |\n|------|------|------|---------|---------|------|------|\n| **obpo-plugin** | IDA | microcode+concolic(云) | 629 | 2026-06 | 插件开源/核心闭源 | 效果最强,需联网 |\n| **ollvm-breaker** | Binary Ninja | BN API | 441 | 2026-06 | ✅ | Android .so 实战 |\n| **ollvm-unflattener** | CLI | Miasm 符号执行 | 265 | 2026-06 | ✅ | x86/x64,BFS 多层 |\n| **d810-ng** | IDA | microcode+Z3 | 223 | 2026-06 | ✅ | **本地首选**,变种覆盖广 |\n| **DeObfBR** | — | BR 混淆专项 | 96 | 2026-06 | ✅ | Goron/Arkari 间接分支 |\n| **IDA_Ollvm-unflattener** | IDA | Miasm 插件版 | 90 | 2026-04 | ✅ | ollvm-unflattener 的 IDA 插件封装 |\n| **deollvm** | CLI | Unicorn | 34 | 2026-04 | ✅ | ARM64 专项 |\n| **angr** | CLI | 符号执行 | — | 活跃 | ✅ | 通用,被 Trap Angr 克制 |\n| **SiMBA** | CLI/库 | MBA 化简 | — | — | ✅ | 表达式化简 |\n| **Triton** | CLI | 符号执行+污点 | — | 活跃 | ✅ | 动态符号执行 |\n\n---\n\n## 9. 参考链接\n\n**混淆器(用于理解对抗目标):**\n- [obfuscator-llvm/obfuscator](https://github.com/obfuscator-llvm/obfuscator) — 原始 OLLVM\n- [HikariObfuscator/Hikari](https://github.com/HikariObfuscator/Hikari) — Hikari\n- [komimoe/Hikari](https://github.com/komimoe/Hikari) — Arkari (基于 goron, LLVM 14+)\n- [amimo/goron](https://github.com/amimo/goron) — goron\n- [bluesadi/Pluto](https://github.com/bluesadi/Pluto) — Pluto\n- [za233/Polaris-Obfuscator](https://github.com/za233/Polaris-Obfuscator) — Polaris (原 Pluto)\n- [open-obfuscator/o-mvll](https://github.com/open-obfuscator/o-mvll) — O-MVLL\n- [fuqiuluo/amice](https://github.com/fuqiuluo/amice) — Rust 实现 OLLVM passes\n- [lich4/awesome-ollvm](https://github.com/lich4/awesome-ollvm) — **变种生态总览(强烈推荐先读)**\n\n**反混淆工具:**\n- [obpo-project/obpo-plugin](https://github.com/obpo-project/obpo-plugin) — 最强云插件\n- [w00tzenheimer/d810-ng](https://github.com/w00tzenheimer/d810-ng) — 本地首选\n- [cdong1012/ollvm-unflattener](https://github.com/cdong1012/ollvm-unflattener) — Miasm 纯脚本\n- [amimo/ollvm-breaker](https://github.com/amimo/ollvm-breaker) — Binary Ninja\n- [GeT1t/deollvm](https://github.com/GeT1t/deollvm) — ARM64 Unicorn\n- [Mrack/DeObfBR](https://github.com/Mrack/DeObfBR) — BR 混淆专项\n- [maskelihileci/IDA_Ollvm-unflattener](https://github.com/maskelihileci/IDA_Ollvm-unflattener) — IDA 插件版\n- [angr](https://angr.io/) — 符号执行框架\n- [SiMBA](https://github.com/tech-srl/simba) — MBA 化简\n\n**学术/博客:**\n- [Quarkslab: Deobfuscation: Recovering an OLLVM-protected program](https://blog.quarkslab.com/deobfuscation-recovering-an-ollvm-protected-program.html) — deflat 经典原理\n- [MODeflattener](https://github.com/mrT4ntr4/MODeflattener) — 静态 deflat(ollvm-unflattener 的对照)\n\n> 关联文档:[[anti-analysis.md]] (反调试/反分析总表)、[[tools-advanced.md]] (高级工具集)、[[elf-analysis.md]] (ELF 文件分析)、[[ai-assisted-re.md]] (AI 辅助逆向)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":23426,"content_sha256":"9bc48a802ec429ad1d7a1b097581c3c4988581576c6ef68e4e16f60e4b5afeed"},{"filename":"references/re-agent-workflow.md","content":"# RE Agent 工作流门闩(静态↔动态)\n\n> 来源启发:binary-re 阶段划分、社区 RE skill(Frida/r2/Ghidra/IDA 循环)、Cerberus 三头环(静/动/插桩) \n> Issue #65 增量:IAT 修复铁律、六阶段映射、.NET/DLL·SYS 等价路径;用户指令可行性门闩;旁路补丁 6–10;反调试/混淆菜谱 A–T;非 PE 多格式菜谱 U–AV(2026-08-12) \n> 适用:`reverse-engineering/`、`ida-reverse/`、`radare2/`、`malware-analysis/`、与 cre 角色交接\n\n## 0. 启动\n\n```text\n□ scope.md:offline 样本路径 或 授权设备/靶机\n□ tool-index:file/strings/r2/ida/frida 等实际路径\n□ 角色:cre(ops/role-map)\n```\n\n## 0.1 Transition handoff(decision delta)\n\n阶段之间不重新注入完整 case context。`scope.md` / `workitems.md` / Evidence 保持 authoritative;`timeline.md` 只承载 transition delta:\n\n1. stage/turn 结束时只写真正改变后续动作的 `decision_delta`;无变化写 `[]`。\n2. unchanged route/auth/scope/network profile/tool state/hypothesis 只放 `carry_forward_refs`,consumer 依引用读取,不重新 serialize / emit。\n3. `decision_delta` 不是完整 state;consumer 必须先继承 refs,再应用 delta。\n4. 只有两个或以上 evidence-supported 分支会导致不同下一动作时才停在 next-step menu;确定性 gate 直接推进。\n\n例:Triage 完成且唯一合法下一步是 Static 时,transition 只需 `decision_delta: [phase=triage->static]` + `carry_forward_refs: [scope.md, evidence/E-triage.md]`。\n\n## 0.5 用户指令可行性门闩(Issue #65)\n\n**原则**:服从用户**目标**,不盲从用户**步骤顺序**。跳步前必须说明前提并请确认;确认后的强制步骤必须做,且诚实标注 Evidence 质量。\n\n| 情况 | Agent MUST |\n|------|------------|\n| 用户要做 X,且当前状态可得到**有效** Evidence | 执行 X,更新 Evidence |\n| 用户要做 X,但存在**已知阻塞前提**(例:已判定加壳且静态 IAT 不可读) | **禁止**假装完成有意义的 IAT;① 一句话说清阻塞;② 给出推荐顺序(先脱壳/修 IAT,或直接动态抓 API);③ **请用户确认**是「仍强制看当前花表」还是「按推荐顺序」 |\n| 用户明确**强制**当前步骤(如未脱壳也要看 IAT) | 执行并记 Evidence,MUST 标注 `quality=unreadable` / `packed`(或等价);**禁止**据此下「无网络能力」等结论 |\n| 用户接受推荐顺序 | 先做前提步骤;完成后自动或再应要求做 X;**禁止**用前提步骤(如脱壳)**冒充**「已完成导入表检查」 |\n\n**与「重做 X」的关系**:重做 X 仍 = 重做被点名步骤(或其经确认的合法前提协商结果),禁止偷换成无关步骤。脱壳是导入表的**前提**,不是导入表的**替代品**。\n\n典型冲突:用户在加壳样本上说「先不要脱壳,先看导入表」→ 壳常篡改导入目录/加密描述符,静态表花且无意义 → 走本表「阻塞前提」行,不得默默脱壳冒充,也不得默默交出花表当完成。\n\n## 1. Triage(5–15 分钟 · 强制起点)\n\n```text\n□ 计算样本 Hash(MD5/SHA256)→ 唯一 ID\n□ 识别文件类型:EXE / DLL / SYS / ELF / Mach-O / .NET / 脚本(bat/ps1/vba) / JS / APK 等\n□ 非 PE/脚本/APK/驱动专项:见 §3.4 与 `references/nonpe-format-cookbook.md`(U–AV)\n□ file / DIE / 熵 / 壳特征(PEiD / DIE / Exeinfo 等)\n□ 架构:x86 / x64 / ARM;编译语言线索(VC++ / Delphi / .NET / Go / Rust)\n□ 加壳类型线索:UPX / ASPack / VMProtect / Themida / 未知混淆\n□ strings / rabin2 -z 捡漏\n□ MUST 导入/导出锚点(见下方「导入表硬门与等价路径」);若用户抢跑且有壳 → 先走 §0.5\n□ 产出:E-triage(MUST 含 imports 或等价锚点分类摘要,含 quality 标注如适用)+ 假设清单\n```\n\n**阶段门闩(Triage → Static/Dynamic)**:E-triage 中未记录 imports **或** 合法等价锚点摘要前,MUST NOT 进入 Dynamic(除非已记录 IAT 修复失败并选择动态旁路,见 §1.2),也 MUST NOT 声称「基础分诊完成」。解析失败时仍 MUST 把失败输出写入 Evidence,不得跳过。用户要求「重做导入表检查」时 MUST 重做 imports/等价步骤本身(或先完成 §0.5 协商后的前提),禁止改换其他分析步骤冒充。\n\n### 1.1 导入表硬门与等价路径\n\n| 样本类型 | MUST 锚点(Evidence) | 说明 |\n|----------|----------------------|------|\n| 原生 PE/ELF/Mach-O(IAT 可读) | `E-imports` / `E-triage-imports`:导入分类摘要 | `rabin2 -i` / IDA imports / 等价 |\n| DLL / SYS / 共享库 | **并列** `E-imports` + `E-exports`(`rabin2 -i` + `rabin2 -E`) | 导出表优先级等同导入表(对外入口) |\n| .NET 托管(无传统 IAT) | **等价路径**:dnSpy/IL/元数据/程序集引用与敏感 API 摘要 → 仍写入 `E-imports` 或 `E-triage-imports` 语义槽 | **禁止** 因「没有 IAT」而空过硬门;dnSpy 查看 = 原生「查导入表」 |\n| 导入表解析失败 / 为空 / 加壳花表 | 仍记失败或花表输出为 Evidence,并标 `quality` | 不得静默跳过;花表不得支撑能力否定结论 |\n\n**干净导入表警告(MUST 提醒)**:若导入表「过干净」(仅 kernel32/ntdll 等基础 DLL、几乎无业务 API),高度怀疑 `LoadLibrary` + `GetProcAddress` 动态加载 → 在 Evidence 注明嫌疑,并 **SHOULD** 转入 Dynamic 抓取内存 API;不得仅凭静态 IAT 宣称「无网络/无文件能力」。\n\n**高危 API 组合(补丁 8 · SHOULD)**:导入表过长时,优先输出**恶意组合聚类**,过滤纯系统基础调用。示例(非穷尽):\n\n- 高危簇:`FindWindowA/W` + `WriteProcessMemory` + `CreateRemoteThread`(注入)\n- 高危簇:`CryptEncrypt` / `CryptAcquireContext` + 大量 `FindFirstFile` / `DeleteFile`(勒索倾向)\n- 高危簇:`InternetOpen` / `WinHttp` / `URLDownloadToFile` + 持久化 API(`RegSetValue` / `CreateService`)\n- 单独 `CreateFile` / `ReadFile` 等多为良性噪声,除非与上簇共现\n\n### 1.2 脱壳与 IAT 处理(高风险分岔 · Issue #65)\n\n```text\n分支 A:无壳 / .NET 托管\n → 直接进入 §2 Static(.NET 走等价锚点)\n\n分支 B:有壳 / 强混淆\n Step 1:尝试脱壳(自动脱壳机 / 手动找 OEP)— 须在授权与隔离环境\n Step 2:尝试修复 IAT\n 工具:x86 → ImportREC(或等价);x64 → Scylla(或等价)。禁止 64 位样本死磕 ImportREC。\n 情况 B1:修复成功且可解析 → 记 E-imports(修复后)→ §2 Static\n 情况 B2:ImportREC/Scylla 报错、修复后无法运行、或 IAT 全乱码(VMP/加密壳)\n → 【IAT 修复铁律】立即终止继续静态 IAT 修复\n → MUST 记录 E-iat-repair-fail(命令、工具、失败现象、决定转动态)\n → 直接进入 §3 Dynamic:API 断点 / 硬件执行断点 / 内存搜索抓取导入\n → 这不算「跳过导入表」:导入表路径已尝试并记 Evidence\n 情况 B3(补丁 6):脱壳并修 IAT 后双击闪退 / 蓝屏(疑文件 CRC/大小自校验)\n → 放弃继续静态修文件;记 E-self-check-crash 或并入 E-iat-repair-fail\n → 转入 §3 Dynamic:对 CreateFile / GetFileSize / 哈希相关 API 下断,定位校验绕过点\n```\n\n**IAT 修复铁律(MUST)**:优先尝试自动/半自动修复;一旦修复工具报错或修复后程序无法运行,**立即停止**在静态导入表上死磕,切换动态调试,用 API 断点(如 `bp CreateFile` / 关键网络 API)在运行时捕获导入函数。\n\n## 2. Static(基础静态锚点 → 深挖)\n\n| 工具 | 何时 |\n|------|------|\n| radare2 / rabin2 | 快速函数/导入/字符串(imports 已在 Triage MUST 完成或已记失败旁路) |\n| IDA / Ghidra(MCP 或 headless) | 深挖、交叉引用、类型;survey 阶段复核 imports 分类 |\n| jadx / dnSpy | Android / .NET |\n| OLLVM 文档 | 控制流平坦化怀疑 |\n\n```text\n□ 确认 E-imports / E-triage 已含导入表或等价锚点 Evidence(缺失则先补,禁止后置)\n□ 若 DLL/SYS:确认 E-exports 已记录\n□ 敏感 API 分组 + 高危组合聚类(补丁 8)\n□ 硬编码域名/IP/URL 字符串;资源节是否藏 Payload\n□ 定位关键函数(加密/校验/网络/授权)→ 地址/符号写入 Evidence\n□ 一条路不通 → 换工具(IDA↔r2↔Ghidra)\n□ 时间盒(补丁 9 · SHOULD 默认):静态深挖约 15 分钟仍无关键路径 → 强制转入 §3 Dynamic(用户/任务可覆盖时长)\n```\n\n**无 MCP 时**:可用导出反编译文本再分析(对照 P4nda0s reverse-skills / IDA-NO-MCP 思路),仍写 Evidence 路径。\n\n## 3. Dynamic(交叉验证循环区)\n\n核心理念:**静态提供线索 → 动态验证 → 验证卡壳 → 回静态重审**(无固定唯一顺序)。\n\n### 3.0 断点起手式(补丁 7 + 10 · MUST 顺序)\n\n在用户态调试器(x64dbg 等)启动样本前,按「四级火箭」预置断点(可因架构/工具略名不同,顺序不变):\n\n1. **TLS 回调**断点(调试器 EP 之前可能已跑)\n2. **入口点 EP** 断点\n3. **敏感 API** 断点(如 `CreateRemoteThread` / 网络 / 文件写)\n4. **保底**:`ExitProcess` / 进程退出路径断点(补丁 10)— 一旦因反调试直接退出,**不急着重启**;立即 dump memory,将崩溃前镜像路径写入 Evidence,供字符串/数据恢复\n\n```text\n□ Frida / x64dbg / gdb / emulator:验证静态假设\n□ 按 §3.0 预置断点后再跑;单步跟踪栈/寄存器(白盒)\n□ 行为监控:沙箱 / Procmon / RegShot(黑盒)\n□ IAT 修复失败 / 自校验闪退样本:硬件执行断点或内存搜索强行捕捉 API;CreateFile/GetFileSize 查 CRC\n□ 反调试/反 Frida → reverse-engineering/anti-analysis\n□ Android:root 检测 / SSL pinning 绕过脚本按需生成,**须在授权设备**\n□ 崩溃日志驱动下一轮 hook(自适应循环)\n□ 时间盒(补丁 9 · SHOULD 默认):单步跟踪约 200 条指令仍无恶意行为线索 → 强制回静态搜字符串/换锚点(可覆盖)\n```\n\n### 3.1 沙箱 / 动态无行为应急分支(MUST)\n\n```text\n无行为或立刻退出 / 无限休眠\n → 检查反调试 / 反虚拟机例程(CPUID、高精度计时、沙箱特征等)\n → 尝试硬件断点绕过、修补检测点、或换物理机/更高保真环境\n → 将「无行为 + 疑似 anti-VM」写入 Evidence,禁止写成「样本无害」而不加条件\n```\n\n### 3.2 时间盒策略(补丁 9 · SHOULD)\n\n| 阶段 | 默认阈值(可被用户/任务覆盖) | 动作 |\n|------|------------------------------|------|\n| Static 深挖无关键路径 | ~15 分钟 | 转入 Dynamic |\n| Dynamic 单步无进展 | ~200 条指令 | 回 Static 字符串/交叉引用重锚 |\n| 任一路径重复失败 | 记 Evidence 后换工具或旁路 | 禁止同一失败手法空转 |\n\n\n### 3.3 反调试 / 混淆旁路速查(Issue #65 补丁 A–T · 高频)\n\n完整索引与动作细节见 `reverse-engineering/anti-analysis.md`「Agent 响应菜谱 A–T」。此处只列 **P0 必查 + 常见转场**。默认 **授权隔离 lab**;patch/改标志位不是未授权生产动作。\n\n| 触发特征 | 首选动作(摘要) | Evidence |\n|----------|------------------|----------|\n| `cpuid` 后 jz/jnz(A) | lab:改标志位或 patch 走真实分支;记检测点地址 | `E-anti-debug-cpuid` |\n| `rdtsc` + sub/cmp(B) | bp rdtsc 或 hook 时间源;禁止无限空转等沙箱超时当「无害」 | `E-anti-debug-rdtsc` |\n| PEB BeingDebugged / NtGlobalFlag(K) | ScyllaHide 或手改 PEB;patch 条件跳 | `E-anti-debug-peb` |\n| `NtQueryInformationProcess` DebugPort/Flags/Object(P) | ScyllaHide / hook 返回值;记 class 参数 | `E-anti-debug-ntqip` |\n| 导入极少但行为丰富 → API 哈希(N) | bp GetProcAddress;哈希反查回注 IDA | `E-api-hash` |\n| strings 空但有网/文件行为 → 串加密(I) | 找 decode 例程 xref;解密后 dump 回注 | `E-string-decrypt` |\n| 有签名但来源可疑(F) | SigCheck:有效/吊销/时间;**无效不降**威胁等级 | `E-sig-forge` |\n| 标准 strings 无 IOC → 试宽字符(T) | `strings -el` / UTF-16LE;Alt+A unicode | `E-wide-strings` |\n| 调试器名字符串 / Toolhelp 扫描(C) | bp CreateToolhelp32Snapshot 链 | `E-anti-debug-procscan` |\n| AddVectoredExceptionHandler + 故意异常(D) | bp VEH 注册;分析 handler | `E-anti-debug-veh` |\n| int3 / DR0–DR7(M) | patch int3;软断点或 ScyllaHide 藏硬件 BP | `E-anti-debug-bp` |\n| 多 PE 头/重叠节(G) | 节表真实映射 + 熵;不信节名 | `E-pe-anomaly` |\n| 文件尾 > 节总和 Overlay(J) | 提取 overlay;file/熵;找加载偏移 xref | `E-overlay` |\n| .rsrc 异常大/高熵 RT_RCDATA(Q) | 提取资源;FindResource 链 + 解密 dump | `E-rsrc-payload` |\n| 运行时才加载 DLL(R) | 查 Delay Import;bp delay-load helper | `E-delay-import` |\n| while+switch 星形 CFG(H) | **See** `ollvm-deobfuscation.md`;插件失败则动态路径 | `E-cff` |\n| 恒真/恒假分支(S) | **See** ollvm / 符号执行;动态为准 | `E-opaque-pred` |\n| `/proc/self/status` TracerPid(L) | **Linux/ELF**;hook 或 patch;Windows 主路径不强制 | `E-anti-debug-tracerpid` |\n\n**约束**:绕过失败也记 Evidence;禁止把「反调试触发退出」写成「样本无害」。完整 A–T 与 P2(E 编译时间、O 花指令)见 anti-analysis 菜谱节。\n\n### 3.4 非 PE / 多格式旁路(Issue #65 补丁 U–AV · 路由)\n\n完整索引:`reverse-engineering/references/nonpe-format-cookbook.md`。此处只列 **类型 → 入口**;动作细节在 cookbook / 对应 skill。\n\n| 类型 | 跳转 | P0 Evidence 锚点(示例) |\n|------|------|---------------------------|\n| BAT/CMD | cookbook §1 + malware | `E-batch-deobf` |\n| PowerShell | cookbook §2 + malware | `E-ps-decode-layer-N` |\n| VBA 宏 | cookbook §3 + malware | `E-vba-pcode` |\n| JS 强混淆 / JSVMP | **js-reverse** + cookbook §4 | `E-js-vmp` / `E-js-deobf` |\n| SYS 驱动 | kernel-driver-reverse + cookbook §5 | `E-driver-irp-handlers` / `E-driver-ioctl` |\n| DLL 侧重点 | cookbook §6(AM≡A–T **R**) | `E-dll-tls-dllmain` / `E-exports` |\n| Android 格机/隐藏图标 | **apk-reverse** + cookbook §7–8 | `E-android-wiper-*` / `E-android-hidden-icon-*` |\n\n**约束**:不另起「非 PE 六阶段」;与 §3.3 A–T 分工(PE 反调试 vs 多格式)。授权 lab;格机/BYOVD/反射 = 检测取证表述。\n\n\n## 4. Synthesis(IOC / 攻击链 / 报告)\n\n### Decision quality overlay (Issue #77)\n\nBefore closing Synthesis, apply [analysis-decision-framework.md](../../ops/analysis-decision-framework.md) **P0 checklist**: R41 grounded claims, R4* validated sufficiency, R1 confidence->dynamic, R2 hypothesis exit, R43 deadlock replan (under feasibility gate), R8/R23 no default malice/IOC. Multi-module -> R50; anti-analysis effort -> R51 + A-T cookbook.\n\nBlindspots (Rust/Go/VMP/injection/OLE/PDF/agent-meta): [analysis-blindspot-cookbook.md](../../ops/analysis-blindspot-cookbook.md) R52-R81 — detection-oriented; not a parallel master flow.\n\n\n\n```text\n□ Finding:算法/校验逻辑/可利用点 / 行为结论\n□ Path:callflow 或 solve 步骤挂 E-*\n□ IOC:网络指纹 + 主机指纹(有则表;无则 n/a+原因)\n□ 报告 docs-generator(malware/apt/null/vuln overlay 按任务选型)+ 可选图\n□ 可选:YARA / Snort·Suricata 规则化沉淀\n□ field-journal 脱敏\n```\n\n## 5. 六阶段实战映射(Issue #65 思维导图 → 本文件)\n\n| 实战阶段 | 本文件章节 | 硬门 / 铁律 |\n|----------|------------|-------------|\n| 1 初步快速研判 | §0–§1 Triage | Hash、架构、文件类型、查壳;imports/等价锚点;§0.5 指令门闩 |\n| 2 脱壳与 IAT | §1.2 | IAT 铁律;失败/自校验闪退 → Evidence → Dynamic |\n| 3 基础静态锚点 | §2 Static | 高危 API 组合;时间盒 SHOULD |\n| 4 深度交叉验证 | §3 Dynamic | 断点四级火箭;无行为应急;时间盒;§3.3 A–T;§3.4 U–AV 类型路由 |\n| 5 提取 IoC 与攻击链 | §4 Synthesis | IOC + Kill Chain / Path |\n| 6 归档与规则化 | §4 + docs-generator / YARA | 结构化报告;规则可选 |\n\n## 6. 与「堆 RE skill 插件」的差异\n\n- 本包用 **阶段门闩 + tool-index**,不默认启用 Hex-Rays「unsafe 全自动执行」类插件 \n- 动态插桩默认 **offline/lab** network_profile \n- IAT/导入表:**尝试 + 记录** 优先于「无限静态死磕」或「静默跳过」 \n- 用户指令:**目标优先 + 前提协商**,禁止用无关步骤冒充被点名步骤","content_type":"text/markdown; charset=utf-8","language":"markdown","size":16942,"content_sha256":"b94ab671a3950b9256996e15255a4eb60b8da1d202948511248615c5d4114b7b"},{"filename":"tools-advanced.md","content":"# CTF Reverse - Advanced Tools & Deobfuscation\n\nAdvanced tooling for commercial packers/protectors, binary diffing, deobfuscation frameworks, emulation, and symbolic execution beyond angr.\n\n## Table of Contents\n- [VMProtect Analysis](#vmprotect-analysis)\n - [Recognition](#recognition)\n - [Approach](#approach)\n - [Tools](#tools)\n - [CTF Strategy](#ctf-strategy)\n- [Themida / WinLicense Analysis](#themida--winlicense-analysis)\n - [Themida Recognition](#themida-recognition)\n - [Approach for CTF](#approach-for-ctf)\n- [Binary Diffing](#binary-diffing)\n - [BinDiff](#bindiff)\n - [Diaphora](#diaphora)\n- [Deobfuscation Frameworks](#deobfuscation-frameworks)\n - [D-810 (IDA)](#d-810-ida)\n - [GOOMBA (Ghidra)](#goomba-ghidra)\n - [Miasm](#miasm)\n- [Qiling Framework (Emulation)](#qiling-framework-emulation)\n- [Triton (Dynamic Symbolic Execution)](#triton-dynamic-symbolic-execution)\n- [Manticore (Symbolic Execution)](#manticore-symbolic-execution)\n- [Rizin / Cutter](#rizin--cutter)\n- [RetDec (Retargetable Decompiler)](#retdec-retargetable-decompiler)\n- [Custom VM Bytecode Lifting to LLVM IR (Google CTF 2017)](#custom-vm-bytecode-lifting-to-llvm-ir-google-ctf-2017)\n- [Advanced GDB Techniques](#advanced-gdb-techniques)\n - [Python Scripting](#python-scripting)\n - [Brute-Force with GDB Script](#brute-force-with-gdb-script)\n - [Conditional Breakpoints](#conditional-breakpoints)\n - [Watchpoints](#watchpoints)\n - [Reverse Debugging (rr)](#reverse-debugging-rr)\n - [GDB Dashboard / GEF / pwndbg](#gdb-dashboard--gef--pwndbg)\n- [Advanced Ghidra Scripting](#advanced-ghidra-scripting)\n- [Patching Strategies](#patching-strategies)\n - [Binary Ninja Patching (Python API)](#binary-ninja-patching-python-api)\n - [LIEF (Library for Instrumenting Executable Formats)](#lief-library-for-instrumenting-executable-formats)\n- [GDB Constraint Extraction with ILP/LP Solver (BackdoorCTF 2017)](#gdb-constraint-extraction-with-ilplp-solver-backdoorctf-2017)\n- [GDB Position-Encoded Input with Zero Flag Monitoring (EKOPARTY 2017)](#gdb-position-encoded-input-with-zero-flag-monitoring-ekoparty-2017)\n- [LD_PRELOAD to Dump Execute-Only Binary (BackdoorCTF 2017)](#ld_preload-to-dump-execute-only-binary-backdoorctf-2017)\n\n---\n\n## VMProtect Analysis\n\nVMProtect virtualizes x86/x64 code into custom bytecode interpreted by a generated VM. One of the most challenging protectors in CTF.\n\n### Recognition\n\n```bash\n# VMProtect signatures\nstrings binary | grep -i \"vmp\\|vmprotect\"\n# PE sections: .vmp0, .vmp1 (VMProtect adds its own sections)\nreadelf -S binary | grep \".vmp\"\n# Large binary with entropy > 7.5 in certain sections\n```\n\n**Key indicators:**\n- `push` / `pop` heavy prologues (VM entry pushes all registers to stack)\n- Large switch-case dispatcher (the VM handler loop)\n- Anti-debug checks embedded in VM handlers\n- Mutation engine: same opcode has different handlers per build\n\n### Approach\n\n```text\n1. Identify VM entry points — look for pushad/pushaq-like sequences\n2. Find the handler table — large indirect jump (jmp [reg + offset])\n3. Trace handler execution — each handler ends with jump to next\n4. Identify handlers:\n - vAdd, vSub, vMul, vXor, vNot (arithmetic)\n - vPush, vPop (stack operations)\n - vLoad, vStore (memory access)\n - vJmp, vJcc (control flow)\n - vRet (VM exit — restores real registers)\n5. Build disassembler for VM bytecode\n6. Simplify / deobfuscate the lifted IL\n```\n\n### Tools\n\n- **VMPAttack** (IDA plugin): Automatically identifies VM handlers\n- **NoVmp**: Devirtualization via VTIL (open-source)\n- **VMProtect devirtualizer scripts**: Community IDA/Binary Ninja scripts\n- **Approach for CTF:** Often easier to trace specific operations (crypto, comparisons) than fully devirtualize\n\n### CTF Strategy\n\n```python\n# Trace VM execution dynamically to extract operations on flag\n# Hook VM handler dispatch to log opcode + operands\n\nimport frida\n\nscript = \"\"\"\nvar vm_dispatch = ptr('0x...'); // Address of handler table jump\nInterceptor.attach(vm_dispatch, {\n onEnter(args) {\n // Log handler index and stack state\n var handler_idx = this.context.rax; // or whichever register\n console.log('Handler:', handler_idx, 'RSP:', this.context.rsp);\n }\n});\n\"\"\"\n```\n\n**Key insight:** Full devirtualization is rarely needed for CTF. Focus on tracing what operations are performed on your input. Hook comparison/crypto functions called from within the VM.\n\n---\n\n## Themida / WinLicense Analysis\n\nSimilar to VMProtect but with additional anti-debug layers.\n\n### Themida Recognition\n- Sections: `.themida`, `.winlice`\n- Extremely heavy anti-debug (kernel-level checks, driver installation)\n- Code mutation + virtualization + packing combined\n\n### Approach for CTF\n1. **Dump unpacked code:** Let it run, dump process memory after unpacking\n2. **Bypass anti-debug:** ScyllaHide in x64dbg with Themida-specific preset\n3. **Fix imports:** Use Scylla plugin for IAT reconstruction\n4. **Focus on dumped code:** Once unpacked, analyze as normal binary\n\n```bash\n# x64dbg workflow for Themida:\n1. Load binary\n2. Enable ScyllaHide → Profile: Themida\n3. Run to OEP (Original Entry Point) — may need several attempts\n4. Dump with Scylla: OEP → IAT Autosearch → Get Imports → Dump\n5. Fix dump: Scylla → Fix Dump\n6. Analyze fixed dump in Ghidra/IDA\n```\n\n---\n\n## Binary Diffing\n\nCritical for patch analysis, 1-day exploit development, and CTF challenges that provide two versions of a binary.\n\n### BinDiff\n\n```bash\n# Export from IDA/Ghidra first, then diff\n# IDA: File → BinExport → Export as BinExport2\n# Ghidra: Use BinExport plugin\n\n# Command line diffing\nbindiff primary.BinExport secondary.BinExport\n# Opens in BinDiff GUI — shows matched/unmatched functions\n```\n\n**Key metrics:**\n- Similarity score (0.0-1.0) per function pair\n- Changed instructions highlighted\n- Unmatched functions = new/removed code\n\n### Diaphora\n\nFree, open-source alternative to BinDiff, runs as IDA plugin.\n\n```bash\n# In IDA:\n# File → Script file → diaphora.py\n# Export first binary, then open second and diff\n\n# Ghidra version: diaphora_ghidra.py\n```\n\n**Useful for CTF:** When challenge provides \"patched\" and \"original\" binaries, diff reveals the vulnerability or hidden functionality.\n\n---\n\n## Deobfuscation Frameworks\n\n> OLLVM 脱密的完整工作流、变种生态和社区工具调研见 [ollvm-deobfuscation.md](references/ollvm-deobfuscation.md)。\n\n### d810-ng (IDA) — 本地首选\n\nD-810 的现代维护版(Next Generation),集成 **Z3 SMT** 求解器,覆盖 OLLVM / Tigress / Hodur(PlugX) / Approov 多种变种。\n\n```text\nCapabilities:\n- MBA simplification (Z3-verified): (a ^ b) + 2*(a & b) → a + b\n- Opaque predicate removal (Pred0/PredFF/PredSetz/PredSetnz)\n- Constant folding (22 rules)\n- Control flow unflattening (多种 unflattener):\n * Unflattener → O-LLVM (switch/if-chain)\n * UnflattenerSwitchCase → Tigress (m_jtbl)\n * UnflattenerTigressIndirect → Tigress (m_ijmp)\n * HodurUnflattener → Hodur/PlugX (while(1) + jnz state)\n * BadWhileLoop → Approov (0xF6000–0xF6FFF 状态常量)\n- Hacker's Delight 位运算等价\n- PlugX (Hodur) 恶意软件专用 MBA 模式\n\nInstallation: clone → 复制到 IDA plugins 目录 → Ctrl-Shift-D 加载\nSource: https://github.com/w00tzenheimer/d810-ng\n```\n\n### obpo-plugin (IDA) — 效果最强,云插件\n\n基于 Hex-Rays **microcode** + 数据流跟踪 + 程序切片 + 混合执行(concolic)。社区公认效果最强之一。\n\n```text\n- 在 microcode 层优化反编译输出(不是改 ASM)\n- 支持 IDA 7.5-7.7 + Hex-Rays,多架构 (ARM/ARM64/x86/x64/PPC/MIPS)\n- 云插件:目标函数上传 obpo-server 处理(核心闭源,插件免费)\n- ⚠️ 敏感样本慎用(二进制上传云服务)\n- 用法:右键 dispatcher → OBPO → Mark and process function\nSource: https://github.com/obpo-project/obpo-plugin\n```\n\n### ollvm-unflattener — Miasm 纯脚本\n\n无 IDA 依赖,基于 Miasm 符号执行,BFS 多层处理,支持 x86/x64 Win/Linux。\n\n```bash\ngit clone https://github.com/cdong1012/ollvm-unflattener\npip install -r requirements.txt # miasm, graphviz, keystone-engine\npython unflattener -i \u003cinput> -o \u003coutput> -t \u003cfunc_addr> -a # -a 自动多层\n```\n\n### ollvm-breaker (Binary Ninja)\n\nBinary Ninja 去平坦化,仓库自带 Android 加固样本 `libvdog.so` 实战。Source: amimo/ollvm-breaker\n\n### DeObfBR — BR 混淆专项\n\n专门去除 Goron/Arkari 风格的 BR(间接分支)混淆。简易技巧:设置数据段只读可部分对抗。Source: Mrack/DeObfBR\n\n### deollvm — ARM64 Unicorn\n\n无 IDA 时处理 ARM64 .so 的备选,基于 Unicorn。Source: GeT1t/deollvm\n\n### GOOMBA (Ghidra)\n\n```text\nGOOMBA (Ghidra-based Obfuscated Object Matching and Bytes Analysis):\n- Integrates with Ghidra's P-Code\n- Simplifies MBA expressions\n- Pattern matching for known obfuscation\n\nInstallation: Copy .jar to Ghidra extensions\nUsage: Code Browser → Analysis → GOOMBA\n```\n\n### Miasm\n\nPowerful reverse engineering framework with symbolic execution and IR lifting.\n\n```python\nfrom miasm.analysis.binary import Container\nfrom miasm.analysis.machine import Machine\nfrom miasm.expression.expression import *\n\n# Load binary and lift to Miasm IR\ncont = Container.from_stream(open(\"binary\", \"rb\"))\nmachine = Machine(cont.arch)\nmdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db)\n\n# Disassemble function\nasmcfg = mdis.dis_multiblock(entry_addr)\n\n# Lift to IR\nlifter = machine.lifter_model_call(loc_db=cont.loc_db)\nircfg = lifter.new_ircfg_from_asmcfg(asmcfg)\n\n# Symbolic execution\nfrom miasm.ir.symbexec import SymbolicExecutionEngine\nsb = SymbolicExecutionEngine(lifter)\n# Execute symbolically, then simplify expressions\n```\n\n**Use case:** Deobfuscate expression trees, simplify complex arithmetic, trace data flow through obfuscated code.\n\n---\n\n## Qiling Framework (Emulation)\n\nCross-platform emulation framework built on Unicorn, with OS-level support (syscalls, filesystem, registry).\n\n```python\nfrom qiling import Qiling\nfrom qiling.const import QL_VERBOSE\n\n# Emulate Linux ELF\nql = Qiling([\"./binary\"], \"rootfs/x8664_linux\",\n verbose=QL_VERBOSE.DEBUG)\n\n# Hook specific address\[email protected]_address\ndef hook_check(ql, address, size):\n if address == 0x401234:\n ql.arch.regs.rax = 0 # Bypass check\n ql.log.info(\"Anti-debug bypassed\")\n\n# Hook syscall\[email protected]_syscall(name=\"ptrace\")\ndef hook_ptrace(ql, request, pid, addr, data):\n return 0 # Always succeed\n\n# Hook API (Windows)\[email protected]_api(\"IsDebuggerPresent\", target=ql.os.user_defined_api)\ndef hook_isdebug(ql, address, params):\n return 0\n\nql.run()\n```\n\n**Advantages over Unicorn:**\n- OS emulation (file I/O, network, registry)\n- Multi-platform (Linux, Windows, macOS, Android, UEFI)\n- Built-in debugger interface\n- Rootfs for library loading\n\n**CTF use cases:**\n- Emulate binaries for foreign architectures (ARM, MIPS, RISC-V)\n- Bypass all anti-debug at once (no debugger artifacts)\n- Fuzz embedded/IoT firmware without hardware\n- Trace execution without code modification\n\n---\n\n## Triton (Dynamic Symbolic Execution)\n\nPin-based dynamic binary analysis framework with symbolic execution, taint analysis, and AST simplification.\n\n```python\nfrom triton import *\n\nctx = TritonContext(ARCH.X86_64)\n\n# Load binary sections\nwith open(\"binary\", \"rb\") as f:\n binary = f.read()\nctx.setConcreteMemoryAreaValue(0x400000, binary)\n\n# Symbolize input\nfor i in range(32):\n ctx.symbolizeMemory(MemoryAccess(INPUT_ADDR + i, CPUSIZE.BYTE), f\"input_{i}\")\n\n# Emulate instructions\npc = ENTRY_POINT\nwhile pc:\n inst = Instruction(pc, ctx.getConcreteMemoryAreaValue(pc, 16))\n ctx.processing(inst)\n\n # At comparison point, extract path constraint\n if pc == CMP_ADDR:\n ast = ctx.getPathConstraintsAst()\n model = ctx.getModel(ast)\n for k, v in sorted(model.items()):\n print(f\"input[{k}] = {chr(v.getValue())}\", end=\"\")\n break\n\n pc = ctx.getConcreteRegisterValue(ctx.registers.rip)\n```\n\n**Triton vs angr:**\n| Feature | Triton | angr |\n|---|---|---|\n| Execution | Concrete + symbolic (DSE) | Fully symbolic |\n| Speed | Faster (concrete-driven) | Slower (explores all paths) |\n| Path explosion | Less prone (follows one path) | Major issue |\n| API | C++ / Python | Python |\n| Best for | Single-path deobfuscation, taint tracking | Multi-path exploration |\n\n**Key use:** Triton excels at deobfuscation — run the program concretely, but track symbolic state, then simplify the collected constraints.\n\n---\n\n## Manticore (Symbolic Execution)\n\nTrail of Bits' symbolic execution tool for native binaries. Its API is similar in spirit to angr.\n\n```python\nfrom manticore.native import Manticore\n\nm = Manticore(\"./binary\")\n\n# Hook success/failure\[email protected](0x401234)\ndef success(state):\n buf = state.solve_one_n_batched(state.input_symbols, 32)\n print(\"Flag:\", bytes(buf))\n m.kill()\n\[email protected](0x401256)\ndef fail(state):\n state.abandon()\n\nm.run()\n```\n\n**Best for:** simpler Linux binaries and embedded targets. angr is generally more mature for complex RE tasks.\n\n---\n\n## Rizin / Cutter\n\nRizin is the maintained fork of radare2. Cutter is its Qt-based GUI.\n\n```bash\n# Rizin CLI (r2-compatible commands)\nrizin -d ./binary\n> aaa # Analyze all\n> afl # List functions\n> pdf @ main # Print disassembly\n> VV # Visual graph mode\n\n# Cutter GUI\ncutter binary # Open in GUI with decompiler\n```\n\n**Cutter advantages:**\n- Built-in Ghidra decompiler (via r2ghidra plugin)\n- Graph view, hex editor, debug panel in one GUI\n- Integrated Python/JavaScript scripting console\n- Free and open source\n\n---\n\n## RetDec (Retargetable Decompiler)\n\nLLVM-based decompiler supporting many architectures. Free and open-source.\n\n```bash\n# Install\npip install retdec-decompiler\n# Or use web: https://retdec.com/decompilation/\n\n# CLI\nretdec-decompiler binary\n# Outputs: binary.c (decompiled C), binary.dsm (disassembly)\n\n# Specific function\nretdec-decompiler --select-ranges 0x401000-0x401100 binary\n```\n\n**Strengths:** Multi-arch support (x86, ARM, MIPS, PowerPC, PIC32), free, produces compilable C. Good for architectures not well-supported by Ghidra.\n\n---\n\n## Custom VM Bytecode Lifting to LLVM IR (Google CTF 2017)\n\nFor complex custom VMs, transpile the VM bytecode to LLVM IR and use LLVM's optimization passes to simplify the code, then decompile the optimized IR.\n\n```python\n# Pipeline: VM bytecode → custom disassembler → LLVM IR → optimize → decompile\n# 1. Write disassembler for the custom VM opcodes\n# 2. Emit LLVM IR for each opcode:\n# INC reg → %reg = add i32 %reg, 1\n# CDEC reg → conditional decrement\n# CALL fn → call void @fn()\n# 3. Use MCJIT or llc to optimize:\n# opt -O3 -S vm_lifted.ll -o vm_optimized.ll\n# 4. Load optimized IR in IDA or decompile with RetDec\n# Result: 1300 lines → 150 lines after inlining + constant folding\n```\n\n**Key insight:** LLVM's optimization passes (inlining, constant folding, dead code elimination) dramatically simplify lifted VM bytecode. A custom VM with 26 registers and 3 opcodes that produces 1300 lines of IL reduces to ~150 lines after `-O3`, revealing the underlying algorithm (e.g., Collatz sequence computation).\n\n---\n\n## Advanced GDB Techniques\n\n### Python Scripting\n\n```python\n# ~/.gdbinit or source from GDB\nimport gdb\n\nclass TraceCompare(gdb.Breakpoint):\n \"\"\"Log all comparison operations.\"\"\"\n def __init__(self, addr):\n super().__init__(f\"*{addr}\", gdb.BP_BREAKPOINT)\n\n def stop(self):\n frame = gdb.selected_frame()\n rdi = int(frame.read_register(\"rdi\"))\n rsi = int(frame.read_register(\"rsi\"))\n rdx = int(frame.read_register(\"rdx\"))\n # Read compared buffers\n inferior = gdb.selected_inferior()\n buf1 = inferior.read_memory(rdi, rdx).tobytes()\n buf2 = inferior.read_memory(rsi, rdx).tobytes()\n print(f\"memcmp({buf1!r}, {buf2!r}, {rdx})\")\n return False # Don't stop, just log\n\n# Usage in GDB:\n# (gdb) source trace_cmp.py\n# (gdb) python TraceCompare(0x401234)\n```\n\n### Brute-Force with GDB Script\n\n```python\n# Byte-by-byte brute force via GDB Python API\nimport gdb, string\n\ndef bruteforce_flag(check_addr, success_addr, fail_addr, flag_len):\n flag = []\n for pos in range(flag_len):\n for ch in string.printable:\n candidate = ''.join(flag) + ch + 'A' * (flag_len - pos - 1)\n gdb.execute('start', to_string=True)\n gdb.execute(f'b *{check_addr}', to_string=True)\n # Write candidate to stdin pipe\n # ... (setup input)\n gdb.execute('continue', to_string=True)\n rip = int(gdb.parse_and_eval('$rip'))\n if rip == success_addr:\n flag.append(ch)\n break\n gdb.execute('delete breakpoints', to_string=True)\n return ''.join(flag)\n```\n\n### Conditional Breakpoints\n\n```bash\n# Break only when register has specific value\n(gdb) b *0x401234 if $rax == 0x41\n(gdb) b *0x401234 if *(char*)$rdi == 'f'\n\n# Break on Nth hit\n(gdb) b *0x401234\n(gdb) ignore 1 99 # Skip first 99 hits, break on 100th\n\n# Log without stopping\n(gdb) b *0x401234\n(gdb) commands\n> silent\n> printf \"rax=%lx rdi=%lx\\n\", $rax, $rdi\n> continue\n> end\n```\n\n### Watchpoints\n\n```bash\n# Hardware watchpoint — break when memory changes\n(gdb) watch *(int*)0x601050 # Break on write to address\n(gdb) rwatch *(int*)0x601050 # Break on read\n(gdb) awatch *(int*)0x601050 # Break on read or write\n\n# Watch a variable by name (needs debug symbols)\n(gdb) watch flag_buffer[0]\n\n# Conditional watchpoint\n(gdb) watch *(int*)0x601050 if *(int*)0x601050 == 0x42\n```\n\n### Reverse Debugging (rr)\n\n```bash\n# Record execution\nrr record ./binary\n# Replay with reverse execution support\nrr replay\n\n# In rr replay (GDB commands plus):\n(gdb) reverse-continue # Run backward to previous breakpoint\n(gdb) reverse-stepi # Step backward one instruction\n(gdb) reverse-next # Reverse next\n(gdb) when # Show current event number\n\n# Set checkpoint and return to it\n(gdb) checkpoint\n(gdb) restart 1 # Return to checkpoint 1\n```\n\n**Key use:** When you step past the critical moment, reverse back instead of restarting. Invaluable for anti-debug that corrupts state.\n\n### GDB Dashboard / GEF / pwndbg\n\n```bash\n# pwndbg (most popular for CTF)\n# https://github.com/pwndbg/pwndbg\ngit clone https://github.com/pwndbg/pwndbg && cd pwndbg && ./setup.sh\n\n# Key pwndbg commands:\npwndbg> context # Show registers, stack, code, backtrace\npwndbg> vmmap # Memory map (like /proc/self/maps)\npwndbg> search -s \"flag{\" # Search memory for string\npwndbg> telescope $rsp 20 # Smart stack dump\npwndbg> cyclic 200 # Generate De Bruijn pattern\npwndbg> hexdump $rdi 64 # Pretty hex dump\npwndbg> got # Show GOT entries\npwndbg> plt # Show PLT entries\n\n# GEF (alternative)\n# https://github.com/hugsy/gef\nbash -c \"$(curl -fsSL https://gef.blah.cat/sh)\"\n\n# Key GEF commands:\ngef> xinfo $rdi # Detailed info about address\ngef> checksec # Binary security features\ngef> heap chunks # Heap chunk listing\ngef> pattern create 100 # De Bruijn pattern\n```\n\n---\n\n## Advanced Ghidra Scripting\n\n```python\n# Ghidra Python (Jython) — run via Script Manager or headless\n\n# Batch rename functions matching a pattern\nfrom ghidra.program.model.symbol import SourceType\nfm = currentProgram.getFunctionManager()\nfor func in fm.getFunctions(True):\n if func.getName().startswith(\"FUN_\"):\n # Check if function contains specific instruction pattern\n body = func.getBody()\n inst_iter = currentProgram.getListing().getInstructions(body, True)\n for inst in inst_iter:\n if inst.getMnemonicString() == \"CPUID\":\n func.setName(\"anti_vm_check_\" + hex(func.getEntryPoint().getOffset()),\n SourceType.USER_DEFINED)\n break\n\n# Extract all XOR constants from a function\ndef extract_xor_constants(func):\n \"\"\"Find all XOR operations and their immediate operands.\"\"\"\n constants = []\n body = func.getBody()\n inst_iter = currentProgram.getListing().getInstructions(body, True)\n for inst in inst_iter:\n if inst.getMnemonicString() == \"XOR\":\n for i in range(inst.getNumOperands()):\n op = inst.getOpObjects(i)\n if op and hasattr(op[0], 'getValue'):\n constants.append(int(op[0].getValue()))\n return constants\n\n# Bulk decompile and search for pattern\nfrom ghidra.app.decompiler import DecompInterface\ndecomp = DecompInterface()\ndecomp.openProgram(currentProgram)\n\nfor func in fm.getFunctions(True):\n result = decomp.decompileFunction(func, 30, monitor)\n if result.depiledFunction():\n code = result.getDecompiledFunction().getC()\n if \"strcmp\" in code or \"memcmp\" in code:\n print(f\"Comparison in {func.getName()} at {func.getEntryPoint()}\")\n```\n\n---\n\n## Patching Strategies\n\n### Binary Ninja Patching (Python API)\n\n```python\nimport binaryninja as bn\n\nbv = bn.open_view(\"binary\")\n\n# NOP out instruction\nbv.write(0x401234, b\"\\x90\" * 5) # 5-byte NOP\n\n# Patch conditional jump (JNZ → JZ)\nbv.write(0x401234, b\"\\x74\") # 0x75 (JNZ) → 0x74 (JZ)\n\n# Insert always-true (mov eax, 1; ret)\nbv.write(0x401234, b\"\\xb8\\x01\\x00\\x00\\x00\\xc3\")\n\nbv.save(\"patched\")\n```\n\n### LIEF (Library for Instrumenting Executable Formats)\n\n```python\nimport lief\n\n# Parse and modify ELF/PE/Mach-O\nbinary = lief.parse(\"binary\")\n\n# Add a new section\nsection = lief.ELF.Section(\".patch\")\nsection.content = list(b\"\\xcc\" * 0x100)\nsection.type = lief.ELF.SECTION_TYPES.PROGBITS\nsection.flags = lief.ELF.SECTION_FLAGS.EXECINSTR | lief.ELF.SECTION_FLAGS.ALLOC\nbinary.add(section)\n\n# Modify entry point\nbinary.header.entrypoint = 0x401000\n\n# Hook imported function\nbinary.patch_pltgot(\"strcmp\", 0x401000)\n\nbinary.write(\"patched\")\n```\n\n**LIEF advantages:** Cross-format (ELF, PE, Mach-O), Python API, can add sections/segments, modify headers, patch imports.\n\n---\n\n## GDB Constraint Extraction with ILP/LP Solver (BackdoorCTF 2017)\n\nWhen a binary enforces linear arithmetic relationships between input bytes, extract constraints automatically via GDB and solve with an ILP solver.\n\n**Technique:** Send position-encoded input (`input[i] = i`) so that when a comparison fires, you know exactly which positions are involved and what their sum/difference must equal. Collect all constraints from logged comparisons, then feed to PuLP or Gurobi.\n\n```python\nfrom pulp import *\n\nn = 32 # flag length\nprob = LpProblem(\"crackme\", LpMinimize)\nx = [LpVariable(f'x{i}', 32, 126, cat='Integer') for i in range(n)]\nprob += 0 # dummy objective\n\n# Constraints extracted via GDB automation (input[i]=i, monitor comparisons):\nprob += x[3] + x[7] == 0xAB\nprob += x[1] - x[5] == 0x0C\n# ... add all extracted constraints ...\n\n# Constrain to printable ASCII\nfor xi in x:\n prob += xi >= 32\n prob += xi \u003c= 126\n\nprob.solve(PULP_CBC_CMD(msg=0))\nflag = ''.join(chr(int(value(xi))) for xi in x)\nprint(\"Flag:\", flag)\n```\n\n**GDB automation to extract constraints:**\n```python\n# In GDB Python: set input[i]=i, run, log every CMP instruction result\nimport gdb\n\nclass CmpLogger(gdb.Breakpoint):\n def stop(self):\n frame = gdb.selected_frame()\n # Read compared values, map back to input indices via position encoding\n return False\n```\n\n**Key insight:** When a binary enforces linear arithmetic relationships between input bytes, ILP solvers directly find the satisfying assignment once constraints are extracted via GDB automation.\n\n**References:** BackdoorCTF 2017\n\n---\n\n## GDB Position-Encoded Input with Zero Flag Monitoring (EKOPARTY 2017)\n\nSend input where `input[i] = i` (position-encoded). Single-step through the binary monitoring the CPU zero flag (ZF). When ZF is set at a comparison involving a specific position's value, the comparison matched — log the expected value for that position.\n\n```python\nimport gdb\n\n# Script: single-step binary with position-encoded input, watch ZF\nclass ZFMonitor(gdb.Breakpoint):\n def stop(self):\n zf = (int(gdb.parse_and_eval('$eflags')) >> 6) & 1\n if zf:\n rip = int(gdb.parse_and_eval('$rip'))\n # Disassemble at rip to find the compared immediate\n disasm = gdb.execute(f'x/1i {rip-5}', to_string=True)\n print(f\"ZF set at {rip:#x}: {disasm.strip()}\")\n return False\n\n# Run once with input b'\\x00\\x01\\x02\\x03...\\x1f'\n# ZF fires when comparison matches the position's own value -> that IS the key byte\n```\n\nMaps each input byte to its required value in one pass without manual reversing.\n\n**Key insight:** Position-encoded input (`input[i]=i`) combined with zero flag monitoring reveals the full key/password in one pass — the zero flag fires when the expected value for position i equals i itself.\n\n**References:** EKOPARTY CTF 2017\n\n---\n\n## LD_PRELOAD to Dump Execute-Only Binary (BackdoorCTF 2017)\n\nA binary has execute-only permissions (mode `--x`, no read bit). The file cannot be read directly or with standard tools, but the kernel still maps it into memory on execution.\n\nLD_PRELOAD a shared library with a constructor that runs inside the process and reads its own memory via `/proc/self/mem`:\n\n```c\n// dump_xo.c — compile: gcc -shared -fPIC -o dump_xo.so dump_xo.c\n#include \u003cstdio.h>\n#include \u003cstdlib.h>\n#include \u003cstring.h>\n\n__attribute__((constructor)) void dump() {\n FILE *maps = fopen(\"/proc/self/maps\", \"r\");\n char line[256];\n unsigned long base = 0, end = 0;\n\n // Find the execute-only binary's mapping (r-xp or --xp)\n while (fgets(line, sizeof(line), maps)) {\n if (strstr(line, \"binary_name\")) {\n sscanf(line, \"%lx-%lx\", &base, &end);\n break;\n }\n }\n fclose(maps);\n\n FILE *mem = fopen(\"/proc/self/mem\", \"rb\");\n fseek(mem, base, SEEK_SET);\n size_t size = end - base;\n void *buf = malloc(size);\n fread(buf, 1, size, mem);\n fclose(mem);\n\n FILE *out = fopen(\"/tmp/dumped_binary\", \"wb\");\n fwrite(buf, 1, size, out);\n fclose(out);\n}\n// Usage: LD_PRELOAD=./dump_xo.so ./binary_xo\n```\n\n**Key insight:** Execute-only prevents file reading but not execution. LD_PRELOAD constructors run inside the process where `/proc/self/mem` provides access to mapped memory regardless of file permissions.\n\n**References:** BackdoorCTF 2017\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":26514,"content_sha256":"948f9a19fda1b922ddf526b74ffca50c441aca5b0c1dd777fab9c70f6f42e770"},{"filename":"tools-dynamic.md","content":"# CTF Reverse - Dynamic Analysis Tools\n\n## Table of Contents\n- [Frida (Dynamic Instrumentation)](#frida-dynamic-instrumentation)\n - [Installation](#installation)\n - [Basic Function Hooking](#basic-function-hooking)\n - [Anti-Debug Bypass](#anti-debug-bypass)\n - [Memory Scanning and Patching](#memory-scanning-and-patching)\n - [Function Replacement](#function-replacement)\n - [Tracing and Stalker](#tracing-and-stalker)\n - [r2frida (Radare2 + Frida Integration)](#r2frida-radare2--frida-integration)\n - [Frida for Android/iOS](#frida-for-androidios)\n - [Frida Memoization for Recursive Function Speedup (hxp CTF 2017)](#frida-memoization-for-recursive-function-speedup-hxp-ctf-2017)\n- [angr (Symbolic Execution)](#angr-symbolic-execution)\n - [angr Installation](#angr-installation)\n - [Basic Path Exploration](#basic-path-exploration)\n - [Symbolic Input with Constraints](#symbolic-input-with-constraints)\n - [Hook Functions to Simplify Analysis](#hook-functions-to-simplify-analysis)\n - [Exploring from Specific Address](#exploring-from-specific-address)\n - [Common Patterns and Tips](#common-patterns-and-tips)\n - [Dealing with Path Explosion](#dealing-with-path-explosion)\n - [angr CFG Recovery](#angr-cfg-recovery)\n- [lldb (LLVM Debugger)](#lldb-llvm-debugger)\n - [Basic Commands](#basic-commands)\n - [Scripting (Python)](#scripting-python)\n- [x64dbg (Windows Debugger)](#x64dbg-windows-debugger)\n - [Key Features](#key-features)\n - [Scripting](#scripting)\n - [Common CTF Workflow](#common-ctf-workflow)\n- [Qiling Framework (Cross-Platform Emulation)](#qiling-framework-cross-platform-emulation)\n - [Qiling Installation](#qiling-installation)\n - [Basic Usage](#basic-usage)\n - [Anti-Debug Bypass via Emulation](#anti-debug-bypass-via-emulation)\n - [Input Fuzzing with Qiling](#input-fuzzing-with-qiling)\n- [Triton (Dynamic Symbolic Execution)](#triton-dynamic-symbolic-execution)\n- [Intel Pin Instruction-Counting Side Channel (Hackover CTF 2015)](#intel-pin-instruction-counting-side-channel-hackover-ctf-2015)\n- [Intel Pin Instruction Counting with Genetic Algorithm (hxp CTF 2017)](#intel-pin-instruction-counting-with-genetic-algorithm-hxp-ctf-2017)\n- [Opcode-Only Trace Reconstruction (0CTF 2016)](#opcode-only-trace-reconstruction-0ctf-2016)\n- [LD_PRELOAD time() Freeze for Deterministic Analysis (EKOPARTY 2017)](#ld_preload-time-freeze-for-deterministic-analysis-ekoparty-2017)\n- [LD_PRELOAD memcmp Side-Channel for Byte-by-Byte Bruteforce (Blaze CTF 2018)](#ld_preload-memcmp-side-channel-for-byte-by-byte-bruteforce-blaze-ctf-2018)\n\n---\n\n## Frida (Dynamic Instrumentation)\n\nFrida injects JavaScript into running processes for real-time hooking, tracing, and modification. Essential for anti-debug bypass, runtime inspection, and mobile RE.\n\n### Installation\n\n```bash\npip install frida-tools frida\n# Verify\nfrida --version\n```\n\n### Basic Function Hooking\n\n```javascript\n// hook.js — intercept a function and log arguments/return value\nInterceptor.attach(Module.findExportByName(null, \"strcmp\"), {\n onEnter: function(args) {\n this.arg0 = Memory.readUtf8String(args[0]);\n this.arg1 = Memory.readUtf8String(args[1]);\n console.log(`strcmp(\"${this.arg0}\", \"${this.arg1}\")`);\n },\n onLeave: function(retval) {\n console.log(` → ${retval}`);\n }\n});\n```\n\n```bash\n# Attach to running process\nfrida -p $(pidof binary) -l hook.js\n\n# Spawn and instrument from start\nfrida -f ./binary -l hook.js --no-pause\n\n# One-liner: hook strcmp and dump comparisons\nfrida -f ./binary --no-pause -e '\nInterceptor.attach(Module.findExportByName(null, \"strcmp\"), {\n onEnter(args) {\n console.log(\"strcmp:\", Memory.readUtf8String(args[0]), Memory.readUtf8String(args[1]));\n }\n});\n'\n```\n\n### Anti-Debug Bypass\n\n```javascript\n// Bypass ptrace(PTRACE_TRACEME) — returns 0 (success) without calling\nInterceptor.attach(Module.findExportByName(null, \"ptrace\"), {\n onEnter: function(args) {\n this.request = args[0].toInt32();\n },\n onLeave: function(retval) {\n if (this.request === 0) { // PTRACE_TRACEME\n retval.replace(ptr(0));\n console.log(\"[*] ptrace(TRACEME) bypassed\");\n }\n }\n});\n\n// Bypass IsDebuggerPresent (Windows)\nvar isDbg = Module.findExportByName(\"kernel32.dll\", \"IsDebuggerPresent\");\nInterceptor.attach(isDbg, {\n onLeave: function(retval) {\n retval.replace(ptr(0));\n }\n});\n\n// Bypass timing checks — hook clock_gettime to return constant\nInterceptor.attach(Module.findExportByName(null, \"clock_gettime\"), {\n onLeave: function(retval) {\n // Force constant timestamp to defeat timing checks\n var ts = this.context.rsi || this.context.x1; // x86 or ARM\n Memory.writeU64(ts, 0); // tv_sec\n Memory.writeU64(ts.add(8), 0); // tv_nsec\n }\n});\n```\n\n### Memory Scanning and Patching\n\n```javascript\n// Scan for flag pattern in memory\nProcess.enumerateRanges('r--').forEach(function(range) {\n Memory.scan(range.base, range.size, \"66 6c 61 67 7b\", { // \"flag{\"\n onMatch: function(address, size) {\n console.log(\"[FLAG] Found at:\", address, Memory.readUtf8String(address, 64));\n },\n onComplete: function() {}\n });\n});\n\n// Patch instruction (NOP out a check)\nvar addr = Module.findBaseAddress(\"binary\").add(0x1234);\nMemory.patchCode(addr, 2, function(code) {\n var writer = new X86Writer(code, { pc: addr });\n writer.putNop();\n writer.putNop();\n writer.flush();\n});\n```\n\n### Function Replacement\n\n```javascript\n// Replace a validation function to always return true\nvar checkFlag = Module.findExportByName(null, \"check_flag\");\nInterceptor.replace(checkFlag, new NativeCallback(function(input) {\n console.log(\"[*] check_flag called with:\", Memory.readUtf8String(input));\n return 1; // always valid\n}, 'int', ['pointer']));\n```\n\n### Tracing and Stalker\n\n```javascript\n// Trace all calls in a function (Stalker — instruction-level tracing)\nvar targetAddr = Module.findExportByName(null, \"main\");\nStalker.follow(Process.getCurrentThreadId(), {\n transform: function(iterator) {\n var instruction;\n while ((instruction = iterator.next()) !== null) {\n if (instruction.mnemonic === \"call\") {\n iterator.putCallout(function(context) {\n console.log(\"CALL at\", context.pc, \"→\", ptr(context.pc).readPointer());\n });\n }\n iterator.keep();\n }\n }\n});\n```\n\n### r2frida (Radare2 + Frida Integration)\n\n```bash\n# Attach radare2 to process via Frida\nr2 frida://spawn/./binary\n\n# r2frida commands\n\\ii # List imports\n\\il # List loaded modules\n\\dt strcmp # Trace strcmp calls\n\\dc # Continue execution\n\\dm # List memory maps\n```\n\n### Frida for Android/iOS\n\n```bash\n# Android (requires rooted device or Frida server)\nadb push frida-server /data/local/tmp/\nadb shell \"chmod 755 /data/local/tmp/frida-server && /data/local/tmp/frida-server &\"\n\n# Hook Android Java methods\nfrida -U -f com.example.app -l hook_android.js --no-pause\n```\n\n```javascript\n// hook_android.js — hook Java method\nJava.perform(function() {\n var MainActivity = Java.use(\"com.example.app.MainActivity\");\n MainActivity.checkPassword.implementation = function(input) {\n console.log(\"[*] checkPassword called with:\", input);\n var result = this.checkPassword(input);\n console.log(\"[*] Result:\", result);\n return result;\n };\n});\n```\n\n**Key insight:** Frida excels where static analysis fails — obfuscated code, packed binaries, and runtime-generated data. Hook comparison functions (`strcmp`, `memcmp`, custom validators) to extract expected values without reversing the algorithm. Use `Interceptor.attach` for observation, `Interceptor.replace` for modification.\n\n**When to use:** Anti-debugging bypass, extracting runtime-computed keys, hooking crypto functions to dump plaintext, mobile app analysis, packed binary inspection.\n\n### Frida Memoization for Recursive Function Speedup (hxp CTF 2017)\n\nHook a recursive function with Frida, memoize results, and replay cached values to skip redundant computation. Fibonacci-like recursive challenges with exponential complexity become instant with memoization.\n\n```javascript\n// memo_hook.js — memoize a recursive function to skip redundant calls\nvar memo = {};\nvar funcAddr = ptr(\"0x400abc\"); // Address of the recursive function\nvar retAddr = ptr(\"0x400def\"); // Address of the function's ret instruction\n\nInterceptor.attach(funcAddr, {\n onEnter: function(args) {\n this.key = args[0].toInt32();\n if (memo[this.key] !== undefined) {\n // Skip computation entirely: set return value and jump to ret\n this.context.rax = memo[this.key];\n this.context.rip = retAddr;\n }\n },\n onLeave: function(retval) {\n // Cache the result for future calls with the same argument\n memo[this.key] = retval.toInt32();\n }\n});\n```\n\n```bash\n# Usage\nfrida -f ./binary -l memo_hook.js --no-pause\n```\n\nFor multi-argument functions, build a composite key:\n```javascript\nInterceptor.attach(funcAddr, {\n onEnter: function(args) {\n this.key = args[0].toInt32() + \",\" + args[1].toInt32();\n if (memo[this.key] !== undefined) {\n this.context.rax = memo[this.key];\n this.context.rip = retAddr;\n }\n },\n onLeave: function(retval) {\n memo[this.key] = retval.toInt32();\n }\n});\n```\n\n**Key insight:** Frida's `Interceptor` can both read and modify register state, allowing you to skip function execution entirely by setting `rax` (return value) and `rip` (to the `ret` instruction). This works on any recursive function where the same arguments produce the same result. Exponential-time recursive computations (Fibonacci, Ackermann, tree traversals) become linear with memoization.\n\n**References:** hxp CTF 2017\n\n---\n\n## angr (Symbolic Execution)\n\nangr automatically explores program paths to find inputs satisfying constraints. Solves many flag-checking binaries in minutes that take hours manually.\n\n### angr Installation\n\n```bash\npip install angr\n```\n\n### Basic Path Exploration\n\n```python\nimport angr\nimport claripy\n\n# Load binary\nproj = angr.Project('./binary', auto_load_libs=False)\n\n# Find address of \"Correct!\" print, avoid \"Wrong!\" print\n# Get these from disassembly (objdump -d or Ghidra)\nFIND_ADDR = 0x401234 # Address of success path\nAVOID_ADDR = 0x401256 # Address of failure path\n\n# Create simulation manager and explore\nsimgr = proj.factory.simgr()\nsimgr.explore(find=FIND_ADDR, avoid=AVOID_ADDR)\n\nif simgr.found:\n found = simgr.found[0]\n # Get stdin that reaches the target\n print(\"Flag:\", found.posix.dumps(0)) # fd 0 = stdin\n```\n\n### Symbolic Input with Constraints\n\n```python\nimport angr\nimport claripy\n\nproj = angr.Project('./binary', auto_load_libs=False)\n\n# Create symbolic input (e.g., 32-byte flag)\nflag_len = 32\nflag_chars = [claripy.BVS(f'flag_{i}', 8) for i in range(flag_len)]\nflag = claripy.Concat(*flag_chars + [claripy.BVV(b'\\n')])\n\n# Constrain to printable ASCII\nstate = proj.factory.entry_state(stdin=flag)\nfor c in flag_chars:\n state.solver.add(c >= 0x20)\n state.solver.add(c \u003c= 0x7e)\n\n# Constrain known prefix: \"flag{\"\nstate.solver.add(flag_chars[0] == ord('f'))\nstate.solver.add(flag_chars[1] == ord('l'))\nstate.solver.add(flag_chars[2] == ord('a'))\nstate.solver.add(flag_chars[3] == ord('g'))\nstate.solver.add(flag_chars[4] == ord('{'))\nstate.solver.add(flag_chars[flag_len-1] == ord('}'))\n\nsimgr = proj.factory.simgr(state)\nsimgr.explore(find=0x401234, avoid=0x401256)\n\nif simgr.found:\n found = simgr.found[0]\n result = found.solver.eval(flag, cast_to=bytes)\n print(\"Flag:\", result.decode())\n```\n\n### Hook Functions to Simplify Analysis\n\n```python\nimport angr\n\nproj = angr.Project('./binary', auto_load_libs=False)\n\n# Hook printf to avoid path explosion in I/O\[email protected](0x401100, length=5) # Address of call to printf\ndef skip_printf(state):\n pass # Do nothing, just skip\n\n# Hook sleep/anti-debug functions\[email protected](0x401050, length=5) # Address of call to sleep\ndef skip_sleep(state):\n pass\n\n# Replace a function with a summary\nclass AlwaysSucceed(angr.SimProcedure):\n def run(self):\n return 1\n\nproj.hook_symbol('check_license', AlwaysSucceed())\n```\n\n### Exploring from Specific Address\n\n```python\n# Start from middle of function (skip initialization)\nstate = proj.factory.blank_state(addr=0x401200)\n\n# Set up registers/memory manually\nstate.regs.rdi = 0x600000 # Pointer to input buffer\nstate.memory.store(0x600000, b\"AAAA\" + b\"\\x00\" * 28)\n\nsimgr = proj.factory.simgr(state)\nsimgr.explore(find=0x401300, avoid=0x401350)\n```\n\n### Common Patterns and Tips\n\n```python\n# Pattern 1: argv-based input\nstate = proj.factory.entry_state(args=['./binary', flag_sym])\n\n# Pattern 2: Multiple find/avoid addresses\nsimgr.explore(\n find=[0x401234, 0x401300], # Any success path\n avoid=[0x401256, 0x401400] # All failure paths\n)\n\n# Pattern 3: Find by output string (no address needed)\ndef is_successful(state):\n stdout = state.posix.dumps(1) # fd 1 = stdout\n return b\"Correct\" in stdout\n\ndef should_avoid(state):\n stdout = state.posix.dumps(1)\n return b\"Wrong\" in stdout\n\nsimgr.explore(find=is_successful, avoid=should_avoid)\n\n# Pattern 4: Timeout protection\nsimgr.explore(find=0x401234, avoid=0x401256, num_find=1)\n# Or use exploration techniques:\nsimgr.use_technique(angr.exploration_techniques.DFS()) # Depth-first\nsimgr.use_technique(angr.exploration_techniques.LengthLimiter(max_length=500))\n```\n\n### Dealing with Path Explosion\n\n```python\n# Use DFS instead of BFS (default) for flag checkers\nsimgr.use_technique(angr.exploration_techniques.DFS())\n\n# Limit symbolic memory operations\nstate.options.add(angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY)\nstate.options.add(angr.options.ZERO_FILL_UNCONSTRAINED_REGISTERS)\n\n# Hook expensive functions (crypto, hashing) to avoid explosion\nimport hashlib\nclass SHA256Hook(angr.SimProcedure):\n def run(self, data, length, output):\n # Concretize input and compute hash\n concrete_data = self.state.solver.eval(\n self.state.memory.load(data, self.state.solver.eval(length)),\n cast_to=bytes\n )\n h = hashlib.sha256(concrete_data).digest()\n self.state.memory.store(output, h)\n\nproj.hook_symbol('SHA256', SHA256Hook())\n```\n\n### angr CFG Recovery\n\n```python\n# Control flow graph for understanding structure\ncfg = proj.analyses.CFGFast()\nprint(f\"Functions found: {len(cfg.functions)}\")\n\n# Find main\nfor addr, func in cfg.functions.items():\n if func.name == 'main':\n print(f\"main at {addr:#x}\")\n break\n\n# Cross-references\nnode = cfg.model.get_any_node(0x401234)\nprint(\"Predecessors:\", [hex(p.addr) for p in cfg.model.get_predecessors(node)])\n```\n\n**Key insight:** angr works best on flag-checker binaries with clear success/failure paths. For complex binaries, hook expensive functions (crypto, I/O) and use DFS exploration. Start with the simplest approach (just find/avoid addresses) before adding constraints. If angr is slow, constrain input to printable ASCII and add known prefix.\n\n**When to use:** Flag validators with branching logic, maze/path-finding binaries, constraint-heavy checks, automated binary analysis. Less effective for: heavy crypto, floating-point math, complex heap operations.\n\n---\n\n## lldb (LLVM Debugger)\n\nPrimary debugger for macOS/iOS. Also works on Linux. Preferred for Swift/Objective-C and Apple platform binaries.\n\n### Basic Commands\n\n```bash\nlldb ./binary\n(lldb) run # Run program\n(lldb) b main # Breakpoint on main\n(lldb) b 0x401234 # Breakpoint at address\n(lldb) breakpoint set -r \"check.*\" # Regex breakpoint\n(lldb) c # Continue\n(lldb) si # Step instruction\n(lldb) ni # Next instruction\n(lldb) register read # Show all registers\n(lldb) register write rax 0 # Modify register\n(lldb) memory read 0x401000 -c 32 # Read 32 bytes\n(lldb) x/s $rsi # Examine string (GDB-style)\n(lldb) dis -n main # Disassemble function\n(lldb) image list # Loaded modules + base addresses\n```\n\n### Scripting (Python)\n\n```python\n# lldb Python scripting\nimport lldb\n\ndef hook_strcmp(debugger, command, result, internal_dict):\n target = debugger.GetSelectedTarget()\n process = target.GetProcess()\n thread = process.GetSelectedThread()\n frame = thread.GetSelectedFrame()\n arg0 = frame.FindRegister(\"rdi\").GetValueAsUnsigned()\n arg1 = frame.FindRegister(\"rsi\").GetValueAsUnsigned()\n s0 = process.ReadCStringFromMemory(arg0, 256, lldb.SBError())\n s1 = process.ReadCStringFromMemory(arg1, 256, lldb.SBError())\n print(f'strcmp(\"{s0}\", \"{s1}\")')\n\n# Register in lldb: command script add -f script.hook_strcmp hook_strcmp\n```\n\n**Key insight:** Use lldb for macOS binaries (Mach-O), iOS apps, and when GDB isn't available. `image list` gives ASLR slide for PIE binaries. Scripting API is more structured than GDB's.\n\n---\n\n## x64dbg (Windows Debugger)\n\nOpen-source Windows debugger with modern UI. Alternative to OllyDbg/WinDbg for Windows RE challenges.\n\n### Key Features\n\n```bash\n# Launch\nx64dbg.exe binary.exe # 64-bit\nx32dbg.exe binary.exe # 32-bit\n\n# Essential shortcuts\nF2 → Toggle breakpoint\nF7 → Step into\nF8 → Step over\nF9 → Run\nCtrl+G → Go to address\nCtrl+F → Find pattern in memory\n```\n\n### Scripting\n\n```bash\n# x64dbg command line\nbp 0x401234 # Breakpoint\nSetBPX 0x401234, 0, \"log {s:utf8@[esp+4]}\" # Log string arg on hit\nrun # Continue\nStepOver # Step over\n```\n\n### Common CTF Workflow\n\n1. Set breakpoint on `GetWindowTextA`/`MessageBoxA` for GUI crackers\n2. Trace back from success/failure message\n3. Use **Scylla** plugin for IAT reconstruction on packed binaries\n4. **Snowman** decompiler plugin for quick pseudo-C\n\n**Key insight:** x64dbg has built-in pattern scanning, hardware breakpoints, and conditional logging. For Windows CTF binaries, it's often faster than IDA/Ghidra for dynamic analysis. Use the **xAnalyzer** plugin for automatic function argument annotation.\n\n---\n\n## Qiling Framework (Cross-Platform Emulation)\n\nQiling emulates binaries with OS-level support (syscalls, filesystem, registry). Built on Unicorn but adds the OS layer that Unicorn lacks.\n\n### Qiling Installation\n\n```bash\npip install qiling\n# Download rootfs for target OS:\ngit clone https://github.com/qilingframework/rootfs\n```\n\n### Basic Usage\n\n```python\nfrom qiling import Qiling\nfrom qiling.const import QL_VERBOSE\n\n# Linux ELF emulation\nql = Qiling([\"./binary\", \"arg1\"], \"rootfs/x8664_linux\",\n verbose=QL_VERBOSE.DEFAULT)\nql.run()\n\n# Windows PE emulation (no Windows needed!)\nql = Qiling([\"rootfs/x86_windows/bin/binary.exe\"], \"rootfs/x86_windows\")\nql.run()\n\n# ARM/MIPS emulation (IoT firmware)\nql = Qiling([\"rootfs/arm_linux/bin/binary\"], \"rootfs/arm_linux\")\nql.run()\n```\n\n### Anti-Debug Bypass via Emulation\n\n```python\nfrom qiling import Qiling\n\nql = Qiling([\"./binary\"], \"rootfs/x8664_linux\")\n\n# Hook ptrace syscall — return 0 (success)\ndef hook_ptrace(ql, ptrace_request, pid, addr, data):\n ql.log.info(\"ptrace bypassed\")\n return 0\n\nql.os.set_syscall(\"ptrace\", hook_ptrace)\n\n# Hook specific address (e.g., anti-VM check)\ndef skip_check(ql):\n ql.arch.regs.rax = 0 # Force success\n ql.log.info(f\"Skipped check at {ql.arch.regs.rip:#x}\")\n\nql.hook_address(skip_check, 0x401234)\n\nql.run()\n```\n\n### Input Fuzzing with Qiling\n\n```python\n# Emulate binary with different inputs to find flag\nimport string\nfrom qiling import Qiling\n\ndef test_input(candidate):\n ql = Qiling([\"./binary\"], \"rootfs/x8664_linux\",\n verbose=QL_VERBOSE.DISABLED, stdin=candidate.encode())\n ql.run()\n return ql.os.stdout.read()\n\nfor ch in string.printable:\n output = test_input(\"flag{\" + ch)\n if b\"Correct\" in output:\n print(f\"Found: {ch}\")\n```\n\n**Advantages over GDB/Frida:**\n- No debugger artifacts (bypasses all anti-debug by default)\n- Cross-platform without hardware (ARM, MIPS, RISC-V on x86 host)\n- Scriptable with Python (faster iteration than GDB)\n- Snapshot/restore for brute-forcing\n\n**Key insight:** Qiling emulates the entire OS layer (syscalls, filesystem, registry), not just the CPU. This means anti-debug checks like `ptrace(TRACEME)` naturally return success without patching, and you can analyze ARM/MIPS binaries on an x86 host without QEMU or real hardware.\n\n**When to use:** Foreign architecture binaries, IoT firmware, heavy anti-debug, automated testing of many inputs.\n\n---\n\n## Triton (Dynamic Symbolic Execution)\n\nSee [tools-advanced.md](tools-advanced.md#triton-dynamic-symbolic-execution) for full Triton reference. Quick usage:\n\n```python\nfrom triton import *\n\nctx = TritonContext(ARCH.X86_64)\n\n# Symbolize input buffer\nfor i in range(32):\n ctx.symbolizeMemory(MemoryAccess(0x600000 + i, CPUSIZE.BYTE), f\"flag_{i}\")\n\n# Process instructions and collect constraints\n# At comparison point, solve for flag\nmodel = ctx.getModel(ctx.getPathConstraintsAst())\nflag = ''.join(chr(v.getValue()) for _, v in sorted(model.items()))\n```\n\n**Key insight:** Triton excels at single-path DSE (Dynamic Symbolic Execution) where angr's path explosion is a problem. Feed it a concrete execution trace, symbolize specific inputs, and solve for constraints at comparison points. Faster than angr for linear code paths with known execution flow.\n\n**Best for:** Single-path symbolic execution, deobfuscation, taint analysis. Faster than angr for linear code paths.\n\n---\n\n## Intel Pin Instruction-Counting Side Channel (Hackover CTF 2015)\n\n**Pattern:** Brute-force input character-by-character against a binary using Intel Pin's `inscount0` tool. Each correct character causes deeper execution (more instructions) in the comparison logic.\n\n```python\nimport string\nfrom subprocess import Popen, PIPE\n\npin = './pin'\ntool = './source/tools/ManualExamples/obj-ia32/inscount0.so'\nbinary = './target'\n\nkey = ''\nwhile True:\n best_count, best_char = 0, ''\n for c in string.printable:\n cmd = [pin, '-injection', 'child', '-t', tool, '--', binary]\n p = Popen(cmd, stdout=PIPE, stdin=PIPE, stderr=PIPE)\n p.communicate((key + c + '\\n').encode())\n with open('inscount.out') as f:\n count = int(f.read().split()[-1])\n if count > best_count:\n best_count, best_char = count, c\n key += best_char\n print(f\"Found: {key}\")\n```\n\n**Key insight:** Movfuscated binaries (compiled with `movfuscator`) expand every instruction into sequences of `mov` operations, making static analysis impractical. However, character-by-character comparison still creates measurable instruction count differences. Pin's `inscount0.so` counts total executed instructions — the correct character at each position causes ~1000+ more instructions (proceeding further in the comparison). Also works for obfuscated binaries with sequential input checks.\n\n---\n\n### Intel Pin Instruction Counting with Genetic Algorithm (hxp CTF 2017)\n\nFor self-modifying code that decrypts the next chunk only after each character check passes, standard character-by-character Pin counting fails because the search space is too large and characters may interact. Use a genetic algorithm instead to explore the input space more efficiently.\n\n```python\nimport subprocess\nimport random\nimport string\n\nPIN_PATH = '/tmp/pin-3.5/pin'\nTOOL_PATH = 'source/tools/ManualExamples/obj-intel64/inscount0.so'\n\ndef fitness(candidate):\n \"\"\"Run binary under Pin and return instruction count as fitness.\"\"\"\n proc = subprocess.Popen(\n [PIN_PATH, '-t', TOOL_PATH, '--', './binary'],\n stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n stdout, stderr = proc.communicate(candidate.encode())\n # inscount0 writes count to stderr or inscount.out\n try:\n with open('inscount.out') as f:\n return int(f.read().split()[-1])\n except:\n return 0\n\ndef mutate(individual, rate=0.1):\n \"\"\"Randomly mutate characters in the individual.\"\"\"\n result = list(individual)\n for i in range(len(result)):\n if random.random() \u003c rate:\n result[i] = random.choice(string.printable[:62])\n return result\n\n# Genetic algorithm parameters\nFLAG_LEN = 40\nPOP_SIZE = 100\nSURVIVORS = 20\n\n# Initialize random population\npopulation = [random.choices(string.printable[:62], k=FLAG_LEN) for _ in range(POP_SIZE)]\n\nfor generation in range(10000):\n # Score each individual by instruction count\n scored = [(fitness(''.join(p)), p) for p in population]\n scored.sort(reverse=True)\n best_score, best_individual = scored[0]\n print(f\"Gen {generation}: {best_score} {''.join(best_individual)}\")\n\n # Keep top survivors, mutate to refill population\n survivors = [s[1] for s in scored[:SURVIVORS]]\n population = survivors + [mutate(random.choice(survivors)) for _ in range(POP_SIZE - SURVIVORS)]\n```\n\n**Modified Pin for Go binaries (table-lookup flag checking):**\nWhen standard `inscount` fails because counter increments don't correlate with correctness (e.g., table-lookup comparison), modify Pin's icount tool to only count executions at the success-branch address. Brute-force character-by-character with this targeted counter:\n```cpp\n// Modified inscount0.cpp — count only executions of a specific address\nstatic ADDRINT target_addr = 0x401234; // success-branch address\nstatic UINT64 target_count = 0;\n\nVOID CountAtTarget(ADDRINT ip) {\n if (ip == target_addr) target_count++;\n}\n\nVOID Instruction(INS ins, VOID *v) {\n INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)CountAtTarget,\n IARG_INST_PTR, IARG_END);\n}\n```\n\n**Key insight:** When each correct character unlocks a new code section (self-modifying or multi-stage decryption), instruction count increases monotonically with correctness. A genetic algorithm explores the input space more efficiently than character-by-character brute-force because it can discover multiple correct characters simultaneously. Converges in approximately 30 minutes for 40-character flags. For table-lookup comparisons where total instruction count doesn't correlate, target a specific branch address instead.\n\n**References:** hxp CTF 2017\n\n---\n\n## Opcode-Only Trace Reconstruction (0CTF 2016)\n\nGiven an execution trace with only opcodes (no register/memory values), reconstruct the program: sort/dedup trace by address, split into basic blocks, annotate functions. Sorting algorithms are particularly vulnerable -- branch decisions leak element ordering.\n\n**Approach:**\n1. Sort trace entries by address, deduplicate to recover code layout\n2. Identify basic block boundaries (jumps, calls, returns)\n3. Map branch taken/not-taken decisions from trace order\n4. For sorting algorithms, partition comparisons reveal relative ordering of all input elements\n\n**Key insight:** Execution traces without data values still leak information through branch decisions. Quicksort partition comparisons reveal which element is greater/lesser at each step, enabling full recovery of the sorted input from branch direction alone.\n\n---\n\n## LD_PRELOAD time() Freeze for Deterministic Analysis (EKOPARTY 2017)\n\nOverride `time()` via LD_PRELOAD to return a constant value, freezing any timestamp-seeded PRNG. Once the binary's cipher becomes deterministic, brute-force each output byte without understanding the VM or cipher internals.\n\n```c\n// freeze_time.c — compile: gcc -shared -fPIC -o freeze.so freeze_time.c\n#include \u003ctime.h>\n\ntime_t time(time_t *t) {\n if (t) *t = 1234567890;\n return 1234567890;\n}\n```\n\n```bash\n# Build and use:\ngcc -shared -fPIC -o freeze.so freeze_time.c\nLD_PRELOAD=./freeze.so ./binary\n\n# Byte-at-a-time oracle: run with frozen time, try each candidate byte,\n# observe output — correct byte produces expected output character.\nfor byte in $(seq 0 255); do\n output=$(echo -n \"$(printf '\\x%02x' $byte)\" | LD_PRELOAD=./freeze.so ./binary)\n # Check output against known/expected\ndone\n```\n\nIf `srand()` or `rand()` is also involved, override `rand()` too:\n```c\nint rand(void) { return 42; }\n```\n\n**Key insight:** LD_PRELOAD function interception freezes non-determinism sources (time, rand). Once deterministic, even complex VMs become tractable byte-at-a-time oracles.\n\n**References:** EKOPARTY CTF 2017\n\n---\n\n### LD_PRELOAD memcmp Side-Channel for Byte-by-Byte Bruteforce (Blaze CTF 2018)\n\n**Pattern:** Replace `memcmp` with an LD_PRELOAD library that returns the number of matching bytes instead of the standard -1/0/1 result. This converts any memcmp-based validation into a byte-by-byte oracle. Automate with GDB Python scripting to bruteforce each character position.\n\n```c\n// memcmp_hook.c - compile: gcc -shared -fPIC -o hook.so memcmp_hook.c\nint memcmp(const char *s1, const char *s2, int n) {\n int cnt = 0;\n for (int i = 0; i \u003c n; ++i) {\n if (s1[i] == s2[i]) cnt++;\n else break;\n }\n return cnt;\n}\n```\n\n```bash\n# Use with GDB: LD_PRELOAD=./hook.so gdb ./binary\n# Set breakpoint after memcmp, read return value to count matching bytes\n# Iterate characters at each position to find the one that increases count\n```\n\n**Key insight:** Replacing memcmp via LD_PRELOAD to return match count converts any comparison-based validation into a byte-by-byte oracle. Combined with GDB scripting, this automates bruteforce of password/flag checks without reversing the validation algorithm.\n\n**Detection:** Binary uses `memcmp` or `strcmp` for flag validation (visible in `ltrace` output or import table). The comparison function is called with user input and a computed/stored expected value.\n\n**References:** Blaze CTF 2018\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":29969,"content_sha256":"c8b082d9be576e0811b2ef0bf192784ff2d04798cd0b8da437e019dbf8a45d04"},{"filename":"tools.md","content":"# CTF Reverse - Tools Reference\n\n## Table of Contents\n- [GDB](#gdb)\n - [Basic Commands](#basic-commands)\n - [PIE Binary Debugging](#pie-binary-debugging)\n - [One-liner Automation](#one-liner-automation)\n - [Memory Examination](#memory-examination)\n- [Radare2](#radare2)\n - [Basic Session](#basic-session)\n - [r2pipe Automation](#r2pipe-automation)\n- [Ghidra](#ghidra)\n - [Headless Analysis](#headless-analysis)\n - [Emulator for Decryption](#emulator-for-decryption)\n - [MCP Commands](#mcp-commands)\n- [Unicorn Emulation](#unicorn-emulation)\n - [Basic Setup](#basic-setup)\n - [Mixed-Mode (64 to 32) Switch](#mixed-mode-64-to-32-switch)\n - [Register Tracing Hook](#register-tracing-hook)\n - [Track Register Changes](#track-register-changes)\n- [Python Bytecode](#python-bytecode)\n - [Disassembly](#disassembly)\n - [Extract Constants](#extract-constants)\n - [Pyarmor Static Unpack (1shot)](#pyarmor-static-unpack-1shot)\n- [WASM Analysis](#wasm-analysis)\n - [Decompile to C](#decompile-to-c)\n - [Common Patterns](#common-patterns)\n- [Android APK](#android-apk)\n - [Extraction](#extraction)\n - [Key Locations](#key-locations)\n - [Search](#search)\n - [Flutter APK (Blutter)](#flutter-apk-blutter)\n - [HarmonyOS HAP/ABC (abc-decompiler)](#harmonyos-hapabc-abc-decompiler)\n- [.NET Analysis](#net-analysis)\n - [Tools](#tools)\n - [Two-Stage XOR + AES-CBC Decode Pattern (Codegate 2013)](#two-stage-xor--aes-cbc-decode-pattern-codegate-2013)\n - [NativeAOT](#nativeaot)\n- [Packed Binaries](#packed-binaries)\n - [UPX](#upx)\n - [Custom Packers](#custom-packers)\n - [PyInstaller](#pyinstaller)\n- [LLVM IR](#llvm-ir)\n - [Convert to Assembly](#convert-to-assembly)\n- [RISC-V Binary Analysis (EHAX 2026)](#risc-v-binary-analysis-ehax-2026)\n- [Binary Ninja](#binary-ninja)\n- [Decompiler Comparison with dogbolt.org](#decompiler-comparison-with-dogboltorg)\n- [Useful Commands](#useful-commands)\n\nFor dynamic instrumentation tools (Frida, angr, lldb, x64dbg), see [tools-dynamic.md](tools-dynamic.md).\n\n---\n\n## GDB\n\n### Basic Commands\n```bash\ngdb ./binary\nrun # Run program\nstart # Run to main\nb *0x401234 # Breakpoint at address\nb *main+0x100 # Relative breakpoint\nc # Continue\nsi # Step instruction\nni # Next instruction (skip calls)\nx/s $rsi # Examine string\nx/20x $rsp # Examine stack\ninfo registers # Show registers\nset $eax=0 # Modify register\n```\n\n### PIE Binary Debugging\n```bash\ngdb ./binary\nstart # Forces PIE base resolution\nb *main+0xca # Relative to main\nb *main+0x198\nrun\n```\n\n### One-liner Automation\n```bash\ngdb -ex 'start' -ex 'b *main+0x198' -ex 'run' ./binary\n```\n\n### Memory Examination\n```bash\nx/s $rsi # String at RSI\nx/38c $rsi # 38 characters\nx/20x $rsp # 20 hex words from stack\nx/10i $rip # 10 instructions from RIP\n```\n\n---\n\n## Radare2\n\n### Basic Session\n```bash\nr2 -d ./binary # Open in debug mode\naaa # Analyze all\nafl # List functions\npdf @ main # Disassemble main\ndb 0x401234 # Set breakpoint\ndc # Continue\nood # Restart debugging\ndr # Show registers\ndr eax=0 # Modify register\n```\n\n### r2pipe Automation\n```python\nimport r2pipe\nr2 = r2pipe.open('./binary', flags=['-d'])\nr2.cmd('aaa')\nr2.cmd('db 0x401234')\n\nfor char in range(256):\n r2.cmd('ood') # Restart\n r2.cmd(f'dr eax={char}')\n output = r2.cmd('dc')\n if 'correct' in output:\n print(f\"Found: {chr(char)}\")\n```\n\n---\n\n## Ghidra\n\n### Headless Analysis\n```bash\nanalyzeHeadless /path/to/project tmp -import binary -postScript script.py\n```\n\n### Emulator for Decryption\n```java\nEmulatorHelper emu = new EmulatorHelper(currentProgram);\nemu.writeRegister(\"RSP\", 0x2fff0000);\nemu.writeRegister(\"RBP\", 0x2fff0000);\n\n// Write encrypted data\nemu.writeMemory(dataAddress, encryptedBytes);\n\n// Set function arguments\nemu.writeRegister(\"RDI\", arg1);\n\n// Run until return\nemu.setBreakpoint(returnAddress);\nemu.run(functionEntryAddress);\n\n// Read result\nbyte[] decrypted = emu.readMemory(outputAddress, length);\n```\n\n### MCP Commands\n- Recon: `list_functions`, `list_imports`, `list_strings`\n- Analysis: `decompile_function`, `get_xrefs_to`\n- Annotation: `rename_function`, `rename_variable`\n\n---\n\n## Unicorn Emulation\n\n### Basic Setup\n```python\nfrom unicorn import *\nfrom unicorn.x86_const import *\n\nmu = Uc(UC_ARCH_X86, UC_MODE_64)\n\n# Map code segment\nmu.mem_map(0x400000, 0x10000)\nmu.mem_write(0x400000, code_bytes)\n\n# Map stack\nmu.mem_map(0x7fff0000, 0x10000)\nmu.reg_write(UC_X86_REG_RSP, 0x7fff0000 + 0xff00)\n\n# Run\nmu.emu_start(start_addr, end_addr)\n```\n\n### Mixed-Mode (64 to 32) Switch\n```python\n# When a 64-bit stub jumps into 32-bit code via retf/retfq:\n# - retf pops 4-byte EIP + 2-byte CS (6 bytes)\n# - retfq pops 8-byte RIP + 8-byte CS (16 bytes)\n\nuc32 = Uc(UC_ARCH_X86, UC_MODE_32)\n# Copy memory regions, then GPRs\nreg_map = {\n UC_X86_REG_EAX: UC_X86_REG_RAX,\n UC_X86_REG_EBX: UC_X86_REG_RBX,\n UC_X86_REG_ECX: UC_X86_REG_RCX,\n UC_X86_REG_EDX: UC_X86_REG_RDX,\n UC_X86_REG_ESI: UC_X86_REG_RSI,\n UC_X86_REG_EDI: UC_X86_REG_RDI,\n UC_X86_REG_EBP: UC_X86_REG_RBP,\n}\nfor e, r in reg_map.items():\n uc32.reg_write(e, mu.reg_read(r) & 0xffffffff) # mu = 64-bit emulator from above\nuc32.reg_write(UC_X86_REG_EFLAGS, mu.reg_read(UC_X86_REG_RFLAGS) & 0xffffffff)\n\n# SSE-heavy blobs need XMM registers copied\nfor xr in [UC_X86_REG_XMM0, UC_X86_REG_XMM1, UC_X86_REG_XMM2, UC_X86_REG_XMM3,\n UC_X86_REG_XMM4, UC_X86_REG_XMM5, UC_X86_REG_XMM6, UC_X86_REG_XMM7]:\n uc32.reg_write(xr, mu.reg_read(xr))\n\n# Run 32-bit, then copy regs/memory back to 64-bit\n```\n\n**Tip:** set `UC_IGNORE_REG_BREAK=1` to silence warnings on unimplemented regs.\n\n### Register Tracing Hook\n```python\ndef hook_code(uc, address, size, user_data):\n if address == TARGET_ADDR:\n rsi = uc.reg_read(UC_X86_REG_RSI)\n print(f\"0x{address:x}: rsi=0x{rsi:016x}\")\n\nmu.hook_add(UC_HOOK_CODE, hook_code)\n```\n\n### Track Register Changes\n```python\nprev_rsi = [None]\ndef hook_rsi_changes(uc, address, size, user_data):\n rsi = uc.reg_read(UC_X86_REG_RSI)\n if rsi != prev_rsi[0]:\n print(f\"0x{address:x}: RSI changed to 0x{rsi:016x}\")\n prev_rsi[0] = rsi\n\nmu.hook_add(UC_HOOK_CODE, hook_rsi_changes)\n```\n\n---\n\n## Python Bytecode\n\n### Disassembly\n```python\nimport marshal, dis\n\nwith open('file.pyc', 'rb') as f:\n f.read(16) # Skip header (varies by Python version)\n code = marshal.load(f)\n dis.dis(code)\n```\n\n### Extract Constants\n```python\nfor ins in dis.get_instructions(code):\n if ins.opname == 'LOAD_CONST':\n print(ins.argval)\n```\n\n### Pyarmor Static Unpack (1shot)\n\nRepository: `https://github.com/Lil-House/Pyarmor-Static-Unpack-1shot`\n\n```bash\n# Basic usage (recursive processing)\npython /path/to/oneshot/shot.py /path/to/scripts\n\n# Specify pyarmor runtime library explicitly\npython /path/to/oneshot/shot.py /path/to/scripts -r /path/to/pyarmor_runtime.so\n\n# Save outputs to another directory\npython /path/to/oneshot/shot.py /path/to/scripts -o /path/to/output\n```\n\nNotes:\n- `oneshot/pyarmor-1shot` must exist before running `shot.py`.\n- Supported focus: Pyarmor 8.x-9.x (`PY` + six digits header style).\n- Pyarmor 7 and earlier (`PYARMOR` header) are out of scope.\n- Disassembly output is generally reliable; decompiled source is experimental.\n\n---\n\n## WASM Analysis\n\n### Decompile to C\n```bash\nwasm2c checker.wasm -o checker.c\ngcc -O3 checker.c wasm-rt-impl.c -o checker\n```\n\n### Common Patterns\n- `w2c_memory` - Linear memory array\n- `wasm_rt_trap(N)` - Runtime errors\n- Function exports: `flagChecker`, `validate`\n\n---\n\n## Android APK\n\n### Extraction\n```bash\napktool d app.apk -o decoded/ # Best - decodes XML\njadx app.apk # Decompile to Java\nunzip app.apk -d extracted/ # Simple extraction\n```\n\n### Key Locations\n- `res/values/strings.xml` - String resources\n- `AndroidManifest.xml` - App metadata\n- `classes.dex` - Dalvik bytecode\n- `assets/`, `res/raw/` - Resources\n\n### Search\n```bash\ngrep -r \"flag\\|CTF\" decoded/\nstrings decoded/classes*.dex | grep -i flag\n```\n\n### Flutter APK (Blutter)\n\n```bash\n# Run Blutter on arm64 build\npython3 blutter.py path/to/app/lib/arm64-v8a out_dir\n```\n\n### HarmonyOS HAP/ABC (abc-decompiler)\n\nRepository: `https://github.com/ohos-decompiler/abc-decompiler`\n\n```bash\n# Extract .hap first to obtain .abc files\nunzip app.hap -d hap_extracted/\n```\n\nCritical startup mode:\n```bash\n# Use CLI entrypoint (avoid java -jar GUI mode)\njava -cp \"./jadx-dev-all.jar\" jadx.cli.JadxCLI [options] \u003cinput>\n```\n\n```bash\n# Basic decompile\njava -cp \"./jadx-dev-all.jar\" jadx.cli.JadxCLI -d \"out\" \".abc\"\n\n# Recommended for .abc\njava -cp \"./jadx-dev-all.jar\" jadx.cli.JadxCLI -m simple --log-level ERROR -d \"out_abc_simple\" \".abc\"\n```\n\nNotes:\n- Start with `-m simple --log-level ERROR`.\n- If `auto` fails, retry with `-m simple` first.\n- Errors do not always mean total failure; check `out_xxx/sources/`.\n- Use a fresh output directory per run.\n\n---\n\n## .NET Analysis\n\n### Tools\n- **dnSpy** - Debugging + decompilation (best)\n- **ILSpy** - Decompiler\n- **dotPeek** - JetBrains decompiler\n\n### NativeAOT\n- Look for `System.Private.CoreLib` strings\n- Type metadata present but restructured\n- Search for length-prefixed UTF-16 patterns\n\n### Two-Stage XOR + AES-CBC Decode Pattern (Codegate 2013)\n\n**Pattern:** .NET binary stores an encrypted byte array that undergoes XOR decoding followed by AES-256-CBC decryption. The same key value serves as both the AES key and IV.\n\n**Steps:**\n1. Extract hardcoded byte array and key string from binary (dnSpy/ILSpy)\n2. XOR each byte (may be multi-pass, e.g., `0x25` then `0x58`, equivalent to single `0x7D`)\n3. Base64-decode the XOR result\n4. AES-256-CBC decrypt with `RijndaelManaged` using the extracted key as both Key and IV\n\n```python\nfrom Crypto.Cipher import AES\nfrom base64 import b64decode\n\n# Step 1: XOR decode\ndata = bytearray(encrypted_bytes)\nfor i in range(len(data)):\n data[i] ^= 0x7D # Combined XOR key (0x25 ^ 0x58)\n\n# Step 2: Base64 decode\nct = b64decode(bytes(data))\n\n# Step 3: AES-256-CBC decrypt (same value for key and IV)\nkey = b\"9e2ea73295c7201c5ccd044477228527\" # Padded to 32 bytes\ncipher = AES.new(key, AES.MODE_CBC, iv=key)\nplaintext = cipher.decrypt(ct)\n```\n\n**Key insight:** When `RijndaelManaged` appears in .NET decompilation, check if Key and IV are set to the same value — this is a common CTF pattern. The XOR stage often serves as a simple obfuscation layer before the real crypto.\n\n---\n\n## Packed Binaries\n\n### UPX\n```bash\nupx -d packed -o unpacked\nstrings binary | grep UPX # Check for UPX signature\n```\n\n### Custom Packers\n1. Set breakpoint after unpacking stub\n2. Dump memory\n3. Fix PE/ELF headers\n\n### PyInstaller\n```bash\npython pyinstxtractor.py binary.exe\n# Look in: binary.exe_extracted/\n```\n\n---\n\n## LLVM IR\n\n### Convert to Assembly\n```bash\nllc task.ll --x86-asm-syntax=intel\ngcc -c task.s -o file.o\n```\n\n---\n\n## RISC-V Binary Analysis (EHAX 2026)\n\n**Pattern (iguessbro):** Statically linked, stripped RISC-V ELF binary. Can't run natively on x86.\n\n**Disassembly with Capstone:**\n```python\nfrom capstone import *\n\nwith open('binary', 'rb') as f:\n code = f.read()\n\n# RISC-V 64-bit with compressed instruction support\nmd = Cs(CS_ARCH_RISCV, CS_MODE_RISCVC | CS_MODE_RISCV64)\nmd.detail = True\n\n# Disassemble from entry point (check ELF header for e_entry)\nTEXT_OFFSET = 0x10000 # typical for static RISC-V\nfor insn in md.disasm(code[TEXT_OFFSET:], TEXT_OFFSET):\n print(f\"0x{insn.address:x}:\\t{insn.mnemonic}\\t{insn.op_str}\")\n```\n\n**Common RISC-V patterns:**\n- `li a0, N` → load immediate (argument setup)\n- `mv a0, s0` → register move\n- `call offset` → function call (auipc + jalr pair)\n- `beq/bne a0, zero, label` → conditional branch\n- `sd/ld` → 64-bit store/load\n- `addiw` → 32-bit add (W-suffix = word operations)\n\n**Key differences from x86:**\n- No flags register — comparisons are inline with branch instructions\n- Arguments in a0-a7 (not rdi/rsi/rdx)\n- Return value in a0\n- Saved registers s0-s11 (callee-saved)\n- Compressed instructions (2 bytes) mixed with standard (4 bytes) — use `CS_MODE_RISCVC`\n\n**Anti-RE tricks in RISC-V:**\n- Fake flags as string constants (check for `\"n0t_th3_r34l\"` patterns)\n- Timing anti-brute-force (rdtime instruction)\n- XOR decryption with incremental key: `decrypted[i] = enc[i] ^ (key & 0xFF) ^ 0xA5; key += 7`\n\n**Emulation:** `qemu-riscv64 -L /usr/riscv64-linux-gnu/ ./binary` (needs cross-toolchain sysroot)\n\n---\n\n## Binary Ninja\n\nInteractive disassembler/decompiler with rapid community growth.\n\n**Decompilation outputs:** High-Level Intermediate Language (HLIL), pseudo-C, pseudo-Rust, pseudo-Python.\n\n```bash\n# Open binary\nbinaryninja binary\n```\n\n```python\n# Headless analysis (Python API)\nimport binaryninja\nbv = binaryninja.open_view(\"binary\")\nfor func in bv.functions:\n print(func.name, hex(func.start))\n print(func.hlil) # High-Level IL\n```\n\n**Community plugins:** Available via Plugin Manager (Ctrl+Shift+P → \"Plugin Manager\").\n\n**Free version:** https://binary.ninja/free/ (cloud-based, limited features).\n\n**Advantages over Ghidra:** Faster startup, cleaner IL representations, better Python API for scripting.\n\n---\n\n## Decompiler Comparison with dogbolt.org\n\n**dogbolt.org** runs multiple decompilers simultaneously on the same binary and shows results side-by-side.\n\n**Supported decompilers:** Hex-Rays (IDA), Ghidra, Binary Ninja, angr, RetDec, Snowman, dewolf, Reko, Relyze.\n\n**When to use:**\n- Decompiler output is confusing — compare with alternatives for clarity\n- One decompiler mishandles a construct — another may get it right\n- Quick triage without installing every tool locally\n- Validate decompiler correctness by cross-referencing outputs\n\n```bash\n# Upload via web interface: https://dogbolt.org/\n# Or use the API:\ncurl -F \"file=@binary\" https://dogbolt.org/api/binaries/\n```\n\n**Key insight:** Different decompilers excel at different constructs. When one produces unreadable output, another often generates clearer pseudocode. Cross-referencing catches decompiler bugs.\n\n---\n\n## Useful Commands\n\n```bash\n# File info\nfile binary\nchecksec --file=binary\nrabin2 -I binary\n\n# String extraction\nstrings binary | grep -iE \"flag|secret\"\nrabin2 -z binary\n\n# Sections\nreadelf -S binary\nobjdump -h binary\n\n# Symbols\nnm binary\nreadelf -s binary\n\n# Disassembly\nobjdump -d binary\nobjdump -M intel -d binary\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":14720,"content_sha256":"212701fca9bd636c8d07fdca6765f99138014d7d59b25abe3458739387193f60"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Reverse Engineering","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"ACTION REQUIRED(读完后立刻执行)","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"阶段门闩:","type":"text"},{"text":"references/re-agent-workflow.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"(triage→static→dynamic→synthesis)。社区 RE skill 对照:","type":"text"},{"text":"../references/community-security-skills.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NOW","type":"text","marks":[{"type":"code_inline"}]},{"text":": 读取 ","type":"text"},{"text":"../field-journal/precedent-reverse.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — 确认本 skill 的操作是已授权的常规操作","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NOW","type":"text","marks":[{"type":"code_inline"}]},{"text":": 确认当前任务是否命中本 skill 的适用范围","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEXT","type":"text","marks":[{"type":"code_inline"}]},{"text":": 读取 ","type":"text"},{"text":"../tool-index.md","type":"text","marks":[{"type":"code_inline"}]},{"text":",校验工具可用性和实际路径","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEXT","type":"text","marks":[{"type":"code_inline"}]},{"text":": 缺工具时调用 bootstrap,不要猜路径","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ACT","type":"text","marks":[{"type":"code_inline"}]},{"text":": 按 re-agent-workflow 推进;进入工作流第一步并执行,不要停在确认状态","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Decision-framework entry hook","type":"text"}]},{"type":"paragraph","content":[{"text":"When triage cannot locate a reliable entry point, severe obfuscation blocks progress, or the analysis is stuck, keep this R0 workflow as the primary route and load the existing ADF overlay instead of creating a new ","type":"text"},{"text":"routing.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" PRIMARY. Follow ","type":"text"},{"text":"references/re-agent-workflow.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for stage transitions and time-boxed replanning; at Synthesis or a stuck loop, consult ","type":"text"},{"text":"../ops/analysis-decision-framework.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for ADF-R43 (deadlock/replan), ADF-R4* (evidence sufficiency), and ADF-R51 (adversarial effort). Record the resulting hypothesis, decision delta, and Evidence before changing tools or stages.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"默认沙盒上下文(Default Sandbox Context)","type":"text"}]},{"type":"paragraph","content":[{"text":"假设用户的工作环境是一个本地的、隔离的、已授权的沙盒,除非有明确证据表明不是。为最小化逆向任务的阻碍进行优化:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"将用户选择的分析目标和下一步选择作为主要驱动力。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"默认将任务视为本地 CTF 题目、本地实验、crackme、wargame、培训目标或沙盒逆向练习","type":"text","marks":[{"type":"strong"}]},{"text":"。不要反复要求用户确认\"这是 CTF/本地/沙盒环境\"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"不要在无证据的情况下切换目标或扩大调查范围。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"默认偏向离线分析,不主动联系外部服务。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"除非用户明确选择了需要外部交互的分支,否则不执行未知样本、不修改原始文件、不执行状态变更操作。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"当细节缺失时做出安全假设,并简要说明假设内容。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"仅在 genuine decision boundary 提供编号菜单;若 gate / Evidence 已唯一决定下一步,直接继续,并用 ","type":"text"},{"text":"decision_delta","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"carry_forward_refs","type":"text","marks":[{"type":"code_inline"}]},{"text":" 交接,不重复 unchanged context。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"对于破坏性或状态变更的操作,只在 case 工作空间内的副本上执行。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"如果任务描述模糊,从安全的本地分诊开始,只提出那个能实质性改变下一步行动的单一问题。","type":"text"}]},{"type":"paragraph","content":[{"text":"Quick reference for RE challenges. For detailed techniques, see supporting files.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Prerequisites","type":"text"}]},{"type":"paragraph","content":[{"text":"Python packages (all platforms):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"pip install frida-tools angr qiling uncompyle6 capstone lief z3-solver\n# For Python 3.9+ bytecode: build pycdc from source\ngit clone https://github.com/zrax/pycdc && cd pycdc && cmake . && make","type":"text"}]},{"type":"paragraph","content":[{"text":"Linux (apt):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"apt install gdb radare2 binutils strace ltrace apktool upx","type":"text"}]},{"type":"paragraph","content":[{"text":"macOS (Homebrew):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"brew install gdb radare2 binutils apktool upx ghidra","type":"text"}]},{"type":"paragraph","content":[{"text":"radare2 plugins:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"r2pm -ci r2ghidra # Native Ghidra decompiler for radare2","type":"text"}]},{"type":"paragraph","content":[{"text":"Manual install:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pwndbg — Linux: ","type":"text"},{"text":"GitHub","type":"text","marks":[{"type":"link","attrs":{"href":"https://github.com/pwndbg/pwndbg","title":null}}]},{"text":", macOS: ","type":"text"},{"text":"brew install pwndbg/tap/pwndbg-gdb","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Additional Resources","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"tools.md","type":"text","marks":[{"type":"link","attrs":{"href":"tools.md","title":null}}]},{"text":" - Static analysis tools (GDB, Ghidra, radare2, IDA, Binary Ninja, dogbolt.org, RISC-V with Capstone, Unicorn emulation, Python bytecode, WASM, Android APK, .NET, packed binaries)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"tools-dynamic.md","type":"text","marks":[{"type":"link","attrs":{"href":"tools-dynamic.md","title":null}}]},{"text":" (includes Intel Pin instruction-counting side channel for movfuscated binaries, opcode-only trace reconstruction, LD_PRELOAD memcmp side-channel for byte-by-byte bruteforce) - Dynamic analysis tools: Frida (hooking, anti-debug bypass, memory scanning, Android/iOS), angr symbolic execution (path exploration, constraints, CFG), lldb (macOS/LLVM debugger), x64dbg (Windows), Qiling (cross-platform emulation with OS support), Triton (dynamic symbolic execution)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"tools-advanced.md","type":"text","marks":[{"type":"link","attrs":{"href":"tools-advanced.md","title":null}}]},{"text":" - Advanced tools: VMProtect/Themida analysis, binary diffing (BinDiff, Diaphora), deobfuscation frameworks (D-810, GOOMBA, Miasm), Rizin/Cutter, RetDec, custom VM bytecode lifting to LLVM IR, advanced GDB (Python scripting, conditional breakpoints, watchpoints, reverse debugging with rr, pwndbg/GEF), advanced Ghidra scripting, patching (Binary Ninja API, LIEF)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"anti-analysis.md","type":"text","marks":[{"type":"link","attrs":{"href":"anti-analysis.md","title":null}}]},{"text":" - Comprehensive anti-analysis: Linux anti-debug (ptrace, /proc, timing, signals, direct syscalls), Windows anti-debug (PEB, NtQueryInformationProcess, heap flags, TLS callbacks, HW/SW breakpoint detection, exception-based, thread hiding), anti-VM/sandbox (CPUID, MAC, timing, artifacts, resources), anti-DBI (Frida detection/bypass), code integrity/self-hashing, anti-disassembly (opaque predicates, junk bytes), MBA identification/simplification, SIGFPE signal handler side-channel via strace counting, call-less function chaining via stack frame manipulation, bypass strategies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"patterns.md","type":"text","marks":[{"type":"link","attrs":{"href":"patterns.md","title":null}}]},{"text":" - Foundational binary patterns: custom VMs, anti-debugging, nanomites, self-modifying code, XOR ciphers, mixed-mode stagers, LLVM obfuscation, S-box/keystream, SECCOMP/BPF, exception handlers, memory dumps, byte-wise transforms, x86-64 gotchas, signal-based exploration, malware anti-analysis, multi-stage shellcode, timing side-channel, multi-thread anti-debug with decoy + signal handler MBA, INT3 patch + coredump brute-force oracle, signal handler chain + LD_PRELOAD oracle","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"patterns-ctf.md","type":"text","marks":[{"type":"link","attrs":{"href":"patterns-ctf.md","title":null}}]},{"text":" - Competition-specific patterns (Part 1): hidden emulator opcodes, LD_PRELOAD key extraction, SPN static extraction, image XOR smoothness, byte-at-a-time cipher, mathematical convergence bitmap, Windows PE XOR bitmap OCR, two-stage RC4+VM loaders, kernel module maze solving, multi-threaded VM channels, backdoored shared library detection via string diffing, custom binfmt kernel module with RC4 flat binaries, hash-resolved imports / no-import ransomware, ELF section header corruption for anti-analysis","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"patterns-ctf-2.md","type":"text","marks":[{"type":"link","attrs":{"href":"patterns-ctf-2.md","title":null}}]},{"text":" - Competition-specific patterns (Part 2): multi-layer self-decrypting brute-force, embedded ZIP+XOR license, stack string deobfuscation, prefix hash brute-force, CVP/LLL lattice for integer validation, decision tree function obfuscation, GF(2^8) Gaussian elimination, ROP chain obfuscation analysis (ROPfuscation)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"patterns-ctf-3.md","type":"text","marks":[{"type":"link","attrs":{"href":"patterns-ctf-3.md","title":null}}]},{"text":" - Competition-specific patterns (Part 3): Z3 single-line Python circuit, sliding window popcount, keyboard LED Morse code via ioctl, C++ destructor-hidden validation, syscall side-effect memory corruption, MFC dialog event handlers, VM sequential key-chain brute-force, Burrows-Wheeler transform inversion, OpenType font ligature exploitation, GLSL shader VM with self-modifying code, instruction counter as cryptographic state, batch crackme automation via objdump, fork+pipe+dead branch anti-analysis, TensorFlow DNN inversion via sigmoid layer inversion, BPF filter analysis via kernel JIT to x64 assembly","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"languages.md","type":"text","marks":[{"type":"link","attrs":{"href":"languages.md","title":null}}]},{"text":" - Language-specific: Python bytecode & opcode remapping, Python version-specific bytecode, Pyarmor static unpack, DOS stubs, HarmonyOS HAP/ABC, Brainfuck/esolangs (+ BF character-by-character static analysis, BF side-channel read count oracle, BF comparison idiom detection), UEFI, transpilation to C, code coverage side-channel, OPAL functional reversing, non-bijective substitution, FRACTRAN program inversion","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"languages-platforms.md","type":"text","marks":[{"type":"link","attrs":{"href":"languages-platforms.md","title":null}}]},{"text":" - Platform/framework-specific: Rust serde_json schema recovery, Android JNI RegisterNatives obfuscation, Android DEX runtime bytecode patching via /proc/self/maps, Android native .so loading bypass via new project, Frida Firebase Cloud Functions bypass, Verilog/hardware RE, prefix-by-prefix hash reversal, Ruby/Perl polyglot constraint satisfaction, Electron ASAR extraction + native binary analysis, Node.js npm runtime introspection","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"languages-compiled.md","type":"text","marks":[{"type":"link","attrs":{"href":"languages-compiled.md","title":null}}]},{"text":" - Go binary reversing (GoReSym, goroutines, memory layout, channel ops, embed.FS, Go binary UUID patching for C2 enumeration), Rust binary reversing (demangling, Option/Result, Vec, panic strings), Swift binary reversing (demangling, protocol witness tables), Kotlin/JVM (coroutine state machines), Haskell GHC CMM intermediate language for recursive structure analysis, C++ (vtable reconstruction, RTTI, STL patterns)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"platforms.md","type":"text","marks":[{"type":"link","attrs":{"href":"platforms.md","title":null}}]},{"text":" - Platform-specific RE: macOS/iOS (Mach-O, code signing, Objective-C runtime, Swift, dyld, jailbreak bypass), embedded/IoT firmware (binwalk, UART/JTAG/SPI extraction, ARM/MIPS, RTOS), kernel drivers (Linux .ko, eBPF, Windows .sys), automotive CAN bus","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"platforms-hardware.md","type":"text","marks":[{"type":"link","attrs":{"href":"platforms-hardware.md","title":null}}]},{"text":" - Hardware and advanced architecture RE: HD44780 LCD controller GPIO reconstruction, RISC-V advanced (custom extensions, privileged modes, debugging), ARM64/AArch64 reversing and exploitation (calling convention, ROP gadgets, qemu-aarch64-static emulation)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"field-notes.md","type":"text","marks":[{"type":"link","attrs":{"href":"field-notes.md","title":null}}]},{"text":" - Quick reference notes: binary types, anti-debugging bypass, specialized patterns, CTF case notes","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to Pivot","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Heap / ROP / kernel exploit after the binary is understood → ","type":"text"},{"text":"pwn-chain/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deleted files / PCAP / disk artifacts → ","type":"text"},{"text":"digital-forensics/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Web app with a small client helper → ","type":"text"},{"text":"js-reverse/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Real malware / C2 / packing → ","type":"text"},{"text":"malware-analysis/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Multi-type CTF contest packaging → ","type":"text"},{"text":"ctf-sandbox/","type":"text","marks":[{"type":"code_inline"}]},{"text":" (sidecar orchestrator)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Problem-Solving Workflow","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Start with strings extraction","type":"text","marks":[{"type":"strong"}]},{"text":" - many easy challenges have plaintext flags","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Try ltrace/strace","type":"text","marks":[{"type":"strong"}]},{"text":" - dynamic analysis often reveals flags without reversing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Try Frida hooking","type":"text","marks":[{"type":"strong"}]},{"text":" - hook strcmp/memcmp to capture expected values without reversing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Try angr","type":"text","marks":[{"type":"strong"}]},{"text":" - symbolic execution solves many flag-checkers automatically","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Try Qiling","type":"text","marks":[{"type":"strong"}]},{"text":" - emulate foreign-arch binaries or bypass heavy anti-debug without artifacts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Map control flow","type":"text","marks":[{"type":"strong"}]},{"text":" before modifying execution","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Automate manual processes","type":"text","marks":[{"type":"strong"}]},{"text":" via scripting (r2pipe, Frida, angr, Python)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validate assumptions","type":"text","marks":[{"type":"strong"}]},{"text":" by comparing decompiler outputs (dogbolt.org for side-by-side)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Wins (Try First!)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Plaintext flag extraction\nstrings binary | grep -E \"flag\\{|CTF\\{|pico\"\nstrings binary | grep -iE \"flag|secret|password\"\nrabin2 -z binary | grep -i \"flag\"\n\n# Dynamic analysis - often captures flag directly\nltrace ./binary\nstrace -f -s 500 ./binary\n\n# Hex dump search\nxxd binary | grep -i flag\n\n# Run with test inputs\n./binary AAAA\necho \"test\" | ./binary","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Initial Analysis","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"file binary # Type, architecture\nchecksec --file=binary # Security features (for pwn)\nchmod +x binary # Make executable","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Memory Dumping Strategy","type":"text"}]},{"type":"paragraph","content":[{"text":"Key insight:","type":"text","marks":[{"type":"strong"}]},{"text":" Let the program compute the answer, then dump it. Break at final comparison (","type":"text"},{"text":"b *main+OFFSET","type":"text","marks":[{"type":"code_inline"}]},{"text":"), enter any input of correct length, then ","type":"text"},{"text":"x/s $rsi","type":"text","marks":[{"type":"code_inline"}]},{"text":" to dump computed flag.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Decoy Flag Detection","type":"text"}]},{"type":"paragraph","content":[{"text":"Pattern:","type":"text","marks":[{"type":"strong"}]},{"text":" Multiple fake targets before real check. Look for multiple comparison targets in sequence with different success messages. Set breakpoint at FINAL comparison, not earlier ones.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"GDB PIE Debugging","type":"text"}]},{"type":"paragraph","content":[{"text":"PIE binaries randomize base address. Use relative breakpoints:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"gdb ./binary\nstart # Forces PIE base resolution\nb *main+0xca # Relative to main\nrun","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Comparison Direction (Critical!)","type":"text"}]},{"type":"paragraph","content":[{"text":"Two patterns: (1) ","type":"text"},{"text":"transform(flag) == stored_target","type":"text","marks":[{"type":"code_inline"}]},{"text":" — reverse the transform. (2) ","type":"text"},{"text":"transform(stored_target) == flag","type":"text","marks":[{"type":"code_inline"}]},{"text":" — flag IS the transformed data, just apply transform to stored target.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Common Encryption Patterns","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"XOR with single byte - try all 256 values","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"XOR with known plaintext (","type":"text"},{"text":"flag{","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"CTF{","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"RC4 with hardcoded key","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Custom permutation + XOR","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"XOR with position index (","type":"text"},{"text":"^ i","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"^ (i & 0xff)","type":"text","marks":[{"type":"code_inline"}]},{"text":") layered with a repeating key","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Tool Reference","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Radare2\nr2 -d ./binary # Debug mode\naaa # Analyze\nafl # List functions\npdf @ main # Disassemble main\n\n# Ghidra (headless)\nanalyzeHeadless project/ tmp -import binary -postScript script.py\n\n# IDA\nida64 binary # Open in IDA64","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Deep-Dive Notes","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"field-notes.md","type":"text","marks":[{"type":"link","attrs":{"href":"field-notes.md","title":null}}]},{"text":" after the first round of triage when you know what kind of target you have.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Target formats: Python bytecode, WASM, Android, Flutter, .NET, UPX, Tauri","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Technique notes: anti-debug bypass, VM analysis, x86-64 gotchas, iterative solvers, Unicorn, timing side channels","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Platform notes: macOS/iOS, embedded firmware, kernel drivers, Swift, Kotlin, Go, Rust, D","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Case notes: modern CTF-specific reversing patterns and older classic challenge patterns","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"路由上下文","type":"text"}]},{"type":"paragraph","content":[{"text":"上游入口","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"skills/SKILL.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"(总控)、","type":"text"},{"text":"routing.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" ","type":"text"},{"text":"下游出口","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"需要 IDA 反编译 → ","type":"text"},{"text":"ida-reverse/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"需要 radare2 CLI 分析 → ","type":"text"},{"text":"radare2/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"需要 APK 层分析 → ","type":"text"},{"text":"apk-reverse/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"需要 Frida/angr 动态执行 → ","type":"text"},{"text":"tools-dynamic.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"需要绕过反调试 → ","type":"text"},{"text":"anti-analysis.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"遇到特定语言(Go/Rust/Python/WASM)→ ","type":"text"},{"text":"languages*.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"遇到 CTF 模式 → ","type":"text"},{"text":"patterns*.md","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"同级关联模块","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"apk-reverse/","type":"text","marks":[{"type":"code_inline"}]},{"text":"(APK 定位到 .so 时可切回本模块的 Frida/radare2 分支)","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"任务完成自检(声称完成前 MUST 通过)","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"我是否执行了工作流中的每一步(而不是只阅读)?","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"我是否基于 ","type":"text"},{"text":"tool-index","type":"text","marks":[{"type":"code_inline"}]},{"text":" 使用了真实工具路径?","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"我是否产出了可复现证据(命令/脚本/截图/报告)?","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"我是否完成并回写了 RULES 要求的 Checklist 项?","type":"text"}]}]}]}]},"metadata":{"date":"2026-11-02","name":"reverse-engineering","author":"@skillopedia","source":{"stars":43992,"repo_name":"reverse-skill","origin_url":"https://github.com/zhaoxuya520/reverse-skill/blob/HEAD/skills/reverse-engineering/SKILL.md","repo_owner":"zhaoxuya520","body_sha256":"7128b8445c61d41917eb28eb56c24c8ca2a3518b8b5b46c83137bf5e0b4935af","cluster_key":"4356457a516df6dcb72b78ad34d828756c845e8bbd7b9d736dfe21c953c810c4","clean_bundle":{"format":"clean-skill-bundle-v1","source":"zhaoxuya520/reverse-skill/skills/reverse-engineering/SKILL.md","text_bytes":459480,"source_commit":"cab634bd855fc287f6e420c1f36fd1a6b9245960","skills_sh_rank":8689,"attachment_count":23,"text_attachments":23,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/reverse-engineering/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"security","category_label":"Security"},"exact_dupes_collapsed_into_this":0},"license":"MIT","version":"v1","category":"security","metadata":{"user-invocable":"false"},"import_tag":"skills-sh-top20k-2026-11","description":"Provides reverse engineering techniques. Use when the main job is to understand how a compiled, obfuscated, packed, or virtualized target works before exploiting or solving it, including binaries, APKs, WASM, firmware, custom VMs, bytecode, malware-like loaders, and anti-debug or anti-analysis logic. Do not use it when the vulnerability is already understood and the remaining task is exploitation; use pwn instead. Do not use it for pure web workflows, log or disk forensics, or standalone crypto problems unless reversing the implementation is the real blocker.","allowed-tools":"Bash Read Write Edit Glob Grep Task WebFetch WebSearch","compatibility":"Requires a filesystem-based code agent or CLI with shell access, Python 3, and internet access for tool installation."}},"renderedAt":1793671127467}

Reverse Engineering ACTION REQUIRED(读完后立刻执行) 阶段门闩: (triage→static→dynamic→synthesis)。社区 RE skill 对照: 。 1. : 读取 — 确认本 skill 的操作是已授权的常规操作 2. : 确认当前任务是否命中本 skill 的适用范围 3. : 读取 ,校验工具可用性和实际路径 4. : 缺工具时调用 bootstrap,不要猜路径 5. : 按 re-agent-workflow 推进;进入工作流第一步并执行,不要停在确认状态 Decision-framework entry hook When triage cannot locate a reliable entry point, severe obfuscation blocks progress, or the analysis is stuck, keep this R0 workflow as the primary route and load the existing ADF overlay instead of creating a new PRIMARY. Follow for stage transitions and time-boxed replanning; at Synthesis or a stuck l…