draugrgen is a simple python script to help with the creation of hook functions for use within draugr / crystal palace
crystal palace has capabilities to perform function hooking to redirect DFR calls to a user-defined function. one of the main applications for this is call stack spoofing, as crystal palace loaders will often run from unbacked memory. draugr is a call stack spoofing implementation which requires a specific function definition format to setup arguments which are passed to an assembly stub. generating the function definitions is a very manual task and who wants to be searching through msdn?
example draugr function and DFR definition for hooked function:
DECLSPEC_IMPORT HINTERNET WINAPI WINHTTP$WinHttpOpen(LPCWSTR pszAgentW, DWORD dwAccessType, LPCWSTR pszProxyW, LPCWSTR pszProxyBypassW, DWORD dwFlags);
WINBASEAPI HINTERNET WINAPI _WinHttpOpen(LPCWSTR pszAgentW, DWORD dwAccessType, LPCWSTR pszProxyW, LPCWSTR pszProxyBypassW, DWORD dwFlags) {
FUNCTION_CALL call = {0};
call.function = (PVOID)(WINHTTP$WinHttpOpen);
call.args = 5;
call.args[0] = (ULONG_PTR)(pszAgentW);
call.args[1] = (ULONG_PTR)(dwAccessType);
call.args[2] = (ULONG_PTR)(pszProxyW);
call.args[3] = (ULONG_PTR)(pszProxyBypassW);
call.args[4] = (ULONG_PTR)(dwFlags);
return (BOOL)spoof_call(&call);
}
once the hooked function has been compiled into an object file, crystal palace can reference it within a spec file like so:
x64:
load "loader.o"
make pic +gofirst +optimize
load "hooks.o"
merge
attach "WINHTTP$WinHttpOpen" "_WinHttpOpen"
export
git clone https://github.com/ziggoon/draugrgen --recurse-submodules
cd draugrgen
# Basic usage - search specific DLLs for APIs
python gen.py -f WinHttpOpen,WinHttpConnect -d WinHttp
# Wildcard search - search ALL DLLs for APIs (useful when you don't know which DLL)
python gen.py -f VirtualAlloc,CreateThread -d "*"
# Custom output file (fileapi will resolve to KERNEL32 automatically)
python gen.py -f CreateFileA,ReadFile -d fileapi -o my_hooks.c
# List all available DLL definitions
python gen.py --list-dllsThe JSON files in windows_sdk_data/data/ are organized by Windows SDK headers (e.g., memoryapi.json, fileapi.json), but each function definition contains an api_locations field that lists the actual DLLs where the function is implemented.
draugrgen automatically extracts the correct DLL name from the first entry in api_locations and uses it in the DFR syntax. This means:
- Searching
memoryapi.jsonforVirtualAllocgeneratesKERNEL32$VirtualAlloc(notMEMORYAPI$VirtualAlloc) - Searching
fileapi.jsonforCreateFileAgeneratesKERNEL32$CreateFileA(notFILEAPI$CreateFileA) - The JSON filename is just for organization - the actual DLL mapping is resolved automatically
This ensures your DFR calls reference the correct DLL exports that Windows will recognize at runtime.
Example output:
// Searching memoryapi.json generates:
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
// Searching fileapi.json generates:
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, ...);
// Searching winhttp.json generates:
DECLSPEC_IMPORT HINTERNET WINAPI WINHTTP$WinHttpOpen(LPCWSTR pszAgentW, DWORD dwAccessType, ...);- Automatic DLL resolution - Extracts correct DLL names from function metadata (Kernel32, Winhttp, etc.)
- Wildcard DLL search - Use
-d "*"to search all 355 DLL definitions - Progress tracking - Shows which DLLs are being searched and what's found
- Missing API reporting - Warns about APIs that couldn't be found
- Coverage statistics - Shows percentage of requested APIs found
- Custom output paths - Use
-oto specify output file location - JSON validation - Validates JSON structure and skips malformed entries
- Function caching - Pre-builds index for faster searches
- Early exit - Stops searching once all APIs are found
usage: gen.py [-h] [-f FUNCS] [-d DLLS] [-o OUTPUT] [--list-dlls] [--data-dir DATA_DIR]
Win32 API parser + Draugr stub generator for call stack spoofing research
options:
-h, --help show this help message and exit
-f, --funcs FUNCS Comma-separated list of Win32 APIs to parse (e.g., WinHttpOpen,CreateFileA)
-d, --dlls DLLS Comma-separated list of DLLs to search (e.g., WinHttp,Kernel32) or '*' for all
-o, --output OUTPUT Output file path (default: stubs.txt)
--list-dlls List all available DLL definition files and exit
--data-dir DATA_DIR Path to directory containing DLL JSON files (default: windows_sdk_data/data)
Examples:
# Search specific DLLs for APIs
gen.py -f WinHttpOpen,WinHttpConnect -d WinHttp
# Search all DLLs (wildcard)
gen.py -f CreateFileA,ReadFile,WriteFile -d "*"
# Custom output file
# Note: Searching memoryapi will automatically resolve to KERNEL32$VirtualAlloc
gen.py -f VirtualAlloc -d memoryapi -o my_stubs.c
# List available DLL definitions
gen.py --list-dlls