# inlinehook **Repository Path**: cutecuteyu/inlinehook ## Basic Information - **Project Name**: inlinehook - **Description**: 使用C++的inlinehook技术示例 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-08-23 - **Last Updated**: 2026-03-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Inline Hook A C++ project demonstrating Windows Inline Hook technology. ## Project Structure ``` inlinehook/ ├── README.md # Chinese documentation ├── README.en.md # English documentation ├── LICENSE # MIT License └── Project1/ ├── 源.cpp # Main program entry ├── 手动测试.cpp # Test program ├── Project1.sln # Solution file ├── Project1.vcxproj # Project file └── Project2/ ├── 代码实现.cpp # Core Inline Hook implementation └── Project2.vcxproj ``` ## Description This project demonstrates the basic principles and implementation of **Inline Hook** technology. Inline Hook is a technique that intercepts and redirects function calls by modifying the entry point instructions of a target function. ### Core Features - Intercept Windows API function calls - Inject custom logic before/after target function execution - Complete restoration of original function functionality --- ## Detailed Principle Explanation ### 1. What is Inline Hook? Inline Hook is a runtime patching technique that modifies the machine code at the entry point of a target function to redirect the execution flow to our custom function. Unlike traditional Windows hooks (like SetWindowsHookEx), Inline Hook directly modifies the function code in memory, so it can intercept any function call, whether it's a system API or a custom function. ### 2. x86 JMP Instruction Deep Dive In x86 architecture, the **JMP (Jump) instruction** is used for unconditional jumps to a specified address. The relative jump machine code format is: ``` [0xE9] [4-byte offset] ``` - `0xE9`: JMP instruction opcode - `4-byte offset`: Target address relative to the next instruction (32-bit signed integer) **Jump Offset Calculation Formula**: ``` offset = target_address - (current_instruction_address + 5) ``` The +5 is because the JMP instruction itself occupies 5 bytes (1 byte opcode + 4 bytes offset). Example: - Assume `CreateFileA` address = 0x7FFA1234 - Assume `MY_CreateFileA` address = 0x00401000 - Offset = 0x00401000 - (0x7FFA1234 + 5) = negative number (jump to lower address) ### 3. Code Modification Principle Taking this project as an example, the complete steps to hook `CreateFileA`: ```cpp // Target function address char* target = (char*)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "CreateFileA"); ``` #### Step 1: Modify Memory Protection The code section (.text segment) is typically read-only (PAGE_EXECUTE_READ) and cannot be written directly. We need to use `VirtualProtect` to modify memory attributes: ```cpp DWORD oldProtect; VirtualProtect(target, 5, PAGE_EXECUTE_READWRITE, &oldProtect); ``` Parameters: - `target`: Target function address - `5`: Number of bytes to modify (5 bytes = 1 byte JMP opcode + 4 bytes offset) - `PAGE_EXECUTE_READWRITE`: Allow read, write, execute - `&oldProtect`: Output parameter, stores original protection for later restoration #### Step 2: Backup Original Instructions ```cpp char backups_asm[5]; memcpy(backups_asm, target, 5); ``` Save the first 5 bytes of the target function entry. These 5 bytes may be: - The first few instructions of the function - Or part of an instruction (if the instruction crosses the 5-byte boundary) The backup is necessary to restore the original function later. #### Step 3: Write JMP Instruction ```cpp unsigned char jmp_0xe9 = 0xE9; unsigned int jmp_addr = detour - (target + 5); memcpy(target, &jmp_0xe9, 1); // Write opcode 0xE9 memcpy(target + 1, &jmp_addr, 4); // Write offset (4 bytes) ``` This replaces the original function entry with `JMP target_address`, redirecting to our Hook function. Memory layout after modification: ``` Original function entry (target): ┌─────────┬──────────────┐ │ 0xE9 │ 4-byte offset│ ├─────────┴──────────────┤ │ JMP instruction (5B) │ └───────────────────────┘ ``` ### 4. Hook Function Implementation Principle In the Hook function, we need to: 1. **Execute custom logic**: Print parameters, log, modify parameters, etc. 2. **Restore original function**: Write back the backed-up 5 bytes so the original function can execute normally 3. **Call original function**: Execute the original functionality 4. **Optional: Re-install Hook**: If continuous interception is needed ```cpp HANDLE __stdcall MY_CreateFileA( LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { DWORD oldProtect; // 1. Execute custom logic printf("MY_CreateFileA: %s \n", lpFileName); MessageBoxA(NULL, "aaaaa", "bbbbb", MB_OK); // 2. Restore original instructions (5 bytes) VirtualProtect(target, 5, PAGE_EXECUTE_READWRITE, &oldProtect); memcpy(target, backups_asm, 5); VirtualProtect(target, 5, oldProtect, &oldProtect); // 3. Call original function return CreateFileA( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } ``` **Why restore original instructions?** - Because the JMP instruction has overwritten the first 5 bytes of the original function entry - Without restoration, the original function cannot execute normally - After restoration, call the original function, then re-write the JMP instruction if needed ### 5. Calling Convention (__stdcall) ```cpp HANDLE __stdcall MY_CreateFileA(...) ``` `__stdcall` is the Windows API standard calling convention: - **Parameter Passing**: Parameters are pushed onto the stack from right to left - **Stack Cleanup**: Callee cleans up the stack - **Name Decoration**: Function name prefixed with underscore, suffixed with @ and total parameter bytes This ensures our custom function's parameter layout matches the original function, allowing the caller to correctly pass and clean up parameters. --- ## Detailed Code Analysis ### Complete Code Walkthrough #### 1. Get Target Function Address ```cpp char backups_asm[5]; char* target = (char*)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "CreateFileA"); ``` - `GetModuleHandleA("Kernel32.dll")`: Get handle to Kernel32.dll - `GetProcAddress(...)`: Get address of specified exported function - `CreateFileA`: ANSI version of CreateFile (not Unicode version CreateFileW) #### 2. First Call (Before Hook) ```cpp printf("第一次调用CreateFileA \n"); hFile = CreateFileA("abc.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); ``` This call happens before the Hook is installed, so it executes normally. #### 3. Install Hook ```cpp char* detour = (char*)&MY_CreateFileA; DWORD oldProtect; // Modify memory attribute to read-write-execute if (!VirtualProtect(target, 5, PAGE_EXECUTE_READWRITE, &oldProtect)) { printf("VirtualProtect false\n"); return 0; } // Backup original 5 bytes memcpy(backups_asm, target, 5); // Build JMP instruction unsigned char jmp_0xe9 = 0xE9; unsigned int jmp_addr = detour - (target + 5); // Write JMP instruction memcpy(target, &jmp_0xe9, 1); memcpy(target + 1, &jmp_addr, 4); // Restore memory attribute VirtualProtect(target, 5, oldProtect, &oldProtect); ``` #### 4. Second Call (After Hook) ```cpp printf("第二次调用CreateFileA \n"); hFile = CreateFileA("bcd.txt", ...); ``` Now the call flow becomes: ``` CreateFileA() ↓ (CPU executes to entry, finds JMP instruction) ↓ MY_CreateFileA() ← Execute custom logic here ↓ (Restore original instructions) ↓ Original CreateFileA() ← Actually create the file ↓ Return and possibly re-install Hook ``` --- ## Complete Execution Flow Diagram ``` ┌─────────────────────────────────────────────────────────────┐ │ Program Start │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ First Call: CreateFileA("abc.txt") │ │ - CPU executes CreateFileA entry instructions normally │ │ - Creates file abc.txt │ │ - Output: "第一次调用CreateFileA" │ │ - Output: "CreateFileA success" │ │ - Returns file handle │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Install Hook │ │ 1. VirtualProtect(..., PAGE_EXECUTE_READWRITE, ...) │ │ 2. Save original 5 bytes: memcpy(backups_asm, target, 5) │ │ 3. Calculate offset: jmp_addr = MY_CreateFileA - (t+5) │ │ 4. Write JMP: memcpy(target, "\xE9\xXX\xXX\xXX\xXX") │ │ 5. VirtualProtect(..., oldProtect, ...) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Second Call: CreateFileA("bcd.txt") │ │ - CPU reads byte at target: 0xE9 │ │ - CPU recognizes as JMP instruction, reads offset │ │ - CPU jumps to MY_CreateFileA │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ MY_CreateFileA() │ │ - Print parameter: "MY_CreateFileA: bcd.txt" │ │ - Show MessageBox │ │ - Restore original: memcpy(target, backups_asm, 5) │ │ - Call original CreateFileA("bcd.txt") │ │ - Return file handle │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Software Architecture - **Programming Language**: C++ - **Development Tools**: Visual Studio 2019+ - **Target Platform**: Windows x86/x64 --- ## Installation 1. Install Visual Studio 2019 or higher 2. Install Windows SDK 3. Open `Project1/Project1.sln` with Visual Studio 4. Build both Project1 and Project2 --- ## Usage 1. **Build Project**: - Open `Project1.sln` - Select Release or Debug configuration - Build the entire solution 2. **Run Test**: - Run Project2 to see the Hook effect - Observe console output and the popup MessageBox 3. **Key Code Locations**: - Hook implementation: `Project1/Project2/代码实现.cpp:39-105` - Custom function: `Project1/Project2/代码实现.cpp:10-37` --- ## Sample Output ``` 第一次调用CreateFileA CreateFileA success 第二次调用CreateFileA MY_CreateFileA: bcd.txt ``` --- ## Notes 1. **Memory Protection**: Inline Hook requires modifying code in memory and needs appropriate memory protection permissions 2. **Multi-threading**: In production use, multi-threading safety issues need to be handled using mutexes or critical sections 3. **Exception Handling**: Hooks may cause program crashes, requiring robust exception handling 4. **Security Software**: Some security software may block such behavior 5. **x64 Architecture**: On x64 architecture, JMP instructions are longer (14 bytes needed), making implementation more complex 6. **Instruction Length**: This example uses 5 bytes; if the hooked function entry is less than 5 bytes, there could be issues --- ## Further Reading - **VEH/SEH**: Vectored Exception Handling / Structured Exception Handling for more secure Hook - **IAT Hook**: Hook by modifying Import Address Table (only works for imported functions) - **EAT Hook**: Hook by modifying Export Address Table - **MinHook**: Mature Hook library using Trampoline technology, supports x86/x64 --- ## Contribution 1. Fork the repository 2. Create Feat_xxx branch 3. Commit your code 4. Create Pull Request