
Un framework de hooking de API para interceptar y monitorear aplicaciones de Windows.
ApiScope es una herramienta de investigación para Windows x64 que permite rastrear llamadas API seleccionadas en un proceso nuevo o en ejecución. Sigue los eventos de carga de DLL a través de la API del depurador de Windows e instala hooks antes de que el proceso depurado continúe desde cada evento.
Hooks incluidos:
ntdll.dll!NtCreateFile (registra la ruta de destino)ntdll.dll!NtOpenFile (registra la ruta de destino)ntdll.dll!NtReadFilentdll.dll!NtWriteFilentdll.dll!NtClosentdll.dll!NtOpenKey (registra la ruta de la clave)ntdll.dll!NtSetValueKeyntdll.dll!NtQueryValueKeybcrypt.dll!BCryptOpenAlgorithmProviderRequisitos:
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 se descarga en un commit fijado y se enlaza únicamente en
apiscope.exe. El apiscope-hooks.dll inyectado permanece libre de imports.
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]
Los nombres de hooks siempre están calificados por módulo. La coincidencia de módulos no distingue entre mayúsculas y minúsculas; la coincidencia de exports sí distingue entre mayúsculas y minúsculas.
.\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
Los eventos de terminal permanecen legibles mientras que --output opcionalmente
duplica texto o JSONL a un archivo. --quiet suprime el espejo de eventos en la
terminal. --color auto|always|never controla el color de la terminal (por defecto
auto: activo en una TTY, desactivado cuando se redirige o bajo NO_COLOR); el
color nunca aparece en los archivos de --output. En una TTY, ApiScope también
muestra un pie de estado en vivo (eventos, descartes, tasa y contadores por hook)
que se redibuja en su lugar; contrólalo 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)
Los eventos JSONL contienen metadatos genéricos y campos locales del hook:
{"schema_version":1,"sequence":1,"module":"bcrypt.dll","api":"BCryptOpenAlgorithmProvider","hook":"bcrypt.dll!BCryptOpenAlgorithmProvider","fields":{"flags":0,"result":"STATUS_SUCCESS (0x00000000)"}}
Consulta SCHEMA.md para conocer la envoltura del evento y las
codificaciones de campos por tipo (los punteros y estados se muestran como
cadenas hexadecimales 0x).
Pulsa Ctrl+C o Ctrl+Break para restaurar los hooks activos, liberar la instrumentación remota y desadjuntarte. El objetivo continúa ejecutándose. En una salida natural, ApiScope imprime el estado del objetivo en decimal y hexadecimal, seguido de un resumen de sesión (eventos, descartes y contadores por hook) en stderr.
NtCreateFile, NtOpenFile y NtOpenKey resuelven la path objetivo a partir de
OBJECT_ATTRIBUTES e informan del handle resultante. ApiScope registra cada
apertura exitosa y anota las operaciones posteriores sobre el mismo handle —
lecturas, escrituras, acceso a valores de registro y el NtClose correspondiente —
con la path resuelta, de modo que la actividad sea legible sin tener que rastrear
handles manualmente. NtClose también expulsa el handle, y las aperturas relativas
se resuelven a través de un handle root_directory visto previamente.
[*] 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
La path en los eventos de lectura y escritura se correlaciona a partir del
handle, no se observa en la propia llamada.
Cada hook es un archivo dentro de src/apiscope-hooks/hooks/ y declara
conjuntamente su módulo de origen, export, handler, ranura de trampolín, convención
de llamada y 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 descubre los descriptores de diseño fijo exportados por
la DLL de hooks. No se requiere ninguna lista central de APIs ni un esquema de
eventos en el lado del lanzador.
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