$npx -y skills add meltedinhex/analyst-ai-pack --skill defeating-string-and-api-obfuscationRecovers obfuscated strings and resolves dynamically loaded APIs in malware:
| 1 | # Defeating String and API Obfuscation |
| 2 | |
| 3 | ## When to Use |
| 4 | |
| 5 | - A binary has few readable strings because they are XOR/stack-encoded or built at runtime. |
| 6 | - The import table is sparse because APIs are resolved by hash at runtime. |
| 7 | - You need to recover C2 URLs, paths, and the real API set to understand behavior. |
| 8 | |
| 9 | **Do not use** plain `strings` and conclude "no indicators" — modern malware hides strings; |
| 10 | absence of readable strings is itself a sign of obfuscation. |
| 11 | |
| 12 | ## Prerequisites |
| 13 | |
| 14 | - A disassembler/decompiler to read the decode routine, plus the bundled XOR/hash tooling. |
| 15 | - Optionally FLOSS for automated stack/decoded-string recovery. |
| 16 | |
| 17 | ## Workflow |
| 18 | |
| 19 | ### Step 1: Recognize the obfuscation type |
| 20 | |
| 21 | ```text |
| 22 | Stack strings : bytes mov'd to the stack one/few at a time, then used |
| 23 | Single-byte XOR: a loop XORing a buffer with a constant |
| 24 | Multi-byte/RC4 : a keyed stream over a blob |
| 25 | API hashing : a hash compared against export-name hashes to resolve functions |
| 26 | ``` |
| 27 | |
| 28 | ### Step 2: Recover XOR-encoded strings |
| 29 | |
| 30 | If you find the key and ciphertext, decode directly. The script brute-forces single-byte XOR |
| 31 | and surfaces readable results: |
| 32 | |
| 33 | ```bash |
| 34 | python scripts/analyst.py xor-strings sample.bin |
| 35 | ``` |
| 36 | |
| 37 | ### Step 3: Reconstruct stack strings |
| 38 | |
| 39 | Read the decompiler to collect the byte sequence assembled on the stack and reassemble it. For |
| 40 | volume, FLOSS emulates and extracts these automatically. |
| 41 | |
| 42 | ### Step 4: Resolve API hashing |
| 43 | |
| 44 | Identify the hash algorithm (often ROR13/ROR7 additive, or djb2). Precompute hashes for known |
| 45 | export names and match the constants in the binary back to functions: |
| 46 | |
| 47 | ```bash |
| 48 | python scripts/analyst.py api-hash --algo ror13 --hash 0x726774C |
| 49 | ``` |
| 50 | |
| 51 | ### Step 5: Reannotate and extract IOCs |
| 52 | |
| 53 | Apply recovered strings and API names back in the disassembler and extract the now-visible |
| 54 | URLs, paths, and behavior. |
| 55 | |
| 56 | ## Validation |
| 57 | |
| 58 | - Decoded strings are meaningful (URLs, DLL/API names, paths), not random bytes. |
| 59 | - Resolved API names match the calls' usage in the surrounding code. |
| 60 | - The recovered API set explains behavior seen dynamically. |
| 61 | |
| 62 | ## Pitfalls |
| 63 | |
| 64 | - Assuming single-byte XOR when it is keyed/RC4; check key length and the decode loop. |
| 65 | - Using the wrong hash algorithm/seed and getting no matches — verify against a known function. |
| 66 | - Recovering strings but not feeding them back into the analysis. |
| 67 | |
| 68 | ## References |
| 69 | |
| 70 | - See [`references/api-reference.md`](references/api-reference.md) for the XOR and API-hash |
| 71 | tools. |
| 72 | - FLOSS and API-hashing references (linked in frontmatter). |