前段时间有一个需求,就是在进程启动的第一时间实现dll的注入,当时一想以为很简单嘛,比如拦截CreateProcessInternalW等不就行了吗?后来发现如果你在CreateProcessInternalW前处理进程还没有启动,而之后处理的话,进程的主线程已经开始工作了,再后来通过修改创建标志把创建的进程的主线程挂起,等进程创建后我来注入,此时才发现创建远线程搞不定, 此时进程只有NTDLL,其他模块还没有加载呢.再最后终于发现了detours 2.1为我们提供了一个函数DetourCreateProcessWithDllW,它可以实现在进程创建初期就将dll加载进去,下面我就来分析一下detours怎么做到在进程初期就将dll加载进程的.
先来看DetourCreateProcessWithDllW函数,可以分为四个步骤:
BOOL
WINAPI
DetourCreateProcessWithDllW(LPCWSTR lpApplicationName,
__in_z LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation,
LPCSTR lpDetouredDllFullName,
LPCSTR lpDllName,
PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
... {
// 第一步:修改创建标志位
DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED);
PROCESS_INFORMATION pi;
if (pfCreateProcessW == NULL) ...{
pfCreateProcessW = CreateProcessW;
}
// 第二步:调用原始CreateProcessW
if (!pfCreateProcessW(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwMyCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
&pi)) ...{
return FALSE;
}
LPCSTR rlpDlls[2];
DWORD nDlls = 0;
if (lpDetouredDllFullName != NULL) ...{
rlpDlls[nDlls++] = lpDetouredDllFullName;
}
if (lpDllName != NULL) ...{
rlpDlls[nDlls++] = lpDllName;
}
// 第三步: 修改目标进程的输入表
if (!UpdateImports(pi.hProcess, rlpDlls, nDlls)) ...{
return FALSE;
}
if (lpProcessInformation) ...{
CopyMemory(lpProcessInformation, &pi, sizeof(pi));
}
// 第四步: 让目标进程的主线程继续运行
if (!(dwCreationFlags & CREATE_SUSPENDED)) ...{
ResumeThread(pi.hThread);
}
return TRUE;
}
WINAPI
DetourCreateProcessWithDllW(LPCWSTR lpApplicationName,
__in_z LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation,
LPCSTR lpDetouredDllFullName,
LPCSTR lpDllName,
PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
... {
// 第一步:修改创建标志位
DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED);
PROCESS_INFORMATION pi;
if (pfCreateProcessW == NULL) ...{
pfCreateProcessW = CreateProcessW;
}
// 第二步:调用原始CreateProcessW
if (!pfCreateProcessW(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwMyCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
&pi)) ...{
return FALSE;
}
LPCSTR rlpDlls[2];
DWORD nDlls = 0;
if (lpDetouredDllFullName != NULL) ...{
rlpDlls[nDlls++] = lpDetouredDllFullName;
}
if (lpDllName != NULL) ...{
rlpDlls[nDlls++] = lpDllName;
}
// 第三步: 修改目标进程的输入表
if (!UpdateImports(pi.hProcess, rlpDlls, nDlls)) ...{
return FALSE;
}
if (lpProcessInformation) ...{
CopyMemory(lpProcessInformation, &pi, sizeof(pi));
}
// 第四步: 让目标进程的主线程继续运行
if (!(dwCreationFlags & CREATE_SUSPENDED)) ...{
ResumeThread(pi.hThread);
}
return TRUE;
}
呵呵,看出来了,原来detours使用的是修改输入表来实现dll的注入的,在来看其中最关键的函数UpdateImports,
BOOL WINAPI UpdateImports(HANDLE hProcess, LPCSTR
*
plpDlls, DWORD nDlls)
... {
BOOL fSucceeded = FALSE;
BYTE * pbNew = NULL;
DETOUR_EXE_RESTORE der;
DWORD i;
ZeroMemory(&der, sizeof(der));
der.cb = sizeof(der);
// 从 0x10000 开始寻找MEM_IMGAE标志的内存,然后验证其是否是exe
// 如果是那么返回其首地址
PBYTE pbModule = (PBYTE)FindExe(hProcess);
IMAGE_DOS_HEADER idh;
ZeroMemory(&idh, sizeof(idh));
// 读取 IMAGE_DOS_HEADER
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) ...{
DETOUR_TRACE(("ReadProcessMemory(idh) failed: %d ", GetLastError()));
finish:
if (pbNew != NULL) ...{
delete[] pbNew;
pbNew = NULL;
}
return fSucceeded;
}
CopyMemory(&der.idh, &idh,
... {
BOOL fSucceeded = FALSE;
BYTE * pbNew = NULL;
DETOUR_EXE_RESTORE der;
DWORD i;
ZeroMemory(&der, sizeof(der));
der.cb = sizeof(der);
// 从 0x10000 开始寻找MEM_IMGAE标志的内存,然后验证其是否是exe
// 如果是那么返回其首地址
PBYTE pbModule = (PBYTE)FindExe(hProcess);
IMAGE_DOS_HEADER idh;
ZeroMemory(&idh, sizeof(idh));
// 读取 IMAGE_DOS_HEADER
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) ...{
DETOUR_TRACE(("ReadProcessMemory(idh) failed: %d ", GetLastError()));
finish:
if (pbNew != NULL) ...{
delete[] pbNew;
pbNew = NULL;
}
return fSucceeded;
}
CopyMemory(&der.idh, &idh,