前言
首先想法是 强制创建一个目标进程的线程,把我自己的恶意DLL加载进去 被注入的DLL拥有目标进程内存的访问权限,所以我们可以通过该
向某个进程注入DLL时的方法主要有以下三种:
• 创建远程线程(CreateRemoteThread() API) • 使用注册表(AppInit_DLLs值) • 消息钩取(SetWindowsHookEx())
小试牛刀
目前尝试第一种: 1. 使用VirtualAllocEx()在目标进程的地址空间中创建一块我们DLL所在路径长度的内存空间。 2. 使用WriteProcessMemory()将DLL路径写入分配的内存。 3. 一旦DLL路径写入内存中,再使用CreateRemoteThread()(或者其他无正式说明的功能),它再调用LoadLibrary函数将DLL注入目标进程中。
代码:
- 使用VirtualAllocEx()在目标进程的地址空间中创建一块我们DLL所在路径长度的内存空间。
void process(int pid, char* path){ //获取进程的句柄 如果成功返回程序句柄,失败返回NULL HANDLE processHANDLE = OpenProcess(PROCESS_ALL_ACCESS, false,pid); //申请一块内存给DLL路径 LPVOID pReturnAddress = VirtualAllocEx(processHANDLE, NULL, strlen(path) + 1, MEM_COMMIT, PAGE_READWRITE);
- 然后使用WriteProcessMemory()把我们要载如的DLL路径写入到刚刚创建的DLL内存空间中
//写入路径到上一行代码申请的内存中去
WriteProcessMemory(processHANDLE,pReturnAddress,path,strlen(path)+1,NULL);
- 一旦DLL路径写入内存中,再使用CreateRemoteThread(或者其他无正式说明的功能),它再调用LoadLibrary()函数将我们的DLL注入目标进程中。
//获取函数模块句柄
HMODULE hmodule = GetModuleHandleA("KERNEL32.dll");
//获取DLL载入函数的地址
LPTHREAD_START_ROUTINE lpStartAddress =(LPTHREAD_START_ROUTINE)GetProcAddress(hmodule,"LoadLibraryA");
/* CreateRemoteThread()
hProcess:要在其中创建线程的进程的句柄
lpThreadAttributes:指向SECURITY_ATTRIBUTES结构的指针,一般为NULL
dwStackSize:一般为0
lpStartAddress:最重要的一个参数,表示远程进程中线程的起始地址
lpParameter:指向要传递给线程函数的变量的指针。
dwCreationFlags:控制线程创建的标志。
*/
CreateRemoteThread(processHANDLE,NULL,0,lpStartAddress,pReturnAddress,0,NULL);
第四个参数lpParameter
指向要传递给线程要执行的函数的变量(参数—)路径 也就是dll的路径)的指针。 整体代码如下:
/* 本程序是利用Windows API 实现远程线程注入 2021.4.19/20:24 */
#include <iostream>
#include <windows.h>
void process(int pid, char* path){
//获取进程的句柄 如果成功返回程序句柄,失败返回NULL
HANDLE processHANDLE = OpenProcess(PROCESS_ALL_ACCESS, false,pid);
//申请一块内存给DLL路径
LPVOID pReturnAddress = VirtualAllocEx(processHANDLE, NULL, strlen(path) + 1, MEM_COMMIT, PAGE_READWRITE);
//写入路径到上一行代码申请的内存中去
WriteProcessMemory(processHANDLE,pReturnAddress,path,strlen(path)+1,NULL);
//获取函数模块句柄
HMODULE hmodule = GetModuleHandleA("KERNEL32.dll");
//获取DLL载入函数的地址
LPTHREAD_START_ROUTINE lpStartAddress =(LPTHREAD_START_ROUTINE)GetProcAddress(hmodule,"LoadLibraryA");
/* CreateRemoteThread()
hProcess:要在其中创建线程的进程的句柄
lpThreadAttributes:指向SECURITY_ATTRIBUTES结构的指针,一般为NULL
dwStackSize:一般为0
lpStartAddress:最重要的一个参数,表示远程进程中线程的起始地址
lpParameter:指向要传递给线程函数的变量的指针。
dwCreationFlags:控制线程创建的标志。
*/
CreateRemoteThread(processHANDLE,NULL,0,lpStartAddress,pReturnAddress,0,NULL);
}
int main() {
const char *path ="C:\\Users\\86132\\Desktop\\libDLL.dll"; //这里做了一个强制类型转换
process(11620,(char*)path); //第一个参数是被注入进程的PID,第二个则是要注入dll的路径
return 0;
}
远程线程注入 优化
在多线程的情况下,有时候我们希望等待某一个线程完成后,再让程序继续调用其他线程 防止程序线程的阻塞
基于上面的注入代码做一个优化 我们利用GreateRemoteTread()函数,如果成功会返回线程的句柄
接下里介绍这个:
WaitForSingleObject函数
等待直到指定的对象处于发信号状态或超时间隔过去。
参数: hHandle 对象的句柄,必须具有SYNCHRONIZE访问权限
dwMilliseconds 超时间隔(以毫秒为单位)。 如果指定了非零值,则函数将等待,直到发出信号通知对象或间隔过去为止。 如果dwMilliseconds为零,则如果未用信号通知对象,则函数不会进入等待状态;否则,函数将进入等待状态。它总是立即返回。 如果dwMilliseconds为INFINITE,则仅在发出对象信号时该函数才会返回。也就是有多久等多久
//创建远程线程 并获取句柄 hThread
HANDLE hThread = CreateRemoteThread(processHANDLE,NULL,0,lpStartAddress,pReturnAddress,0,NULL);
//等待线程事件
WaitForSingleObject(hThread,2000);
这里等待2秒 还有一个小细节,利用closehandle()函数关闭打开的对象句柄。防止内存泄漏
//关掉句柄,防止内存泄漏
CloseHandle(hmodule);
CloseHandle(processHANDLE);