dll注入技术

由于学习hook技术过程中需要dll注入,递归学习至此

总体步骤

  1. 附加到目标/远程进程

  2. 在目标/远程进程内分配内存

  3. 将DLL文件路径,dll文件,复制到目标/远程进程的内存空间

  4. 控制进程运行dll文件

相关API

  • CreateRemoteThread()

  • NtCreateThreadEx()

  • QueueUserAPC()

  • SetWindowsHookEx()

  • RtlCreateUserThread()

  • SetThreadContext()

  • 反射DLL

实现方法

  • 创建远程线程

  • 使用注册表

  • 消息hook

注册表方法

Windows注册表中有AppInit_DLLs与LoadAppInit_DLLs两个注册表项,把要注入的DLL路径写入AppInit_DLLs,然后将LoadAppInit_DLLs项设置为1.重启后,指定DLL就会注入所有运行进程。

原理:user32.dll被加载到进程时,会读取AppInit_DLLs注册表项,如果有值,就加载到加载user32.dll的进程。WindowsXP会忽略LoadAppInit_DLLs的注册表项。

创建远程线程方法

  1. 获取目标进程句柄

  2. 将要注入的dll路径写入目标进程内存

  3. 获取LoadLibraryW() API地址

  4. 在目标进程中运行远程线程

注入器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <tchar.h>
#include <Windows.h>
#include <iostream>
#include <fstream>
#include <TlHelp32.h>
#include <comdef.h>

using namespace std;

#define DEF_PROCESS_NAME "notepad.exe"

LPVOID WriteFileAddress = NULL;
CREATE_PROCESS_DEBUG_INFO CreateProcessDebugInfomation;
BYTE INT3 = 0xCC, OldByte = 0;
/*
* @method 注入dll到指定进程
*/
BOOL injectDll(int pid, wchar_t* szDllPath) {

HANDLE hProcess = NULL, hThread = NULL;
HMODULE hMod = NULL;
LPVOID pRemoteBuf = NULL;
DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
LPTHREAD_START_ROUTINE pThreadProc;
// 使用pid获取目标进程句柄
if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid))) {
_tprintf(L"OpenProcess(%d) failed [%d]\n", pid,GetLastError());
return FALSE;
}
// 在目标进程中分配内存
// 这个API返回的地址是目标进程的地址
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
// 将dll写入内存
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);
// 获取LoadLibraryW() API地址
hMod = GetModuleHandle(L"kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");
// 运行线程
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
/*
* @method 遍历进程寻找notepad.exe的pid
*/
int traverseProcesses() {
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
printf("Create snap Error!\n");
return false;
}
BOOL bResult = Process32First(hProcessSnap, &pe32);
int num(0);
while (bResult) {
_bstr_t b(pe32.szExeFile); // 将宽字节转化为窄字节
if (!strcmp(b, "notepad.exe")) {
printf("[*] Find notepad.exe: %d\n", pe32.th32ProcessID);
return pe32.th32ProcessID;
}
bResult = Process32Next(hProcessSnap, &pe32);
}
return -1;
}
int _tmain(int argc, TCHAR* argv[]) {
wchar_t dllName[] = L"myhackdll.dll";
int pid = traverseProcesses();
if (pid == -1) {
printf("[-] Not found\n");
exit(-1);
}
if (injectDll(pid, dllName)) {
_tprintf(L"Inject success\n");
}
else {
_tprintf(L"Inject failed\n");
}
return 0;
}

myhackdll.dll代码(要注入的dll)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "pch.h"
#include <tchar.h>
#include <stdio.h>

// 加载静态链接库
#pragma comment(lib,"urlmon.lib")
// dllMain函数是程序的入口点
HMODULE g_hMod = NULL;

DWORD WINAPI ThreadProc(LPVOID lParam) {
TCHAR szPath[MAX_PATH] = { 0, };
if (!GetModuleFileName(g_hMod, szPath, MAX_PATH)) {
return FALSE;
}
FILE* f = fopen("Hello.txt","w");
if (!f)return FALSE;
fprintf(f, "Hello! You are hacked!\n");
fclose(f);
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
){
HANDLE hThread = NULL;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
OutputDebugString(L"myhack.dll Inject!!!");
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
CloseHandle(hThread);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

调试的方法

这里讲如何在调试器中看到dll注入后的效果

  1. 使用调试器attach后按f9继续运行

  2. 选项中选中”pause on new modules”

  3. 运行注入器,dll将在注入的dll入口点暂停

dll卸载

  1. 获取目标进程pid

  2. 获取进程加载的dll信息

  3. 获取FreeLibraryAPI地址

  4. 在目标进程中运行线程

SetWindowsHookEx方法

这同时也是一种hook方法,参见windows hook

参考资料

[1] 《逆向工程核心原理》