> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/JoasASantos/SysWhispers4/llms.txt
> Use this file to discover all available pages before exploring further.

# RecycledGate

> Hybrid SSN resolution combining FreshyCalls sorting with opcode validation

## Overview

RecycledGate represents the **most resilient** SSN resolution technique available in SysWhispers4, combining the hook-resistant VA-sorting of [FreshyCalls](/advanced/freshycalls) with opcode validation from Hell's Gate. This dual-verification approach provides maximum confidence even in hostile environments.

<Tip>
  Use RecycledGate when you need **highest confidence** in SSN accuracy without the performance cost of [SyscallsFromDisk](/advanced/syscalls-from-disk).
</Tip>

## The Core Insight

RecycledGate asks: **What if we could get the benefits of both approaches?**

* **FreshyCalls**: Works when hooks modify opcodes, but relies on export table accuracy
* **Hell's Gate**: Works when export table is clean, but fails on hooked opcodes

**Solution**: Use FreshyCalls as the **primary** source, Hell's Gate as **validation** when possible:

```
IF stub is clean (no hook detected):
    ssn_freshycalls = sorted_index
    ssn_opcode = read_mov_eax_instruction()
    
    IF ssn_freshycalls == ssn_opcode:
        RETURN ssn_freshycalls  // Double-confirmed!
    ELSE:
        RETURN ssn_freshycalls  // Trust VA sort over potentially-tampered opcode
ELSE (stub is hooked):
    RETURN ssn_freshycalls      // Opcode is garbage, VA sort is authoritative
```

## Algorithm

### Step-by-Step Process

<Steps>
  <Step title="Sort by Virtual Address (FreshyCalls)">
    Parse `ntdll.dll` export table and sort all `Nt*` functions by VA:

    ```c theme={null}
    // Collect exports
    SW4_EXPORT* ntExports = parse_ntdll_exports(pNtdll);

    // Sort ascending by address
    qsort(ntExports, ntCount, sizeof(SW4_EXPORT), compare_va);

    // Index = candidate SSN
    for (i = 0; i < ntCount; i++) {
        candidate_ssn[ntExports[i].Hash] = i;
    }
    ```
  </Step>

  <Step title="Check for Hooks (Pattern Detection)">
    Inspect the first few bytes of each stub for common EDR hook patterns:

    ```c theme={null}
    BOOL is_hooked(PVOID addr) {
        PBYTE code = (PBYTE)addr;
        
        // E9 xx xx xx xx — near JMP
        if (code[0] == 0xE9) return TRUE;
        
        // FF 25 xx xx xx xx — far JMP [rip+offset]
        if (code[0] == 0xFF && code[1] == 0x25) return TRUE;
        
        // EB xx — short JMP
        if (code[0] == 0xEB) return TRUE;
        
        // CC — INT3 breakpoint
        if (code[0] == 0xCC) return TRUE;
        
        // E8 xx xx xx xx — CALL (rare)
        if (code[0] == 0xE8) return TRUE;
        
        return FALSE;  // Appears clean
    }
    ```
  </Step>

  <Step title="Opcode Validation (When Clean)">
    If the stub appears unhoooked, read the SSN from opcodes:

    ```c theme={null}
    if (!is_hooked(funcAddr)) {
        PBYTE code = (PBYTE)funcAddr;
        
        // Expected: 4C 8B D1 B8 [SSN_lo] [SSN_hi] 00 00
        if (code[0] == 0x4C && code[1] == 0x8B && code[2] == 0xD1 &&
            code[3] == 0xB8) {
            DWORD ssn_opcode = *(DWORD*)(code + 4);
            
            // Cross-check with FreshyCalls
            if (ssn_opcode == candidate_ssn[hash]) {
                SW4_SsnTable[idx] = ssn_opcode;  // Verified!
            } else {
                // Mismatch — trust FreshyCalls
                SW4_SsnTable[idx] = candidate_ssn[hash];
            }
        }
    } else {
        // Stub is hooked — use FreshyCalls exclusively
        SW4_SsnTable[idx] = candidate_ssn[hash];
    }
    ```
  </Step>

  <Step title="Handle Edge Cases">
    For stubs that are hooked, rely solely on the VA-sort index:

    ```c theme={null}
    // Even if ALL stubs are hooked, RecycledGate still works
    // because FreshyCalls doesn't require clean opcodes
    for (i = 0; i < ntCount; i++) {
        if (is_hooked(ntExports[i].Address)) {
            // Trust sorted index
            SW4_SsnTable[idx] = i;
        }
    }
    ```
  </Step>
