
Ein API-Hooking-Framework zum Abfangen und Überwachen von Windows-Anwendungen
ApiScope ist ein Windows x64-Forschungswerkzeug zur Verfolgung ausgewählter API-Aufrufe in einem neuen oder laufenden Prozess. Es folgt DLL-Ladeereignissen über die Windows-Debugger-API und installiert Hooks, bevor der Debuggee von jedem Ereignis fortfährt.
Enthaltene Hooks:
ntdll.dll!NtCreateFile (zeichnet den Zielpfad auf)ntdll.dll!NtOpenFile (zeichnet den Zielpfad auf)ntdll.dll!NtReadFilentdll.dll!NtWriteFilentdll.dll!NtClosentdll.dll!NtOpenKey (zeichnet den Schlüsselpfad auf)ntdll.dll!NtSetValueKeyntdll.dll!NtQueryValueKeybcrypt.dll!BCryptOpenAlgorithmProviderSehen Sie sich das MP4-Video an.
Voraussetzungen:
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 wird bei einem festgelegten Commit abgerufen und nur in apiscope.exe eingebunden. Die injizierte apiscope-hooks.dll bleibt importfrei.
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]
Hook-Namen sind immer modulqualifiziert. Die Modulübereinstimmung erfolgt case-insensitiv; die Exportübereinstimmung ist case-sensitiv.
.\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
Terminalereignisse bleiben lesbar, während --output optional Text oder JSONL in eine Datei umleitet. --quiet unterdrückt die Terminalereignisspiegelung. --color auto|always|never steuert die Terminalfarbe (Standard auto: an für ein TTY, aus bei Weiterleitung oder unter NO_COLOR); Farbe erscheint nie in --output-Dateien. Auf einem TTY zeigt ApiScope auch eine Live-Statusfußzeile (Ereignisse, Verluste, Rate und Pro-Hook-Zählungen), die an Ort und Stelle neu gezeichnet wird; steuern Sie es mit --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)
JSONL-Ereignisse enthalten generische Metadaten und hook-lokale Felder:
{"schema_version":1,"sequence":1,"module":"bcrypt.dll","api":"BCryptOpenAlgorithmProvider","hook":"bcrypt.dll!BCryptOpenAlgorithmProvider","fields":{"flags":0,"result":"STATUS_SUCCESS (0x00000000)"}}
Siehe SCHEMA.md für den Ereignisumschlag und die feldspezifischen Kodierungen (Zeiger und Status werden als 0x Hex-Strings dargestellt).
Drücken Sie Strg+C oder Strg+Untbrechen, um aktive Hooks wiederherzustellen, die entfernte Instrumentierung freizugeben und abzutrennen. Das Ziel läuft weiter. Bei natürlichem Beenden gibt ApiScope den Zielstatus in Dezimal und Hexadezimal aus, gefolgt von einer Sitzungszusammenfassung (Ereignisse, Verluste und Pro-Hook-Zählungen) auf stderr.
NtCreateFile, NtOpenFile und NtOpenKey lösen den Ziel-path aus OBJECT_ATTRIBUTES auf und melden das resultierende Handle. ApiScope zeichnet jedes erfolgreiche Öffnen auf und annotiert spätere Operationen auf demselben Handle – Lesevorgänge, Schreibvorgänge, Registrierungswertzugriffe und das passende NtClose – mit dem aufgelösten path, sodass die Aktivität ohne manuelle Handle-Verfolgung lesbar ist. NtClose entfernt auch das Handle, und relative Öffnungen werden über ein zuvor gesehenes root_directory-Handle aufgelöst.
[*] 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
Der path bei Lese- und Schreibereignissen wird vom Handle abgeleitet, nicht beim Aufruf selbst beobachtet.
Jeder Hook ist eine Datei unter src/apiscope-hooks/hooks/ und deklariert sein Quellmodul, Export, Handler, Trampolin-Slot, Aufrufkonvention und Signatur gemeinsam:
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 erkennt Deskriptoren mit festem Layout, die von der Hook-DLL exportiert werden. Es ist keine zentrale API-Liste oder ein launcherseitiges Ereignisschema erforderlich.
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
loop CREATE_PROCESS / LOAD_DLL events
Debugger-->>ApiScope: Module base and file handle
ApiScope->>Modules: Register module name and base
alt ntdll.dll loaded
ApiScope->>Target: Build unpatched NtReadVirtualMemory bypass
end
ApiScope->>Modules: Resolve module.dll!Export and forwarders
alt export and dependencies are loaded
ApiScope->>Hooks: Resolve handler and trampoline slot
ApiScope->>Target: Allocate trampoline and patch export
else dependency is not loaded yet
ApiScope->>ApiScope: Keep hook pending
end
ApiScope->>Debugger: ContinueDebugEvent
end