如何使用Windows ImportRedirection实现DLL导入函数Hook
Windows API导入重定向实现失效排查
问题背景
Windows 10及以上版本提供API Redirection(API导入重定向)特性,支持将进程加载DLL时的导入函数调用重定向到自定义实现,本次实现目标为:
- 编写
A.dll,导出原生Sum()函数 - 编写
Redirection.dll,实现自定义mySum()函数 - 启动目标进程
target.exe时,将其对A.dll!Sum()的调用重定向到Redirection.dll!mySum()
初步规划实现步骤仅包含编写重定向DLL、关联重定向DLL创建进程两步,但实际运行时重定向DLL未被加载,重定向完全不生效。
现有实现代码
Redirection.dll 代码
#include "pch.h" #include <stdlib.h> int mySum(int a, int b) { printf("rewrite! \n"); return 222222222; } const REDIRECTION_FUNCTION_DESCRIPTOR RedirectionFunction[] = { { "Dll1.lib", "Sum", &mySum } }; extern "C" __declspec(dllexport) const REDIRECTION_DESCRIPTOR __RedirectionInformation__ = { CURRENT_IMPORT_REDIRECTION_VERSION, _countof(RedirectionFunction), RedirectionFunction };
A.dll 代码
#include "pch.h" extern "C" _declspec(dllexport) int Sum(int a, int b) { printf("orginal dll1. \n"); return a + b; }
target.exe 代码
#include <Windows.h> #include <iostream> #pragma comment(lib,"A.lib") #define DLLIMPORT extern "C" _declspec(dllimport) DLLIMPORT int Sum(int a, int b); int main() { std::cout << "this is injectFuction main process: Hello World!\n"; std::cout << Sum(1, 2) << std::endl; Sleep(10000000); return 0; }
进程创建代码
#include <Windows.h> #include "ntdll.h" int main() { UNICODE_STRING NtImagePath; UNICODE_STRING NtDLLPath; RtlInitUnicodeString(&NtImagePath, (PWSTR)L"\\??\\D:\\newJunFiles\\RedirectionExample\\x64\\Debug\\target.exe"); RtlInitUnicodeString(&NtDLLPath, (PWSTR)L"\\??\\D:\\newJunFiles\\RedirectionExample\\x64\\Debug\\Redirection.dll"); PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL; RtlCreateProcessParametersEx(&ProcessParameters, &NtImagePath, &NtDLLPath, NULL, NULL, NULL, NULL, NULL, NULL, NULL, RTL_USER_PROCESS_PARAMETERS_NORMALIZED); PS_CREATE_INFO CreateInfo = { 0 }; CreateInfo.Size = sizeof(CreateInfo); CreateInfo.State = PsCreateInitialState; PPS_ATTRIBUTE_LIST AttributeList = (PPS_ATTRIBUTE_LIST)RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PS_ATTRIBUTE)); AttributeList->TotalLength = sizeof(PS_ATTRIBUTE_LIST) - sizeof(PS_ATTRIBUTE); AttributeList->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME; AttributeList->Attributes[0].Size = NtImagePath.Length; AttributeList->Attributes[0].Value = (ULONG_PTR)NtImagePath.Buffer; HANDLE hProcess, hThread = NULL; NtCreateUserProcess(&hProcess, &hThread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, NULL, NULL, NULL, NULL, ProcessParameters, &CreateInfo, AttributeList); RtlFreeHeap(RtlProcessHeap(), 0, AttributeList); RtlDestroyProcessParameters(ProcessParameters); }
失效原因与修正方案
现有实现存在3个核心错误,按顺序修正即可生效:
- 重定向描述符DLL名称配置错误
REDIRECTION_FUNCTION_DESCRIPTOR结构体第一个字段需要填写被重定向DLL的PE导出名称,不是导入库的.lib后缀名。你要重定向的是A.dll的导出,这里应填"A.dll",而非"Dll1.lib"。
修正后的重定向函数表写法:
const REDIRECTION_FUNCTION_DESCRIPTOR RedirectionFunction[] = { { "A.dll", "Sum", &mySum } };
- 错误使用
RtlCreateProcessParametersEx参数
该函数第三个参数是进程初始化时的默认DLL搜索路径,不是用来指定要加载的重定向DLL路径,直接将该参数传NULL即可。重定向DLL只需要放在目标EXE同目录,或者加入系统已知DLL列表,就能被加载器自动识别。 - PS_ATTRIBUTE列表缺少重定向启用配置
当前属性列表仅配置了镜像名称,没有添加PS_ATTRIBUTE_REDIRECTION_STATE属性来显式启用导入重定向,加载器不会主动扫描重定向DLL的导出符号。需要在属性列表中新增该配置项,设置值为启用状态。
额外注意事项:
__RedirectionInformation__导出符号必须用extern "C"修饰避免名称改编,当前写法正确无需修改- 重定向函数的签名、参数个数、调用约定必须和原函数完全一致,否则会触发栈损坏
- 重定向DLL的架构必须和目标进程完全匹配,x64进程只能加载x64重定向DLL,x86同理
补充:该API重定向特性仅在Windows 10 1903及以上版本系统中生效,低版本系统不支持该机制
内容的提问来源于stack exchange,提问作者GuangJun Liu
相关产品推荐
相关产品推荐