</Steps>

## Full Implementation

```c theme={null}
BOOL SW4_RecycledGate(PVOID pNtdll) {
    // Phase 1: FreshyCalls — sort by VA
    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pNtdll;
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((PBYTE)pNtdll + dos->e_lfanew);
    PIMAGE_EXPORT_DIRECTORY exports = 
        (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pNtdll + 
        nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    PDWORD nameRvas = (PDWORD)((PBYTE)pNtdll + exports->AddressOfNames);
    PDWORD funcRvas = (PDWORD)((PBYTE)pNtdll + exports->AddressOfFunctions);
    PWORD ordinals = (PWORD)((PBYTE)pNtdll + exports->AddressOfNameOrdinals);

    SW4_EXPORT* ntExports = (SW4_EXPORT*)calloc(exports->NumberOfNames, sizeof(SW4_EXPORT));
    DWORD ntCount = 0;

    for (DWORD i = 0; i < exports->NumberOfNames; i++) {
        PCHAR name = (PCHAR)((PBYTE)pNtdll + nameRvas[i]);
        if (name[0] == 'N' && name[1] == 't') {
            DWORD funcRva = funcRvas[ordinals[i]];
            ntExports[ntCount].Address = (PVOID)((PBYTE)pNtdll + funcRva);
            ntExports[ntCount].Hash = djb2_hash(name);
            ntCount++;
        }
    }

    qsort(ntExports, ntCount, sizeof(SW4_EXPORT), compare_va);

    // Phase 2: Cross-validation with opcode reading
    for (DWORD i = 0; i < ntCount; i++) {
        PVOID addr = ntExports[i].Address;
        DWORD hash = ntExports[i].Hash;
        DWORD ssn_candidate = i;  // FreshyCalls SSN

        // Find matching function in our table
        DWORD funcIdx = 0xFFFFFFFF;
        for (DWORD j = 0; j < SW4_FUNC_COUNT; j++) {
            if (SW4_FunctionHashes[j] == hash) {
                funcIdx = j;
                break;
            }
        }
        if (funcIdx == 0xFFFFFFFF) continue;

        // Check if stub is hooked
        PBYTE code = (PBYTE)addr;
        BOOL hooked = (code[0] == 0xE9 || code[0] == 0xCC || code[0] == 0xEB ||
                       (code[0] == 0xFF && code[1] == 0x25) || code[0] == 0xE8);

        if (!hooked) {
            // Validate with Hell's Gate opcode read
            if (code[0] == 0x4C && code[1] == 0x8B && code[2] == 0xD1 &&
                code[3] == 0xB8) {
                DWORD ssn_opcode = *(DWORD*)(code + 4);
                
                if (ssn_opcode == ssn_candidate) {
                    // Perfect match — double-verified!
                    SW4_SsnTable[funcIdx] = ssn_opcode;
                } else {
                    // Mismatch — VA sort is more reliable
                    SW4_SsnTable[funcIdx] = ssn_candidate;
                }
            } else {
                // Unexpected opcode pattern — trust VA sort
                SW4_SsnTable[funcIdx] = ssn_candidate;
            }
        } else {
            // Stub is hooked — FreshyCalls is authoritative
            SW4_SsnTable[funcIdx] = ssn_candidate;
        }
    }

    free(ntExports);
    return TRUE;
}
```

## Advantages

<CardGroup cols={2}>
  <Card title="Dual Verification" icon="shield-check">
    SSNs are cross-validated when possible, maximizing confidence in results
  </Card>

  <Card title="Hook Resistant" icon="shield-halved">
    Works even if 100% of stubs are hooked — FreshyCalls provides fallback
  </Card>

  <Card title="Opcode Anomaly Detection" icon="triangle-exclamation">
    Detects discrepancies between VA-sort and opcodes (EDR tampering indicators)
  </Card>

  <Card title="Fast" icon="gauge-high">
    Minimal overhead vs. FreshyCalls (\~3-5ms vs. \~2ms) — much faster than SyscallsFromDisk
  </Card>
</CardGroup>

## Use Cases

### Scenario 1: Partially Hooked NTDLL

EDR hooks 20% of `Nt*` functions:

