Win32 利用远程线程注入dll

Posted 不会写代码的丝丽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Win32 利用远程线程注入dll相关的知识,希望对你有一定的参考价值。

一些程序会利用CreateRemoteThread这个函数为其他进程创建一个线程,而传入的线程回调函数地址为kernel32.dllLoadLibraryA函数。
这个函数最原始的功能是用来加载动态库的,而且这个函数可以和最原始的线程回调函数声明是相同的。因此一些Hack利用这个特性来完成一些跨进程dll注入。

我们首先观察下这个函数

//kernel32.dll 
HMODULE
WINAPI
LoadLibraryA(_In_ LPCSTR lpLibFileName);

在对比下最原始的线程回调函数

typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(
    LPVOID lpThreadParameter
    );

可以发现两个函数传入的参数是一样的(单个参数且都可以视为char*),所以我们利用这个特性完成一些奇淫技巧(传入的参数为dll地址那不就可以加载一个库了吗)。

我们首先定下一个目标程序给其注入一个dll,并打印一个弹出窗口。

目标程序这里选取的计算器
在这里插入图片描述
我们的dll代码如下:

//dll被加载的时候会回调这个函数
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{

	OutputDebugString("Your was injected by test ");

    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
		MessageBox(NULL, "成功注入dll", "注入提示", MB_OK);
		break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


预期效果如下:
在这里插入图片描述

我们首先看CreateRemoteThread文档
CreateRemoteThread 文档

HANDLE CreateRemoteThread(
  HANDLE                 hProcess,//指定为哪一个进程创建线程
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,//安全属性
  SIZE_T                 dwStackSize, //指定栈大小
  LPTHREAD_START_ROUTINE lpStartAddress,//回调函数
  LPVOID                 lpParameter,//回调的参数
  DWORD                  dwCreationFlags,//创建一些标识符 我们传0即可
  LPDWORD                lpThreadId //线程id 可以传NULL
);

我们的大致流程:

  1. 寻找计算器的句柄
  2. 获取kernel32模块中的LoadLibraryA函数地址。
  3. 将dll字符串的内容拷贝到计算器进程
  4. 调用CreateRemoteThread为计算器进程创建线程,回调函数为LoadLibraryA,回调函数的传入参数为dll目录字符串地址
  5. 资源释放


int main()
{

	/**
	第一步:寻找计算器的句柄
	**/
	//返回窗口句柄
	HWND hWndCalc = FindWindow(NULL, "计算器");
	DWORD wdproId = 0;

	//获取窗口句柄对应的线程ID https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowthreadprocessid
	GetWindowThreadProcessId(hWndCalc, &wdproId);

	//返回进程的句柄
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, wdproId);


	/**
	第二步: 获取`kernel32`模块中的`LoadLibraryA`函数地址
	**/
	//得到加载kernel32模块的句柄
	HMODULE hModker = GetModuleHandle("kernel32");

	//从指定的动态链接库 (DLL) 中检索导出函数或变量的地址。
	LPVOID pLoadLibrary = GetProcAddress(hModker, "LoadLibraryA");


	/**
	第三步:  将dll字符串的内容拷贝到`计算器`进程
	**/
	char  szDllPath[] = { "C:\\\\Users\\\\fmy\\\\source\\\\repos\\\\MyDllProject\\\\x64\\\\Debug\\\\MyDllProject.dll" };
	//https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
	LPVOID  pPathBuf = VirtualAllocEx(hProcess, NULL, sizeof(szDllPath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

	if (pPathBuf == NULL)
	{
		return 0;

	}
	SIZE_T writeWord;
	WriteProcessMemory(hProcess, pPathBuf, szDllPath, sizeof(szDllPath), &writeWord);
	/**
	第四步:  调用`CreateRemoteThread`为计算器进程创建线程,回调函数为`LoadLibraryA`,回调函数的传入参数为dll目录字符串地址
	**/
	HANDLE hTread = CreateRemoteThread(
		hProcess,
		NULL,
		0,
		(LPTHREAD_START_ROUTINE)pLoadLibrary,
		(LPVOID)pPathBuf,
		0,
		NULL
	);


	/**
	第五步:资源释放
	**/
	WaitForSingleObject(hTread, INFINITE);
	BOOL result = VirtualFreeEx(hProcess, pPathBuf, 0, MEM_RELEASE);
	CloseHandle(hTread);


	return EXIT_SUCCESS;
}

需要注意一点:你要特别留意目标进程和dll库以及注入进程的位数必须要相同。比如全部都是64位等

为什么需要第三步: 将dll字符串的内容拷贝到计算器进程 ?
因为这个字符串内容现在在你的进程内存中,而对于计算器进程来说是不可以访问到的

以上是关于Win32 利用远程线程注入dll的主要内容,如果未能解决你的问题,请参考以下文章

远程线程DLL注入, 如何释放DLL和结束DLL的线程

安全之路 —— 利用远程线程注入的方法(使用DLL)实现穿墙与隐藏进程

Dll注入:X86/X64 远程线程CreateRemoteThread 注入

详细解读:远程线程注入DLL到PC版微信

32位程序注入64位DLL到64位进程

远程线程注入遇到的问题