Skip to content
166 changes: 165 additions & 1 deletion .gemini/skills/capemon-developer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Integration of YARA for in-memory scanning
- **Platform:** Windows (x86 and x64).
- **Hooking Method:** Inline hooking of Win32 and Native APIs (NTAPI).
- **Debugger:** Native in-process 'self' debugging utilising minimal OS interfaces & hardware capabilities (breakpoint, single-step)
- **Dependencies:**
- **Dependencies:**
- `distorm` for instruction decoding.
- `libyara` for pattern matching.
- `Scylla` for PE reconstruction.
Expand All @@ -65,6 +65,170 @@ Integration of YARA for in-memory scanning
## Engineering & Documentation Mandates
- **Always update `@docs/configuration.md`:** Whenever a new configurable option is introduced to the engine (such as `log-format`, `sleep-skip-seconds`, etc.), you must immediately append its documentation details to the appropriate table inside the configuration reference document to ensure the user and the system documentation are fully up-to-date.

## Critical System Constraints & OS-Level Design Rules

**Verify Injection Context:** `capemon` is dynamically loaded post-startup via `LoadLibrary`/`LdrLoadDll`, not during process initialization. This context affects every C feature, compiler directive, and dependency you choose.

### Memory & Thread Locality

- **Never use `__declspec(thread)` for data structures in post-loaded DLLs.** Static TLS is allocated at process load time and causes crashes/corruption when DLLs are injected post-startup. Use dynamic Windows TLS APIs (`TlsAlloc`, `TlsGetValue`, `TlsSetValue`, `TlsFree`) for actual context data.
- *Pointer caching is safe:* `static __declspec(thread) ctx_t* g_tls_cache = NULL;` with NULL-fallback to `TlsGetValue()` is a valid performance optimization (avoids repeated API calls on hot path).
- **NEVER allocate heap memory in hot-path hooks.** A hook running in all threads can deadlock if another thread holds the heap lock. Use stack allocation, Small Buffer Optimization (SBO), or pre-allocated TLS instead.
- **NEVER call hooked APIs inside hook callbacks.** Recursion causes stack overflow. Always call the original function pointer (e.g., `Old_FunctionName()`).

### Hook Architecture

- **Consolidate hooks inside existing gateways.** Don't install a new hook if filtering logic can go into `NtOpenKey`, `NtCreateFile`, or other core APIs already hooked. Every new hook thrashes the I-Cache and increases deadlock surface.
- **Respect calling conventions exactly.** Match Windows SDK signatures: `__stdcall`, `__fastcall`, `__cdecl`. Don't modify volatile registers (`ECX`/`EDX` on x86, `RCX`/`RDX` on x64) unless spoofing a return value.

### Behavioral Fidelity

- **Match Windows error behavior exactly.** If native Windows returns `WBEM_E_NOT_FOUND` for a bad query, the hook must too. Malware probes for mock behavior by sending invalid input; mismatched responses reveal the sandbox.
- **Avoid static hardware configs.** Don't spoof the same L1/L2/L3 cache size, or return identical core counts. Use stateless deterministic hashing (e.g., `(ULONG_PTR)_this >> 4 % N`) to simulate realistic hardware variation.
- **Verify under identical test VMs.** Before optimizing spin-retries, locks, or buffers, verify re-entrancy, recursive thread calls, and `va_list` lifecycles on the target environment.

### COM & Virtual Table Hooking

- **Account for vtable offset variance.** COM interfaces across OS versions and MSVC versions have shifting offsets. Protect with SEH blocks and pointer-validation checks (`IsBadReadPtr`-like probes).
- **Use self-propagating COM chains.** For dynamically-instantiated interfaces without symbol exports (Windows 10/11), hook the creator (e.g., `IWbemServices`), then intercept returned objects (e.g., `IEnumWbemClassObject`) to hook their vtables on-the-fly.
- **Match calling conventions for COM methods:** x86 COM methods (e.g., `ICorJitInfo::getMethodName`) use `__thiscall` where `this` is passed in `ECX`, not `__stdcall`. Using wrong convention causes stack imbalance: callee cleans wrong stack frame → ESP corruption → crash. On x86, typedef function pointers as `__thiscall`; on x64, use `__fastcall`. Always validate vtable pointers and method parameters with `IsBadReadPtr` before calling CLR/COM vtables.

### Pull Request Discipline

- **Split unrelated fixes into separate surgical PRs.** Don't consolidate evasion fixes for al-khaser, anticuckoo, ACPI, PCI, and NtYieldExecution in one PR. Modular reviews guarantee correctness and frictionless merges.

### Code Preservation & Intellectual Debt

- **Never delete comments with research citations.** Developer comments contain malware hashes, CVE references, and GitHub repository links. When refactoring, migrate citations cleanly to keep the codebase traceable and educational.

## Common Crash Patterns & Prevention

### Crash 1: Static TLS Corruption in Post-Loaded DLLs

**Symptoms:** Immediate crash or stack corruption during early logging or thread-local operations.

**Root Cause:** Using `__declspec(thread)` to store data structures (not pointers) in a DLL loaded post-startup. Static TLS is allocated by the OS loader at process init; dynamic injection skips this initialization, leading to memory corruption.

**Example:** `static __declspec(thread) bson g_bson[1];` → **CRASH**

**Fix:** Use dynamic Windows TLS APIs for actual data:
```c
// g_bson → stored via TlsSetValue(g_bson_tls_index, context)
// Macro accessor: #define g_bson (ctx ? ctx->g_bson : NULL)
// Fallback: IsBadReadPtr checks before access
```