```
NtAllocateVirtualMemory:  Clean   → VA-sort: 0x18, Opcode: 0x18 ✅ Verified
NtCreateThreadEx:         Hooked  → VA-sort: 0xC2 ✅ Trusted (opcode garbage)
NtWriteVirtualMemory:     Clean   → VA-sort: 0x3A, Opcode: 0x3A ✅ Verified
NtProtectVirtualMemory:   Hooked  → VA-sort: 0x50 ✅ Trusted
```

**Result**: All SSNs correct, 80% double-verified.

### Scenario 2: Sophisticated EDR

EDR modifies export table **and** hooks stubs:

```
Export table VA order:    [Possibly tampered]
Opcode bytes:             [Hooked with E9 JMP]

RecycledGate:             VA-sort still reflects true stub layout
                          Opcode validation skipped (hooks detected)
                          ✅ Correct SSNs from VA-sort
```

**Result**: Still works — FreshyCalls component is export-table-independent at the VA level.

### Scenario 3: Clean NTDLL

No hooks present (testing, early-stage payload):

```
All stubs clean → 100% of SSNs double-verified (VA + opcode)
→ Maximum confidence in results
```

## Performance Analysis

| Operation           |     Time    | Notes                                             |
| ------------------- | :---------: | ------------------------------------------------- |
| Export table parse  |    \~1ms    | Same as FreshyCalls                               |
| qsort (VA ordering) |    \~1ms    | Same as FreshyCalls                               |
| Hook detection      |    \~1ms    | Simple byte checks                                |
| Opcode validation   |    \~1ms    | Only for clean stubs                              |
| Cross-check logic   |    \<1ms    | Comparison arithmetic                             |
| **Total**           | **\~4-5ms** | \~2x FreshyCalls, 3x faster than SyscallsFromDisk |

<Info>
  Performance impact is negligible — occurs once during `SW4_Initialize()`. Subsequent syscalls are full-speed.
</Info>

## Comparison with Alternatives

| Feature               |  FreshyCalls  |     RecycledGate     | SyscallsFromDisk |   HW Breakpoint  |
| --------------------- | :-----------: | :------------------: | :--------------: | :--------------: |
| **Hook Resistance**   |   Very High   |      **Maximum**     |    **Maximum**   |    **Maximum**   |
| **Verification**      |  Single (VA)  | **Dual (VA+Opcode)** |  Single (Opcode) | Single (Runtime) |
| **Speed**             |  Fast (\~2ms) |   **Fast (\~5ms)**   |   Slow (\~15ms)  |   Slow (\~20ms)  |
| **Complexity**        |      Low      |      **Medium**      |      Medium      |       High       |
| **Anomaly Detection** |       ❌       |         **✅**        |         ❌        |         ❌        |
| **Export Tampering**  | ⚠️ Vulnerable |     ⚠️ Vulnerable    |     ✅ Immune     |     ✅ Immune     |

## Limitations

### Export Table Manipulation

If an EDR **reorders the export directory RVAs** to break VA-sorting (extremely rare — would break legitimate API resolution), RecycledGate is defeated:

```c theme={null}
// Hypothetical attack: EDR swaps export RVAs
exports->AddressOfFunctions[NtAlloc_index] = trampoline_rva;  // Points elsewhere
exports->AddressOfFunctions[NtCreate_index] = original_NtAlloc_rva;
```

**Mitigation**: Use [SyscallsFromDisk](/advanced/syscalls-from-disk), which maps clean ntdll from `\KnownDlls\`.

### Opcode Pattern Changes

Future Windows versions may change the syscall stub prologue:

```asm theme={null}
; Current x64 stub (Win7-Win11):
4C 8B D1              mov r10, rcx
B8 XX XX 00 00        mov eax, <SSN>
0F 05                 syscall
C3                    ret

; Hypothetical future change:
XX XX XX XX XX        <new prologue>
B8 XX XX 00 00        mov eax, <SSN>
...
```

**Impact**: Opcode validation would fail, but **FreshyCalls fallback** ensures SSNs are still resolved.

## When to Use RecycledGate

<AccordionGroup>
  <Accordion title="Ideal Scenarios" icon="circle-check">
    * **High-security targets** with sophisticated EDRs
    * **Verification-critical operations** (privilege escalation, persistence)
    * **Partial hook environments** (maximizes validation coverage)
    * **Performance-sensitive** but paranoia-required contexts (faster than SyscallsFromDisk)
    * **Anomaly detection desired** — mismatch between VA/opcode signals tampering
  </Accordion>

  <Accordion title="Overkill For" icon="triangle-exclamation">
    * **CTF challenges** — FreshyCalls is sufficient
    * **Testing environments** without EDR — Static resolution is faster
    * **Sandboxed contexts** — if KnownDlls blocked, no advantage over FreshyCalls
  </Accordion>
</AccordionGroup>

## Usage in SysWhispers4

### Generate with RecycledGate

```bash theme={null}
# Basic usage
python syswhispers.py --preset injection --resolve recycled

