关于dll注入

前言

最近在学游戏实战逆向的一些东西,记些微不足道的笔记。之前也有做过关于dll注入的逆向题,当时官方wp是结合函数名泄露写dll注入解的,我复现的时候是照着别人的wp结合ce分析挖掘dump代码做的,因为不太理解dll注入,坑留到现在,所以先补一补dll注入的一些知识和API的学习

什么是dll注入

dll(Dynamic Link Library)意为动态链接库,一般dll文件里面通常包含各种功能实现的函数等。

dll注入就是将自己编写的dll注入到进程中去,常用的注入方式是远程线程注入,这里主要记录一下这种注入方式

DLL里编写实现我们功能的代码,在加载入进程中后让其立马执行

远程线程注入dll

常规步骤如下:

查找窗口,获取窗口的句柄

1
2
3
4
5
6
7
8
HWND hWnd = FindWindowA("Valve001", "Counter-Strike");
//第一个参数是类名,第二个参数是窗口名称,第一个参数可省略
//返回窗口句柄
if (NULL == hWnd)
{
MessageBox(NULL, "FindWindow Error", "error", MB_OK);
return;
}

根据窗口句柄,查找进程PID

1
2
3
4
DWORD DwPid = 0;
GetWindowThreadProcessId(hWnd, &DwPid);
//第一个参数是窗口句柄,第二个存储获取到的PID

根据进程PID,获得进程句柄

1
2
3
4
5
6
7
HANDLE hProHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DwPid);  
//参数一,选择所有权限;参数二,不继承给false;参数三,给上面获得的pid的值
if (NULL == hProHandle)
{
MessageBox(NULL, "OpenProcess Error", "error", MB_OK);
return;
}

给远程进程申请空间,并且返回空间的首地址

1
2
3
4
5
6
7
LPVOID lpAddr = VirtualAllocEx(hProHandle, NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
//参数一,进程句柄;参数二,NULL;参数三,空间字节大小;参数四,是否立即申请,(是)MEM_COMMIT;参数五,所申请的空间的权限
if (NULL == lpAddr)
{
MessageBox(NULL, "VirtualAlloc Error", "error", MB_OK);
return;
}

将要注入的DLL的路径写入进程内存中

1
2
3
const char* Path = "E:\\游戏逆向学习\\glCSEzCheat\\Release\\glCSEzCheat.dll";
WriteProcessMemory(hProHandle, lpAddr, Path, strlen(Path) + 1, NULL);
//参数一,进程句柄;参数二,写入目标地址;参数三,写入数据源地址;参数四,写入字节大小;参数五,NULL

远程进程开辟线程,调用LoadLibrary,加载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
HMODULE LDhm = LoadLibrary("Kernel32.dll");     //这里选择调用Kenel32.dll中的LoadlibraryA
if (LDhm == NULL)
{
MessageBox(NULL, "加载失败", "ERROR", MB_OK);
}
LPTHREAD_START_ROUTINE lpstart = (LPTHREAD_START_ROUTINE)GetProcAddress(LDhm, "LoadLibraryA");
//获取LoadLibraryA的函数地址

HANDLE hThreadHandle = CreateRemoteThread(hProHandle, NULL, 0, lpstart, lpAddr, 0, NULL);
//远程进程开辟线程,执行函数,加载dll

//第一个参数: 进程的句柄(你要往哪个进程开辟线程)
//第二个参数: 安全属性,句柄可否继承,不需要给NULL
//第三个参数: 栈的大小,给0则默认
//第四个参数: 函数执行,我们要开辟线程,开辟的线程叫做loadLibrary
//第五个参数: 开辟线程传入的参数,我们知道,线程只有一个参数,而现在正好load也是一个参数,所以加载的参数就是我们的
// 写入远程进程内存的dll路径,而dll路径一旦启动,则会执行自己的代码(核心,一定掌握)
//第六个参数: 创建的标志,默认给0
//第七个参数: 线程的ID,不需要知道,给NULL

if (hThreadHandle == NULL)
MessageBox(NULL, "CreatThread Error", "error", MB_OK);

WaitForSingleObject(hThreadHandle, INFINITE);
VirtualFreeEx(hProHandle, lpAddr, strlen(Path) + 1, MEM_DECOMMIT);
CloseHandle(hThreadHandle);
CloseHandle(hProHandle);
//收尾工作

调用退出代码,释放远程线程的dll

与注入类似,就是远线程调用FreeLibrary卸载DLL

参考资料

iBinary:https://www.cnblogs.com/iBinary/p/7898189.html

Comments