
Un framework di API hooking per intercettare e monitorare le applicazioni Windows.
ApiScope è uno strumento di ricerca per Windows x64 che traccia chiamate API selezionate in un processo nuovo o già in esecuzione. Segue gli eventi di caricamento delle DLL tramite l'API del debugger di Windows e installa hook prima che il processo sottoposto a debug continui da ogni evento.
Hook inclusi:
ntdll.dll!NtCreateFile (registra il percorso di destinazione)ntdll.dll!NtOpenFile (registra il percorso di destinazione)ntdll.dll!NtReadFilentdll.dll!NtWriteFilentdll.dll!NtClosentdll.dll!NtOpenKey (registra il percorso della chiave)ntdll.dll!NtSetValueKeyntdll.dll!NtQueryValueKeybcrypt.dll!BCryptOpenAlgorithmProviderRequisiti:
cmake -S . -B build -A x64
cmake --build build --config Release
ctest --test-dir build -C Release --output-on-failure
powershell -ExecutionPolicy Bypass -File .\scripts\validate-apiscope-hooks.ps1 .\build\bin\Release\apiscope-hooks.dll
powershell -ExecutionPolicy Bypass -File .\scripts\smoke.ps1 -SkipBuild
Zydis v4.1.1 viene recuperato a un commit fisso e collegato solo in apiscope.exe. La DLL iniettata apiscope-hooks.dll rimane priva di import.
apiscope.exe [--help | --version | --list-hooks]
apiscope.exe run -k <module!export|all> [-k <module!export>] [-f text|jsonl] [-o <path>] [-q] -- <program> [args...]
apiscope.exe attach -p <pid> -k <module!export|all> [-k <module!export>] [-f text|jsonl] [-o <path>] [-q]
I nomi degli hook sono sempre qualificati dal modulo. La corrispondenza dei moduli non fa distinzione tra maiuscole e minuscole; la corrispondenza degli export fa distinzione tra maiuscole e minuscole.
.\apiscope.exe run `
--hook ntdll.dll!NtCreateFile `
--hook bcrypt.dll!BCryptOpenAlgorithmProvider `
-- C:\path\app.exe
.\apiscope.exe attach --pid 4242 --hook all
.\apiscope.exe run --hook all --format jsonl --output trace.jsonl --quiet -- app.exe
Gli eventi sul terminale rimangono leggibili mentre --output facoltativamente invia una copia del testo o JSONL su un file. --quiet sopprime il mirror degli eventi sul terminale. --color auto|always|never controlla il colore del terminale (default auto: attivo su una TTY, disattivato quando si usa una pipe o sotto NO_COLOR); il colore non compare mai nei file --output. Su una TTY, ApiScope mostra anche una barra di stato live (eventi, drop, velocità e conteggi per hook) che si ridisegna in posizione; controllala con --status auto|always|never.
[*] ntdll.dll!NtWriteFile ----------
timestamp : 2026-06-07T17:44:23.3834340Z
thread_id : 3508
sequence : 3
file_handle : 0x000000000000008C
length : 16
buffer_ascii : Hello, ApiScope!
result : STATUS_SUCCESS (0x00000000)
Gli eventi JSONL contengono metadati generici e campi specifici dell'hook:
{"schema_version":1,"sequence":1,"module":"bcrypt.dll","api":"BCryptOpenAlgorithmProvider","hook":"bcrypt.dll!BCryptOpenAlgorithmProvider","fields":{"flags":0,"result":"STATUS_SUCCESS (0x00000000)"}}
Vedi SCHEMA.md per l'involucro dell'evento e le codifiche dei campi per tipo (i puntatori e gli stati vengono mostrati come stringhe esadecimali 0x).
Premi Ctrl+C o Ctrl+Break per ripristinare gli hook attivi, rilasciare la strumentazione remota e scollegarti. Il processo target continua a essere eseguito. All'uscita naturale, ApiScope stampa lo stato del target in decimale ed esadecimale, seguito da un riepilogo della sessione (eventi, drop e conteggi per hook) su stderr.
NtCreateFile, NtOpenFile e NtOpenKey risolvono il path target da OBJECT_ATTRIBUTES e riportano l'handle risultante. ApiScope registra ogni apertura riuscita e annota le operazioni successive sullo stesso handle — letture, scritture, accesso ai valori del registro e la corrispondente NtClose — con il path risolto, così l'attività è leggibile senza dover tracciare manualmente gli handle. NtClose rimuove anche l'handle, e le aperture relative vengono risolte tramite un handle root_directory già visto in precedenza.
[*] ntdll.dll!NtCreateFile ----------
sequence : 2
path : test_file.txt
file_handle : 0x000000000000008C
result : STATUS_SUCCESS (0x00000000)
[*] ntdll.dll!NtReadFile ----------
sequence : 3
file_handle : 0x000000000000008C
buffer_ascii : Hello, ApiScope!
result : STATUS_SUCCESS (0x00000000)
path : test_file.txt
Il path negli eventi di lettura e scrittura viene correlato dall'handle, non osservato direttamente nella chiamata.
Ogni hook è un file in src/apiscope-hooks/hooks/ e dichiara insieme modulo sorgente, export, handler, slot del trampoline, convenzione di chiamata e firma:
DEFINE_API_HOOK(
BCryptOpenAlgorithmProvider,
"bcrypt.dll",
"BCryptOpenAlgorithmProvider",
NTSTATUS,
WINAPI,
PVOID* Algorithm,
const wchar_t* AlgorithmId,
const wchar_t* Implementation,
ULONG Flags) {
TraceEvent event;
InitializeTraceEvent(&event, "bcrypt.dll", "BCryptOpenAlgorithmProvider");
AddTraceUInt32(&event, "flags", Flags);
NTSTATUS result = CALL_ORIGINAL(
BCryptOpenAlgorithmProvider,
Algorithm,
AlgorithmId,
Implementation,
Flags);
AddTraceStatus(&event, "result", result);
EmitTraceEvent(&event);
return result;
}
apiscope.exe --list-hooks individua i descrittori a layout fisso esportati dalla DLL degli hook. Non è richiesto un elenco API centrale né uno schema eventi lato launcher.
sequenceDiagram
actor User
participant ApiScope as apiscope.exe
participant Debugger as Windows debugger API
participant Target as Target process
participant Modules as Loaded DLLs
participant Hooks as apiscope-hooks.dll
participant Ring as Shared-memory ring
User->>ApiScope: run program or attach PID
alt run
ApiScope->>Debugger: CreateProcess(DEBUG_ONLY_THIS_PROCESS)
else attach
ApiScope->>Debugger: DebugActiveProcess(PID)
end
ApiScope->>Debugger: DebugSetProcessKillOnExit(FALSE)
Debugger-->>ApiScope: CREATE_PROCESS_DEBUG_EVENT
ApiScope->>Target: Map import-free hook image
ApiScope->>Ring: Create and initialize bounded ring
ApiScope->>Target: Map shared section with NtMapViewOfSection