# Recommended: combine with obfuscation and indirect invocation
python syswhispers.py --preset stealth \
    --resolve recycled \
    --method randomized \
    --obfuscate \
    --encrypt-ssn \
    --stack-spoof

# Maximum evasion (all techniques)
python syswhispers.py --preset stealth \
    --resolve recycled \
    --method randomized \
    --obfuscate --encrypt-ssn --stack-spoof \
    --etw-bypass --amsi-bypass --unhook-ntdll \
    --anti-debug --sleep-encrypt
```

### Integration Example

```c theme={null}
#include "SW4Syscalls.h"

int main(void) {
    // Optional: remove hooks first for maximum validation coverage
    SW4_UnhookNtdll();

    // Initialize with RecycledGate
    if (!SW4_Initialize()) {
        fprintf(stderr, "[!] RecycledGate initialization failed\n");
        return 1;
    }

    printf("[+] SSNs resolved via RecycledGate (VA-sort + opcode validation)\n");

    // Optional: anti-debugging check
    if (!SW4_AntiDebugCheck()) {
        fprintf(stderr, "[!] Debugger detected\n");
        return 0;
    }

    // Use syscalls with high confidence in SSN accuracy
    PVOID base = NULL;
    SIZE_T size = 0x1000;
    NTSTATUS st = SW4_NtAllocateVirtualMemory(
        GetCurrentProcess(), &base, 0, &size,
        MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE
    );

    if (NT_SUCCESS(st)) {
        printf("[+] Memory allocated at 0x%p\n", base);
        
        // Use sleep encryption during idle
        SW4_SleepEncrypt(5000);  // .text encrypted during sleep
        
        SW4_NtFreeVirtualMemory(GetCurrentProcess(), &base, &size, MEM_RELEASE);
    }

    return NT_SUCCESS(st) ? 0 : 1;
}
```

## Detection Considerations

### Observable Behaviors

1. **Export table enumeration** — common, not inherently suspicious
2. **Opcode reading** — may trigger memory scanning alerts
3. **Hook detection logic** — pattern matching via byte checks

### EDR Visibility

| Action             | Kernel Visibility | User-Mode Visibility |
| ------------------ | :---------------: | :------------------: |
| Parse export table |         ❌         |    ❌ (in-process)    |
| qsort VA list      |         ❌         |    ❌ (in-process)    |
| Read stub opcodes  |   ⚠️ (possible)   |     ✅ (if hooked)    |
| Syscall execution  |     ✅ (ETW-Ti)    |  ❌ (hooks bypassed)  |

### Best Practices

<Steps>
  <Step title="Combine with indirect invocation">
    Keep RIP inside ntdll during syscalls:

    ```bash theme={null}
    python syswhispers.py --resolve recycled --method randomized
    ```
  </Step>

  <Step title="Enable obfuscation">
    Randomize stub order and inject junk instructions:

    ```bash theme={null}
    python syswhispers.py --resolve recycled --obfuscate
    ```
  </Step>

  <Step title="Use ntdll unhooking">
    Remove hooks before RecycledGate runs:

    ```c theme={null}
    SW4_UnhookNtdll();  // Clean ntdll
    SW4_Initialize();    // All stubs clean → 100% validated
    ```
  </Step>
</Steps>

## Further Reading

<CardGroup cols={2}>
  <Card title="FreshyCalls" icon="sort" href="/advanced/freshycalls">
    The VA-sorting technique at RecycledGate's core
  </Card>

  <Card title="Hell's Gate" icon="fire" href="/concepts/ssn-resolution#hells-gate">
    Opcode reading technique used for validation
  </Card>

  <Card title="SyscallsFromDisk" icon="hard-drive" href="/advanced/syscalls-from-disk">
    Alternative when export table tampering suspected
  </Card>

  <Card title="Original Research" icon="link" href="https://github.com/thefLink/RecycledGate">
    RecycledGate by thefLink
  </Card>
</CardGroup>
