dll远线程注入
原理
核心函数
CreateRemoteThread:让在其他进程中创建一个线程变成可能
核心思想
HANDLE WINAPI CreateRemoteThread(
__in HANDLE hProcess,
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out LPDWORD lpThreadId
);
HMODULE
WINAPI
LoadLibraryW(
_In_ LPCWSTR lpLibFileName
);
CreateRemoteThread函数的第四个参数是线程函数,我们可以用LoadLibrary的函数地址作为线程函数地址。
CreateRemoteThread函数的第五个参数是线程函数参数。用要加载的dll路径作为线程函数的参数。
相当于用这个线程函数(LoadLibrary)把参数(dll路径)Load到“被注入的进程”里。
设计的巧合才出现了这一注入方式
代码实现
获取pid
OpenProcess这个函数有个参数是pid,获取pid的方式多种多样,我这里使用的是快照
1 //根据进程名找对应的pid(快照方式)
2 DWORD _getProcessHandle(LPCTSTR lpProcessName)
3 {
4 DWORD dwRet = 0;
5 HANDLE hSnapShot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
6 if (hSnapShot == INVALID_HANDLE_VALUE)
7 {
8 printf("\n获得进程快照失败,返回的GetLastError():%d", ::GetLastError());
9 return dwRet;
10 }
11
12 PROCESSENTRY32 pe32;
13 pe32.dwSize = sizeof(PROCESSENTRY32);
14 ::Process32First(hSnapShot, &pe32);
15 do
16 {
17 if (!lstrcmp(pe32.szExeFile, lpProcessName))
18 {
19 dwRet = pe32.th32ProcessID;
20 break;
21 }
22 } while (::Process32Next(hSnapShot, &pe32));
23 ::CloseHandle(hSnapShot);
24 return dwRet;
25 }
打开进程
hprocess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, _Pid);
在注入进程里申请空间
pAlloc = ::VirtualAllocEx(hprocess,NULL, _SIZE, MEM_COMMIT,PAGE_READWRITE);
因为我们需要找到那个参数(dll路径),在我本来的进程中,dll路径存放的地方和注入进程中dll路径存放的地方不是同一个地方,我们需要跨进程将dll路径写在注入进程中,下面起线程的时候才能找到存放dll路径的字符串
在申请的空间中写入数据
::WriteProcessMemory(hprocess, pAlloc, psDllFillName, _SIZE, NULL);
获得LoadLibraryW的地址
pThreadFunction = ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
由于Windows引入了基址随机化ASLR安全机制,所以导致每次开机启动时系统DLL加载基址都不一样,有些系统dll(kernel,ntdll)的加载地址,允许每次启动基址可以改变,但是启动之后必须固定,也就是说两个不同进程在相互的虚拟内存中,这样的系统dll地址总是一样的。
创建线程在注入进程中
hThread = ::CreateRemoteThread(hprocess, NULL, 0, (LPTHREAD_START_ROUTINE)pThreadFunction, pAlloc,0,NULL);
让这个线程loadlibrary
所有代码
1 #include <iostream>
2 #include <windows.h>
3 #include <TlHelp32.h>
4 #include "tchar.h"
5
6 //根据进程名找对应的pid(快照方式)
7 DWORD _getProcessHandle(LPCTSTR lpProcessName)
8 {
9 DWORD dwRet = 0;
10 HANDLE hSnapShot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
11 if (hSnapShot == INVALID_HANDLE_VALUE)
12 {
13 printf("\n获得进程快照失败,返回的GetLastError():%d", ::GetLastError());
14 return dwRet;
15 }
16
17 PROCESSENTRY32 pe32;
18 pe32.dwSize = sizeof(PROCESSENTRY32);
19 ::Process32First(hSnapShot, &pe32);
20 do
21 {
22 if (!lstrcmp(pe32.szExeFile, lpProcessName))
23 {
24 dwRet = pe32.th32ProcessID;
25 break;
26 }
27 } while (::Process32Next(hSnapShot, &pe32));
28 ::CloseHandle(hSnapShot);
29 return dwRet;
30 }
31
32
33 //打开一个进程并为其创建一个线程
34 DWORD _InjectThread(DWORD _Pid, LPCWSTR psDllFillName)
35 {
36 //打开进程
37 HANDLE hprocess;
38 HANDLE hThread;
39 DWORD _SIZE = 0;
40 LPVOID pAlloc = NULL;
41 DWORD psDllAddr = 0;
42 FARPROC pThreadFunction;
43 hprocess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, _Pid);
44 //在注入进程中写入Loadlibrary名称
45 _SIZE = (_tcslen(psDllFillName) + 1)* sizeof(TCHAR);
46 pAlloc = ::VirtualAllocEx(hprocess,NULL, _SIZE, MEM_COMMIT,PAGE_READWRITE);
47 if (pAlloc == NULL)
48 {
49 printf("VirtualAllocExERROR");
50 return FALSE;
51 }
52 BOOL x = ::WriteProcessMemory(hprocess, pAlloc, psDllFillName, _SIZE, NULL);
53 if (FALSE == x)
54 {
55 printf("WriteProcessMemoryERROR");
56 return FALSE;
57 }
58 //获得Loadlibrary的地址
59 pThreadFunction = ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
60 //在另一个进程创建一个线程
61 hThread = ::CreateRemoteThread(hprocess, NULL, 0, (LPTHREAD_START_ROUTINE)pThreadFunction, pAlloc,0,NULL);
62 if (hThread == NULL)
63 {
64 printf("CreateRemoteThreadError");
65 return FALSE;
66 }
67 WaitForSingleObject(hThread,-1);
68 GetExitCodeThread(hThread, &psDllAddr);
69 VirtualFreeEx(hprocess, pAlloc, _SIZE, MEM_DECOMMIT);
70 ::CloseHandle(hprocess);
71 return TRUE;
72 }
73 int main()
74 {
75 DWORD PID = _getProcessHandle(L"Test.exe");
76 _InjectThread(PID,L"MessageBox.dll");
77 }
实际上整个过程就是等效于在注入进程中自己LoadLibrary,只不过我们是在其他进程load这个dll
Dll文件
1 #include "pch.h"
2
3 BOOL APIENTRY DllMain( HMODULE hModule,
4 DWORD ul_reason_for_call,
5 LPVOID lpReserved
6 )
7 {
8 switch (ul_reason_for_call)
9 {
10 case DLL_PROCESS_ATTACH:
11 MessageBox(NULL, L"sucess!!!", L"注入", MB_OK);
12 case DLL_THREAD_ATTACH:
13 MessageBox(NULL, L"sucess!!!", L"注入", MB_OK);
14 case DLL_THREAD_DETACH:
15 case DLL_PROCESS_DETACH:
16 break;
17 }
18 return TRUE;
19 }
测试
一开始没有这个dll
注入后
说明注入成功