### Crash 2: Calling Convention Mismatch (`__thiscall` vs `__stdcall`)

**Symptoms:** ESP corruption, immediate crash, or delayed stack corruption inside hooked COM methods.

**Root Cause:** x86 COM methods (e.g., `ICorJitInfo::getMethodName`) use `__thiscall` (this in ECX), not `__stdcall`. Wrong convention = arguments on stack instead of registers → callee cleans wrong frame size → ESP corrupted.

**Example:** `typedef const char* (__stdcall *fn)(PVOID _this, ...)` on x86 → **CRASH**

**Fix:** Architecture-specific function pointers:
```c
#if defined(_M_IX86)
typedef const char* (__thiscall *fn)(PVOID _this, PVOID ftn, ...);
#else
typedef const char* (__fastcall *fn)(PVOID _this, PVOID ftn, ...);
#endif
```

### Crash 3: Heap Allocation Under Lock (Re-entrancy Deadlock)

**Symptoms:** Process freezes, all threads block, no exception. Debugger shows one thread holds heap lock, another waits on hook callback that needs heap alloc.

**Root Cause:** Hook runs in all threads. If hook allocates heap (`malloc`, `HeapAlloc`), and another thread holds the heap lock, deadlock. Cannot be caught by SEH; freezes the process.

**Example:**
```c
void hook_callback() {
EnterCriticalSection(&g_mutex);
char *buf = malloc(256); // ← DEADLOCK if another thread holds heap lock
}
```

**Fix:** Use stack allocation or pre-allocated TLS only:
```c
void hook_callback() {
char buf[256]; // stack: always safe
// or
thread_ctx_t *ctx = TlsGetValue(g_tls_index); // pre-allocated
}
```

## Synchronization & Lock Safety

- **Use critical sections only for slow-path operations.** Locks block all threads in the process. Minimize hold time; never call complex functions (API calls, allocations) inside critical sections.
- **Establish a global lock ordering.** If hook A acquires `lock1` then `lock2`, every other code path must acquire locks in the same order. Document lock hierarchy comments in code.
- **Never nest locks on the same thread.** If you hold `g_mutex`, don't try to acquire it again on the same thread. Use `TryEnterCriticalSection` with fallback logic, not blocking re-entry.
- **Protect shared state, not code regions.** Only lock access to shared memory (counters, caches, vtables), not entire operations. Release the lock immediately after modifying shared data.

## Stack-Based Allocation (SBO) Pattern

**Rule:** In hook callbacks, always use **stack allocation**, not heap.

**Why:** Hooks run in all threads. If a callback does `malloc()` and another thread holds the heap lock, re-entrancy deadlock (process freeze, no exception).

**Pattern:**
```c
// Good: stack-based, bounded
static void log_value(const char *name, int value) {
char buf[256]; // bounded stack
snprintf(buf, sizeof(buf), "%s=%d", name, value);
}

// Bad: heap allocation in hook
void hook_callback() {
char *buf = malloc(1024); // ← DEADLOCK risk
}

// Good: Small Buffer Optimization (SBO)
// Pre-allocate thread-local context once, reuse in all callbacks
thread_ctx_t *ctx = TlsGetValue(g_tls_index); // cached pointer
if (ctx) {
snprintf(ctx->buf, sizeof(ctx->buf), ...); // reuse pre-allocated
}
```

**Verification:** Before committing hook code, grep for `malloc`, `calloc`, `HeapAlloc` inside hook callbacks. If found, refactor to stack or pre-allocated TLS.

## Design Decision & Thinking Frameworks

### Pre-Implementation Checklist

**API Fidelity:**
- Exact Windows SDK specification (legal, illegal, undocumented return values)?
- Does the hook break multi-threading, cause spinlocks, or starve CPU cores?
- Will malware detect this as a mock (invalid input probing, timing, memory watches)?

**Architecture & Performance:**
- Can this consolidate into an existing hook (e.g., `NtOpenKey`), or does it need a new trampoline?
- Is the callback re-entrancy safe? (heap-safe, stack buffers only, TLS-backed)
- Does it handle x86/x64 calling conventions cleanly?

**Logging & Completeness:**
- What gets logged—exact argument names, values, state transitions for accurate behavior timeline reconstruction?
- Is the log noise-free? (Set caps, e.g., max 20 exception queries, to prevent expansion attacks)

### Four-Persona Challenge Framework

Challenge every hook/bypass proposal by asking:

| Persona | Key Questions |
|---------|---|
| **OS/Kernel Dev** | What's the exact API spec? Does this break multi-threading or cause CPU starvation? |
| **Malware Author** | How do I detect this mock? Via invalid probes, timing, or memory watches? Can I bypass via direct syscalls? |
| **Capemon Dev** | Should this consolidate into an existing hook? Is it re-entrancy safe? x86/x64 compatible? |
| **Security Analyst** | Is logging complete (names, values, state)? Are there safeguards against infinite expansion? |

### Critical Thinking Mandates

- **Deadlock & Starvation Check:** Before blocking/skipping any syscall, simulate downstream consequences. Will multi-threaded programs or Windows libraries deadlock or starve?
- **Arch Generalization Rule:** If code is `#ifdef _WIN64` or `#ifdef _X86_`, question why. If the fix applies equally to both, refactor to support both cleanly.
- **Historical Debt Preservation:** Never delete comments with malware hashes, CVEs, or repo links. These are research artifacts; migrate them cleanly during refactors.

## Build & Compilation Guide

### 1. Locating MSBuild
Expand Down