Detours开发实战:CreateProcessWithDll实现进程注入完整案例
一、进程注入技术痛点与解决方案
你是否在开发Windows应用时遇到以下困境:需要监控第三方进程行为却无法修改其源码?想要在目标进程启动时自动加载插件但缺乏有效手段?微软研究院开发的Detours库提供了优雅的解决方案,其中CreateProcessWithDll系列函数更是实现进程注入的利器。本文将通过完整案例,详解如何使用Detours实现进程注入,解决DLL加载时机、架构兼容性和注入稳定性三大核心痛点。
读完本文你将掌握:
CreateProcessWithDll的工作原理与调用流程- 32/64位进程混合注入的实现方案
- 注入过程中的错误处理与调试技巧
- 从DLL开发到注入验证的全流程实践
二、技术原理与核心函数解析
2.1 Detours进程注入原理
Detours通过修改目标进程的导入表(Import Table)实现DLL注入,其核心流程如下:
这种技术相比传统的CreateRemoteThread具有三大优势:
- 注入时机更早,可在进程初始化阶段加载
- 支持多DLL链式加载
- 对目标进程影响更小,稳定性更高
2.2 CreateProcessWithDll函数原型
Detours提供了三个核心函数实现进程注入:
BOOL WINAPI CreateProcessWithDllA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation,
LPCSTR lpDllName,
LPVOID lpResumeAddress
);
// 宽字符版本
BOOL WINAPI CreateProcessWithDllW(/* 参数同上 */);
// 支持多DLL注入的扩展版本
BOOL WINAPI CreateProcessWithMultipleDllsA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation,
DWORD nDlls,
LPCSTR *rlpDlls
);
2.3 关键数据结构
进程注入过程中需要处理的核心数据结构包括:
DETOUR_EXE_RESTORE - 用于保存和恢复进程PE头信息:
typedef struct _DETOUR_EXE_RESTORE {
DWORD cb;
PBYTE pidh;
DWORD cbidh;
IMAGE_DOS_HEADER idh;
PBYTE pinh;
DWORD cbinh;
IMAGE_NT_HEADERS inh;
PBYTE pclr;
DWORD cbclr;
IMAGE_COR20_HEADER clr;
BYTE raw[4096];
} DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE;
IMAGE_NT_HEADERS - PE文件头结构,用于解析目标进程架构信息:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
三、开发环境准备与项目配置
3.1 环境要求
| 组件 | 版本要求 |
|---|---|
| Windows SDK | 10.0.19041.0+ |
| Visual Studio | 2019+ |
| Detours库 | 4.0.1+ |
| 目标系统 | Windows 7 SP1+ |
3.2 项目配置步骤
- 获取Detours源码
git clone https://gitcode.com/gh_mirrors/de/Detours.git
cd Detours
- 编译Detours库
nmake -f Makefile
- 项目属性配置
- 包含目录添加:
Detours\include - 库目录添加:
Detours\lib.X86或Detours\lib.X64 - 链接器输入添加:
detours.lib
- 包含目录添加:
四、完整实现案例:进程监控DLL注入
4.1 注入DLL实现
创建monitor.dll,实现进程监控功能:
// monitor.cpp
#include <windows.h>
#include <detours.h>
#include <stdio.h>
// 全局日志文件句柄
HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
// 日志函数
void Log(const char* format, ...) {
if (g_hLogFile == INVALID_HANDLE_VALUE) {
g_hLogFile = CreateFileA("C:\\detour_log.txt", GENERIC_WRITE,
FILE_SHARE_READ, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (g_hLogFile == INVALID_HANDLE_VALUE) return;
}
char buffer[1024];
va_list args;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
DWORD bytesWritten;
WriteFile(g_hLogFile, buffer, strlen(buffer), &bytesWritten, NULL);
}
// 钩子函数定义
typedef BOOL (WINAPI *CreateFileAFunc)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
CreateFileAFunc g_origCreateFileA = NULL;
// 钩子实现
BOOL WINAPI HookedCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
Log("CreateFileA called: %s\n", lpFileName);
return g_origCreateFileA(lpFileName, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile);
}
// DLL入口函数
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
Log("Monitor DLL loaded\n");
// 开始挂钩
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
// 挂钩CreateFileA函数
g_origCreateFileA = (CreateFileAFunc)GetProcAddress(
GetModuleHandleA("kernel32.dll"), "CreateFileA");
DetourAttach(&(PVOID&)g_origCreateFileA, HookedCreateFileA);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
// 解除挂钩
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)g_origCreateFileA, HookedCreateFileA);
DetourTransactionCommit();
if (g_hLogFile != INVALID_HANDLE_VALUE) {
CloseHandle(g_hLogFile);
}
break;
}
return TRUE;
}
4.2 注入器实现
创建注入工具injector.cpp:
#include <windows.h>
#include <detours.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
if (argc < 3) {
printf("用法: injector <目标进程路径> <DLL路径>\n");
return 1;
}
const char* targetPath = argv[1];
const char* dllPath = argv[2];
STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
// 使用CreateProcessWithDll注入DLL
BOOL success = CreateProcessWithDllA(
targetPath, // 目标进程路径
NULL, // 命令行参数
NULL, // 进程安全属性
NULL, // 线程安全属性
FALSE, // 不继承句柄
CREATE_SUSPENDED, // 创建挂起进程
NULL, // 使用当前环境变量
NULL, // 使用当前工作目录
&si, // 启动信息
&pi, // 进程信息输出
dllPath, // 要注入的DLL路径
NULL // 恢复地址(NULL表示使用原始入口点)
);
if (success) {
printf("注入成功! 进程ID: %d\n", pi.dwProcessId);
// 可以在这里添加额外操作...
// 关闭句柄
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
} else {
printf("注入失败! 错误代码: %lu\n", GetLastError());
return 1;
}
}
4.3 多DLL注入实现
使用CreateProcessWithMultipleDllsA实现多DLL注入:
// 多DLL注入示例
const char* dlls[] = {
"C:\\path\\to\\monitor.dll",
"C:\\path\\to\\logger.dll"
};
BOOL success = CreateProcessWithMultipleDllsA(
targetPath,
NULL,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&si,
&pi,
2, // DLL数量
dlls // DLL路径数组
);
五、32/64位架构兼容性处理
5.1 架构检测实现
Detours提供了DetourIsWow64Process函数检测进程架构:
BOOL Is64BitProcess(HANDLE hProcess) {
BOOL isWow64 = FALSE;
if (DetourIsWow64Process(hProcess, &isWow64)) {
// 在64位系统上:
// - 64位进程: isWow64 = FALSE
// - 32位进程: isWow64 = TRUE
// 在32位系统上: 始终返回FALSE
SYSTEM_INFO si;
GetNativeSystemInfo(&si);
if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
return !isWow64; // 64位系统上非Wow64进程是64位
}
}
return FALSE; // 32位系统或检测失败
}
5.2 跨架构注入解决方案
当注入器与目标进程架构不同时,需要使用架构适配的DLL:
// 架构适配注入示例
int InjectTarget(const char* targetPath, const char* dll32Path, const char* dll64Path) {
// 1. 创建挂起的目标进程
STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
BOOL success = CreateProcessA(
targetPath, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED | DEBUG_PROCESS, NULL, NULL, &si, &pi
);
if (!success) {
printf("创建进程失败! 错误代码: %lu\n", GetLastError());
return 1;
}
// 2. 检测目标进程架构
BOOL is64Bit = Is64BitProcess(pi.hProcess);
const char* dllPath = is64Bit ? dll64Path : dll32Path;
// 3. 使用DetourUpdateProcessWithDll注入DLL
const char* dlls[] = { dllPath };
success = DetourUpdateProcessWithDll(pi.hProcess, dlls, 1);
if (success) {
// 4. 恢复进程执行
ResumeThread(pi.hThread);
printf("注入成功! 进程ID: %d (架构: %s)\n",
pi.dwProcessId, is64Bit ? "64位" : "32位");
} else {
printf("注入失败! 错误代码: %lu\n", GetLastError());
TerminateProcess(pi.hProcess, 0);
}
// 关闭句柄
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return success ? 0 : 1;
}
六、错误处理与调试技巧
6.1 常见错误码及解决方案
| 错误码 | 含义 | 解决方案 |
|---|---|---|
| 0x2 (ERROR_FILE_NOT_FOUND) | 文件未找到 | 检查目标进程和DLL路径是否正确 |
| 0x5 (ERROR_ACCESS_DENIED) | 访问被拒绝 | 以管理员权限运行注入器 |
| 0xC1 (ERROR_BAD_EXE_FORMAT) | 无效的PE格式 | 确保DLL与目标进程架构匹配 |
| 0x7E (ERROR_PROC_NOT_FOUND) | 函数未找到 | 更新Detours库到最新版本 |
| 0x126 (ERROR_MOD_NOT_FOUND) | 模块未找到 | 检查DLL依赖是否完整 |
6.2 调试技巧
- 启用Detours调试输出
#define DETOUR_DEBUG 1
#include <detours.h>
-
使用DebugView监控调试输出
- 下载并运行DebugView
- 在注入器中添加调试输出:
DETOUR_TRACE(("注入进度: 正在修改进程导入表...\n")); -
进程注入流程验证
七、高级应用与最佳实践
7.1 DLL加载顺序控制
当注入多个DLL时,可以通过以下方式控制加载顺序:
// 按顺序加载多个DLL
const char* dlls[] = {
"C:\\deps\\first.dll", // 第一个加载
"C:\\deps\\second.dll", // 第二个加载
"C:\\main\\monitor.dll" // 最后加载
};
BOOL success = CreateProcessWithMultipleDllsA(
targetPath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED,
NULL, NULL, &si, &pi, 3, dlls
);
7.2 注入后的进程通信
注入DLL后,可以通过多种方式与主进程通信:
- 共享内存
// 创建共享内存
HANDLE hMapFile = CreateFileMappingA(
INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "Global\\MySharedMem"
);
// 映射到进程地址空间
LPVOID pBuf = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 4096);
- 命名管道
// 创建命名管道
HANDLE hPipe = CreateNamedPipeA(
"\\\\.\\pipe\\MyPipe", PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, 4096, 4096, 0, NULL
);
7.3 注入防御与绕过
在实际应用中,可能需要应对目标进程的注入防御机制:
- 反调试检测
// 检查是否处于调试状态
BOOL IsDebuggerPresent() {
__asm {
mov eax, fs:[0x30] // 获取PEB地址
mov bl, [eax+0x2] // PEB->BeingDebugged
movzx eax, bl
}
}
- 注入点隐藏
// 使用自定义恢复地址隐藏注入痕迹
VOID CustomResumeAddress() {
// 这里可以添加反调试或反检测代码
__asm {
jmp original_entry_point // 跳转到原始入口点
}
}
// 在注入时指定自定义恢复地址
BOOL success = CreateProcessWithDllA(
targetPath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED,
NULL, NULL, &si, &pi, dllPath, CustomResumeAddress
);
八、总结与扩展学习
本文详细介绍了使用Detours库的CreateProcessWithDll函数实现进程注入的完整流程,包括:
- 核心原理:通过修改导入表实现早期DLL加载
- 代码实现:从DLL开发到注入器的完整代码
- 架构适配:32/64位进程的兼容处理方案
- 错误调试:常见问题的诊断与解决方法
- 高级应用:多DLL注入与进程通信
扩展学习资源
-
Detours官方文档
- 深入理解导入表修改技术
- 事务处理与线程同步机制
-
PE文件格式解析
- 导入表结构详解
- 重定位表处理
-
进程注入防御技术
- API监控与钩子检测
- 内存完整性校验
通过本文的案例实践,你可以构建稳定、高效的进程注入工具,实现对目标进程的监控、扩展或修复。在实际应用中,请确保遵守相关法律法规,仅在授权环境下使用这些技术。
九、附录:核心函数参考
CreateProcessWithDll参数说明
| 参数 | 含义 | 备注 |
|---|---|---|
| lpApplicationName | 目标进程路径 | 可以为NULL,此时从lpCommandLine解析 |
| lpCommandLine | 命令行参数 | 需以可写内存传入 |
| dwCreationFlags | 创建标志 | 必须包含CREATE_SUSPENDED |
| lpDllName | 注入DLL路径 | 支持绝对路径或相对路径 |
| lpResumeAddress | 恢复地址 | NULL表示使用原始入口点 |
DetourUpdateProcessWithDll工作流程
// 简化的DetourUpdateProcessWithDll实现逻辑
BOOL DetourUpdateProcessWithDll(HANDLE hProcess, LPCSTR* dlls, DWORD nDlls) {
// 1. 枚举进程模块找到主EXE
HMODULE hModule = FindMainModule(hProcess);
// 2. 检测进程架构
BOOL is32BitProcess = CheckProcessArchitecture(hProcess);
// 3. 保存原始PE头信息
DETOUR_EXE_RESTORE der;
RecordExeRestore(hProcess, hModule, &der);
// 4. 更新导入表添加DLL
UpdateImports(hProcess, hModule, is32BitProcess, dlls, nDlls);
// 5. 恢复进程保护属性
RestoreProtection(hProcess, &der);
return TRUE;
}
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



