DLL注入

DLL注入(DLL Injection) 是渗透其他进程的最简单有效的方法,借助DLL注入技术,可以钩取API、改进程序、修复BUG等。

DLL 注入

DLL注入指的是向运行中的其他进程强制插入特定的DLL文件。从技术细节来说,DLL注入命令其他进程自行调用LoadLibrary() API,加载用户指定的DLL文件。DLL注入与一般DLL加载的区别在于,加载的目标进程是其自身或其他进程。
被注入的DLL与其他加载到进程中的dll一样,拥有访问进程内存的(正当)权限,就可以实现任何想做的事了。

DLL(Dynamic Linked Library,动态链接库)

DLL被加载到进程后会自动运行DllMain()函数,用户可以把想执行的代码放到DllMain()函数,每当加载Dll时,添加的代码就会自然而然得到执行。利用该特性可修复程序bug,或向程序添加新功能。
DllMain()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lobReserved)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_DETACH:
break;
}
return true;
}

DLL注入方法

  1. 创建远程线程(CreateRemoteThread)
  2. 使用注册表(AppInit_DLLs)
  3. 消息钩取(SetWindowHookEx)

CreateRemoteThread

编写myhack.dll注入notepad.exe,并弹出MessageBox。

Myhack.cpp源码

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
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "windows.h"

HMODULE g_hMod = NULL;

DWORD WINAPI ThreadProc(LPVOID lParam) {
MessageBox(NULL, L"注入成功", L"提示", MB_OK);
return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
HANDLE hThread = NULL;
g_hMod = hModule;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
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;
}

InjectDll.cpp 源码

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
#include "windows.h"
#include "tchar.h"
#include <iostream>

bool InjectDll(DWORD dwPID, char * szDllPath)
{
HANDLE hProcess = NULL, hThread = NULL;
HMODULE hMod = NULL;
LPVOID pRemoteBuf = NULL;
DWORD dwBufSize = (strlen(szDllPath) + 1) * sizeof(char);
LPTHREAD_START_ROUTINE pThreadProc;

// 使用pid获取目标进程
if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
{
std::cout << "OpenProcess " << dwPID << " failed. " << GetLastError() << std::endl;
return false;
}

// 在目标进程内存中分配szDllName大小的内存
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);

// 将myhack.dll路径写入分配的内存
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);

// 获取LoadLibraryW() API的地址
hMod = GetModuleHandle(L"kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryA");

// 在目标中进程中运行线程
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pThreadProc, pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);

return true;
}

int main(int argc, char *argv[])
{
if (argc != 3)
{
std::cout << "USAGE: " << argv[0] << " pid dll_path" << std::endl;
return 1;
}

if (InjectDll((DWORD)atol(argv[1]), argv[2]))
std::cout << "success!!!" << std::endl;
else
std::cout << " failed!!!" << std::endl;
return 0;
}

AppInit_DLLs

Windows操作系统的注册表中默认提供了AppInit_DLLs与LoadAppInit_DLLs两个注册表项。
在注册表编辑器中,将要注入的DLL的路径字符串写入AppInit_DLLs,然后把LoadAppInit_DLLs的值设置为1.重启后,指定DLL会注入运行进程。
AppInit_DLLs注册表,几乎可以向所有进程注入DLL文件。若被注入的DLL出现BUG,则有可能导致windows系统无法正常启动。

文章目录
  1. 1. DLL 注入
  2. 2. DLL注入方法
    1. 2.1. CreateRemoteThread
    2. 2.2. AppInit_DLLs