Detours
Detours is a software package developed by Microsoft for intercepting Win32 API function calls. It enables developers and security researchers to monitor, modify, and redirect function behavior at runtime through inline code patching and trampolining.
Overview
Detours allows you to:
- Hook existing Win32 API functions
- Redirect function calls to custom handlers
- Intercept and modify function behavior
- Monitor API usage patterns
- Perform DLL injection at runtime
- Create detour chains for multiple hooks
Installation
From Microsoft
# Download Detours from Microsoft Research
# https://www.microsoft.com/en-us/download/details.aspx?id=52172
# Extract the archive
Expand-Archive -Path detours.zip -DestinationPath C:\detours
# Build library
cd C:\detours
msbuild src\detours.sln /p:Configuration=Release /p:Platform=x64
# Add to project include/lib paths
$DetourPath = "C:\detours"
# Include: $DetourPath\include
# Lib: $DetourPath\lib.X64
Building from Source
# Clone or download the source
cd detours/src
# Build with Visual Studio
msbuild detours.sln /p:Configuration=Release
# Or use nmake
nmake
Basic Function Hooking
Simple API Hook Example
#include <detours.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "detours.lib")
// Original function pointer
static LPVOID (WINAPI *Real_HeapAlloc)(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) = HeapAlloc;
// Detour function
LPVOID WINAPI Mine_HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes)
{
printf("[HOOK] HeapAlloc called with size: %zu\n", dwBytes);
return Real_HeapAlloc(hHeap, dwFlags, dwBytes);
}
// Attach hook
void AttachHook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)Real_HeapAlloc, Mine_HeapAlloc);
DetourTransactionCommit();
}
// Detach hook
void DetachHook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)Real_HeapAlloc, Mine_HeapAlloc);
DetourTransactionCommit();
}
Hooking Registry Functions
#include <detours.h>
#include <winreg.h>
#include <stdio.h>
#pragma comment(lib, "detours.lib")
// Hook RegOpenKeyEx
static LONG (WINAPI *Real_RegOpenKeyEx)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions,
REGSAM samDesired, PHKEY phkResult) = RegOpenKeyExA;
LONG WINAPI Mine_RegOpenKeyEx(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions,
REGSAM samDesired, PHKEY phkResult)
{
printf("[HOOK] RegOpenKeyEx: %s\n", lpSubKey ? lpSubKey : "(null)");
return Real_RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, phkResult);
}
void SetupRegistryHook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)Real_RegOpenKeyEx, Mine_RegOpenKeyEx);
DetourTransactionCommit();
}
Hooking File API Functions
#include <detours.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "detours.lib")
// Hook CreateFileA
static HANDLE (WINAPI *Real_CreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) = CreateFileA;
HANDLE WINAPI Mine_CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
printf("[HOOK] CreateFileA: %s\n", lpFileName);
// Log sensitive file access
if (strstr(lpFileName, "password") || strstr(lpFileName, "config"))
{
printf("[ALERT] Sensitive file access detected!\n");
}
return Real_CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
DLL Injection
DLL Injection Module
// injected.dll - Code that runs in target process
#include <windows.h>
#include <stdio.h>
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
// Create log file in target process
FILE* log = fopen("C:\\temp\\injection.log", "a");
fprintf(log, "[*] DLL Injected into process\n");
fclose(log);
// Set up hooks here
SetupAllHooks();
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
FILE* log = fopen("C:\\temp\\injection.log", "a");
fprintf(log, "[*] DLL Detached from process\n");
fclose(log);
}
return TRUE;
}
Injector Program
#include <detours.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "detours.lib")
// Function to inject DLL into target process
BOOL InjectDLL(DWORD dwProcessId, const char* dllPath)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (!hProcess)
{
printf("[-] Failed to open process: %d\n", GetLastError());
return FALSE;
}
// Allocate memory in target process
SIZE_T dllPathLen = strlen(dllPath) + 1;
LPVOID lpBuffer = VirtualAllocEx(hProcess, NULL, dllPathLen,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!lpBuffer)
{
printf("[-] Failed to allocate memory\n");
CloseHandle(hProcess);
return FALSE;
}
// Write DLL path to target process
if (!WriteProcessMemory(hProcess, lpBuffer, (void*)dllPath, dllPathLen, NULL))
{
printf("[-] Failed to write process memory\n");
VirtualFreeEx(hProcess, lpBuffer, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
// Create remote thread to load DLL
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"),
lpBuffer, 0, NULL);
if (!hThread)
{
printf("[-] Failed to create remote thread\n");
VirtualFreeEx(hProcess, lpBuffer, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
// Wait for thread completion
WaitForSingleObject(hThread, INFINITE);
// Cleanup
VirtualFreeEx(hProcess, lpBuffer, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
printf("[+] DLL injected successfully\n");
return TRUE;
}
API Monitoring
Network API Monitoring
#include <detours.h>
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "detours.lib")
#pragma comment(lib, "ws2_32.lib")
// Hook socket operations
static int (WINAPI *Real_send)(SOCKET s, const char* buf, int len, int flags) = send;
int WINAPI Mine_send(SOCKET s, const char* buf, int len, int flags)
{
printf("[HOOK] send() called with %d bytes\n", len);
// Log first 100 bytes
if (len > 0)
{
printf("[DATA] ");
for (int i = 0; i < (len < 100 ? len : 100); i++)
{
printf("%02x ", (unsigned char)buf[i]);
}
printf("\n");
}
return Real_send(s, buf, len, flags);
}
Process Spawning Monitor
#include <detours.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "detours.lib")
static BOOL (WINAPI *Real_CreateProcessA)(LPCSTR lpApplicationName, LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) = CreateProcessA;
BOOL WINAPI Mine_CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
{
FILE* log = fopen("C:\\temp\\process_monitor.log", "a");
fprintf(log, "[*] CreateProcess called:\n");
fprintf(log, " Application: %s\n", lpApplicationName ? lpApplicationName : "(null)");
fprintf(log, " Command Line: %s\n", lpCommandLine ? lpCommandLine : "(null)");
fclose(log);
return Real_CreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes,
lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
}
Advanced Techniques
Detour Chains
// Multiple detours on same function
static int (WINAPI *Real_send)(SOCKET s, const char* buf, int len, int flags) = send;
static int (WINAPI *ChainedSend)(SOCKET s, const char* buf, int len, int flags) = send;
int WINAPI Mine_send_v1(SOCKET s, const char* buf, int len, int flags)
{
printf("[DETOUR 1] Logging\n");
return ChainedSend(s, buf, len, flags);
}
int WINAPI Mine_send_v2(SOCKET s, const char* buf, int len, int flags)
{
printf("[DETOUR 2] Analyzing\n");
return Real_send(s, buf, len, flags);
}
void AttachChain()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
// First detour
ChainedSend = Real_send;
DetourAttach(&(PVOID&)Real_send, Mine_send_v1);
DetourAttach(&(PVOID&)ChainedSend, Mine_send_v2);
DetourTransactionCommit();
}
Function Parameter Modification
// Modify function behavior
static HANDLE (WINAPI *Real_CreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) = CreateFileA;
HANDLE WINAPI Mine_CreateFileA_Protective(LPCSTR lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
// Block access to protected files
if (strstr(lpFileName, "protected"))
{
SetLastError(ERROR_ACCESS_DENIED);
return INVALID_HANDLE_VALUE;
}
return Real_CreateFileA(lpFileName, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
Compilation and Deployment
Building a Detour Hook DLL
# Compile with Detours library
cl.exe /D_WINDOWS /D_USRDLL /D_WINDLL /I"C:\detours\include" ^
myhooks.cpp ^
/link /DLL /LIBPATH:"C:\detours\lib.X64" detours.lib
# Result: myhooks.dll
Testing Detours
// Test program that hooks itself
#include <detours.h>
#include <stdio.h>
static int (WINAPI *Real_printf)(const char*, ...) = printf;
int WINAPI Mine_printf(const char* fmt, ...)
{
// Intercept printf calls
return Real_printf("[HOOKED] %s", fmt);
}
int main()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)Real_printf, Mine_printf);
DetourTransactionCommit();
printf("This will be hooked\n");
return 0;
}
Detection and Defense
Detecting Detours Usage
- Monitor for API hook patterns in memory
- Check for inline code patches
- Monitor CreateRemoteThread + LoadLibrary patterns
- Analyze DLL imports for detours.lib usage
Preventing Detours Injection
# Disable DLL injection at system level
Set-MpPreference -DisableRealtimeMonitoring $true
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\MiSvc" -Name "Start" -Value 4
# Monitor suspicious thread creation
Get-WinEvent -LogName Security | Where-Object {$_.Id -eq 8