dll注入与代码注入

时间:2023-01-12 12:47:14

学习《逆向工程核心原理》,在x64下dll注入与代码注入。

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
);
利用获取到的LoadLibraryW地址作为lpStartAddress,需注入进程中分配保存的dll名称作为lpParameter,实现动态加载dll

代码注入类似,主要用到VirtualAllocEx,WriteProcessMemory,在需注入的进程中开辟空间,写入代码,变量。

  1 #include "pch.h"
2 #include <windows.h>
3 #include <tchar.h>
4 #include <tlhelp32.h>
5 #include <stdio.h>
6 #include <shlobj.h>
7 extern void checkAdmin();
8
9 //遍历输出进程pid
10 int TraversalProcess() {
11 HANDLE hProceessnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
12 if (hProceessnap == INVALID_HANDLE_VALUE)
13 {
14 printf_s("创建进行快照失败\n");
15 return -1;
16 }
17 else
18 {
19 PROCESSENTRY32 pe32;
20 pe32.dwSize = sizeof(pe32);
21 BOOL hProcess = Process32First(hProceessnap, &pe32);
22 while (hProcess)
23 {
24 /*WCHAR * ProcessName =(WCHAR *)L"ProcessID.exe";
25 if (!wcscmp(pe32.szExeFile, ProcessName))
26 {*/
27 printf("进程名:%-10ls ----------------进程ID:%6d\n", pe32.szExeFile, pe32.th32ProcessID);
28 /* break;
29 }*/
30 hProcess = Process32Next(hProceessnap, &pe32);
31 }
32 }
33 CloseHandle(hProceessnap);
34 }
35
36 //设置权限
37 BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
38 {
39 TOKEN_PRIVILEGES tp;
40 HANDLE hToken;
41 LUID luid;
42
43 if (!OpenProcessToken(GetCurrentProcess(),
44 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
45 &hToken))
46 {
47 _tprintf(L"OpenProcessToken error: %u\n", GetLastError());
48 return FALSE;
49 }
50
51 if (!LookupPrivilegeValue(NULL, // lookup privilege on local system
52 lpszPrivilege, // privilege to lookup
53 &luid)) // receives LUID of privilege
54 {
55 _tprintf(L"LookupPrivilegeValue error: %u\n", GetLastError());
56 return FALSE;
57 }
58
59 tp.PrivilegeCount = 1;
60 tp.Privileges[0].Luid = luid;
61 if (bEnablePrivilege)
62 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
63 else
64 tp.Privileges[0].Attributes = 0;
65
66 // Enable the privilege or disable all privileges.
67 if (!AdjustTokenPrivileges(hToken,
68 FALSE,
69 &tp,
70 sizeof(TOKEN_PRIVILEGES),
71 (PTOKEN_PRIVILEGES)NULL,
72 (PDWORD)NULL))
73 {
74 _tprintf(L"AdjustTokenPrivileges error: %u\n", GetLastError());
75 return FALSE;
76 }
77
78 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
79 {
80 _tprintf(L"The token does not have the specified privilege. \n");
81 return FALSE;
82 }
83
84 return TRUE;
85 }
86
87 //dll注入
88 BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
89 {
90 HANDLE hProcess = NULL, hThread = NULL;
91 HMODULE hMod = NULL;
92 LPVOID pRemoteBuf = NULL;
93 DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
94 LPTHREAD_START_ROUTINE pThreadProc;
95
96 // #1. 使用dwPID请求对象进程(notepad.exe)的HANDLE。
97 if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
98 {
99 _tprintf(L"OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError());
100 return FALSE;
101 }
102
103 // #2. 在目标进程(notepad.exe)内存中分配与szDllName大小相同的内存。
104 pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
105
106 // #3. 在分配的内存中使用dll路径
107 WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);
108
109 // #4. 请求到LoadLibraryA() API地址。
110 hMod = GetModuleHandle(L"kernel32.dll");
111 pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");
112
113 // #5. 在notepad.exe进程中运行线程
114 hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
115 //通过CreateRemoteThread,调用pThreadProc,即LoadLibraryW,参数为在需注入进程中开辟的内存(存储了dll路径)
116
117 WaitForSingleObject(hThread, INFINITE);
118
119 CloseHandle(hThread);
120 CloseHandle(hProcess);
121
122 return TRUE;
123 }
124 //卸载dll
125 BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName)
126 {
127 BOOL bMore = FALSE, bFound = FALSE;
128 HANDLE hSnapshot, hProcess, hThread;
129 HMODULE hModule = NULL;
130 MODULEENTRY32 me = { sizeof(me) };
131 LPTHREAD_START_ROUTINE pThreadProc;
132 // dwPID = notepad 进程 ID
133 // 使用TH32CS_SNAPMODULE参数获得载入notepad程序的DLL名称
134 hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
135
136 bMore = Module32First(hSnapshot, &me);
137 for (; bMore; bMore = Module32Next(hSnapshot, &me))
138 {
139 if (!_tcsicmp((LPCTSTR)me.szModule, szDllName) ||
140 !_tcsicmp((LPCTSTR)me.szExePath, szDllName))
141 {
142 bFound = TRUE;
143 break;
144 }
145 }
146
147 if (!bFound)
148 {
149 CloseHandle(hSnapshot);
150 return FALSE;
151 }
152
153 if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
154 {
155 _tprintf(L"OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError());
156 return FALSE;
157 }
158
159 hModule = GetModuleHandle(L"kernel32.dll");
160 pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary");
161 hThread = CreateRemoteThread(hProcess, NULL, 0,
162 pThreadProc, me.modBaseAddr,
163 0, NULL);
164 WaitForSingleObject(hThread, INFINITE);
165
166 CloseHandle(hThread);
167 CloseHandle(hProcess);
168 CloseHandle(hSnapshot);
169
170 return TRUE;
171 }
172
173
174 //代码注入所需结构体
175 typedef struct _THREAD_PARAM
176 {
177 FARPROC pFunc[2]; // LoadLibraryA(), GetProcAddress()
178 char szBuf[4][128]; // "user32.dll", "MessageBoxA", "www.reversecore.com", "ReverseCore"
179 } THREAD_PARAM, *PTHREAD_PARAM;
180
181 typedef HMODULE(WINAPI *PFLOADLIBRARYA)
182 (
183 LPCSTR lpLibFileName
184 );
185
186 typedef FARPROC(WINAPI *PFGETPROCADDRESS)
187 (
188 HMODULE hModule,
189 LPCSTR lpProcName
190 );
191
192 typedef int (WINAPI *PFMESSAGEBOXA)
193 (
194 HWND hWnd,
195 LPCSTR lpText,
196 LPCSTR lpCaption,
197 UINT uType
198 );
199
200 //需注入的代码
201 DWORD WINAPI ThreadProc(LPVOID lParam)
202 {
203 PTHREAD_PARAM pParam = (PTHREAD_PARAM)lParam;
204 HMODULE hMod = NULL;
205 FARPROC pFunc = NULL;
206 //调用 LoadLibrary() 加载 "user32.dll"
207 hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]); // "user32.dll"
208 if (!hMod)
209 return 1;
210
211 //调用 GetProcAddress() 获取"MessageBoxA"
212 pFunc = (FARPROC)((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]); // "MessageBoxA"
213 if (!pFunc)
214 return 1;
215
216 // 调用MessageBoxA()
217 ((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK);
218 return 0;
219 }
220
221 //实现代码注入
222 BOOL InjectCode(DWORD dwPID)
223 {
224 HMODULE hMod = NULL;
225 THREAD_PARAM param = { 0, };
226 HANDLE hProcess = NULL;
227 HANDLE hThread = NULL;
228 LPVOID pRemoteBuf[2] = { 0, };
229 DWORD dwSize = 0;
230
231 hMod = GetModuleHandleA("kernel32.dll");
232
233 // set THREAD_PARAM
234 param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
235 param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
236 strcpy_s(param.szBuf[0], "user32.dll");
237 strcpy_s(param.szBuf[1], "MessageBoxA");
238 strcpy_s(param.szBuf[2], "这是code inject");
239 strcpy_s(param.szBuf[3], "好开心!");
240
241 // Open Process
242 if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, // dwDesiredAccess
243 FALSE, // bInheritHandle
244 dwPID))) // dwProcessId
245 {
246 printf("OpenProcess() fail : err_code = %d\n", GetLastError());
247 return FALSE;
248 }
249
250 // Allocation for THREAD_PARAM 写入代码注入所需的data
251 dwSize = sizeof(THREAD_PARAM);
252 if (!(pRemoteBuf[0] = VirtualAllocEx(hProcess, // hProcess
253 NULL, // lpAddress
254 dwSize, // dwSize
255 MEM_COMMIT, // flAllocationType
256 PAGE_READWRITE))) // flProtect
257 {
258 printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError());
259 return FALSE;
260 }
261 SIZE_T sz = 0;
262 if (!WriteProcessMemory(hProcess, // hProcess
263 pRemoteBuf[0], // lpBaseAddress
264 (LPVOID)&param, // lpBuffer
265 dwSize, // nSize
266 &sz)) // [out] lpNumberOfBytesWritten
267 {
268 printf("写入大小:%d\n", sz);
269 printf("THREAD_PARAM WriteProcessMemory() fail : err_code = %d\n", GetLastError());
270 return FALSE;
271 }
272
273 // Allocation for ThreadProc() 写入代码
274 dwSize = abs((int)((DWORD)InjectCode - (DWORD)ThreadProc));
275
276 printf("dwSize:%d\n", dwSize);
277 //dwSize = 1024;
278 if (!(pRemoteBuf[1] = VirtualAllocEx(hProcess, // hProcess
279 NULL, // lpAddress
280 dwSize, // dwSize
281 MEM_COMMIT, // flAllocationType
282 PAGE_EXECUTE_READWRITE))) // flProtect
283 {
284 printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError());
285 return FALSE;
286 }
287 sz = 0;
288 if (!WriteProcessMemory(hProcess, // hProcess
289 pRemoteBuf[1], // lpBaseAddress
290 (LPVOID)ThreadProc, // lpBuffer
291 dwSize, // nSize
292 &sz)) // [out] lpNumberOfBytesWritten
293 {
294 printf("写入大小:%d\n", sz);
295 printf("ThreadProc() WriteProcessMemory() fail : err_code = %d\n", GetLastError());
296 return FALSE;
297 }
298 printf("ThreadProc()写入大小:%d\n", sz);
299 if (!(hThread = CreateRemoteThread(hProcess, // hProcess
300 NULL, // lpThreadAttributes
301 0, // dwStackSize
302 (LPTHREAD_START_ROUTINE)pRemoteBuf[1], // dwStackSize
303 pRemoteBuf[0], // lpParameter
304 0, // dwCreationFlags
305 NULL))) // lpThreadId
306 {
307 printf("CreateRemoteThread() fail : err_code = %d\n", GetLastError());
308 return FALSE;
309 }
310
311 WaitForSingleObject(hThread, INFINITE);
312 CloseHandle(hThread);
313 CloseHandle(hProcess);
314 printf("code inject end\n");
315 return TRUE;
316 }
317
318
319 int _tmain(int argc, TCHAR *argv[])
320 {
321 /*if (argc != 3)
322 {
323 _tprintf(L"USAGE : %s <pid> <dll_path>\n", argv[0]);
324 return 1;
325 }*/
326 // change privilege
327 // 判断当前进程是否以管理员身份运行
328 checkAdmin();
329 /*if (!SetPrivilege(SE_DEBUG_NAME, TRUE))
330 return 1;*/
331 //TraversalProcess();
332 TCHAR pid[10];
333 TCHAR path[MAX_PATH];
334 system("tasklist");
335 printf("ok\n");
336 printf("输入要注入的进程pid:\n");
337 scanf_s("%ls", pid, 10);
338 printf("请选择功能:1.dll注入 2.代码注入\n");
339 int flag = 0;
340 scanf_s("%d", &flag, 1);
341 if (flag == 1) {
342 printf("输入要注入的dll路径:");
343 scanf_s("%ls", path,MAX_PATH);
344 // inject dll
345 if (InjectDll((DWORD)_tstol(pid), path))
346 _tprintf(L"InjectDll(\"%s\") success!!!\n", path);
347 else
348 _tprintf(L"InjectDll(\"%s\") failed!!!\n", path);
349 printf("输入q 卸载dll\n");
350 while (getchar() != 'q');
351 TCHAR *p = _tcsrchr(path, '\\');
352 if(EjectDll((DWORD)_tstol(pid), p+1))
353 printf("卸载dll成功!\n");
354 else
355 {
356 printf("卸载失败!\n");
357 }
358
359 system("pause");
360 return 0;
361 }
362 else if (flag == 2)
363 {
364 InjectCode((DWORD)_tstol(pid));
365 system("pause");
366 return 0;
367 }
368 else
369 {
370 system("pause");
371 return 0;
372 }
373 }

判断当前运行时的权限,以管理员身份运行。

 1 BOOL    IsAdmin(HANDLE hProcess)
2 {
3 HANDLE hToken = NULL;
4 OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
5
6 TOKEN_ELEVATION_TYPE tokenType = TokenElevationTypeDefault; // 用于接收令牌类型
7
8 DWORD dwRetSize = 0; // 用于接收函数输出信息的字节数
9
10 // 2. 查询进程令牌中的权限提升值.( 这个值会记录当前的令牌是何种类型( 细节在17_权限管理_令牌的获取.cpp ) )
11 GetTokenInformation(hToken,
12 TokenElevationType,// 获取令牌的当前提升等级
13 &tokenType,
14 sizeof(tokenType),
15 &dwRetSize // 所需缓冲区的字节数
16 );
17
18
19 // 根据令牌的类型来输出相应的信息
20 if (TokenElevationTypeFull == tokenType) {
21 // 3. 如果令牌是TokenElevationTypeFull , 则拥有至高无上的能力,可以给令牌添加任何特权
22 printf("管理员账户,并拥有全部的权限,可以给令牌添加任何特权\n");
23 return TRUE;
24 }
25 // 4. 如果是其他的, 则需要以管理员身份重新运行本进程. 这样就能以第三步的方法解决剩下的问题.
26 else if (TokenElevationTypeDefault == tokenType) {
27 printf("默认用户, 可能是一个普通用户, 可能是关闭UAC时登录的管理员用户\n");
28
29 // 调用系统函数IsUserAnAdmin, 进一步确定是普通用户还是管理员用户
30 return IsUserAnAdmin();
31 }
32 else if (TokenElevationTypeLimited == tokenType) {
33
34 // 判断受限制的用户是管理员
35 // 如果是管理员, 则这个令牌中会保存有管理员的SID
36
37 // 1. 获取系统内键管理员用户的SID
38 SID adminSid;
39 DWORD dwSize = sizeof(adminSid);
40 CreateWellKnownSid(WinBuiltinAdministratorsSid, // 获取SID的类型,这里是系统内键管理员
41 NULL, // 传NULL,获取本地计算机的管理员
42 &adminSid,// 函数输出的管理员SID
43 &dwSize // 输入结构的大小,也作为输出
44 );
45
46 // 获取本令牌的连接令牌(受限制的令牌都会有一个连接的令牌,受限制的令牌正式由主令牌所创建的. )
47 TOKEN_LINKED_TOKEN linkToken;
48 GetTokenInformation(hToken,
49 TokenLinkedToken, // 获取连接的令牌句柄
50 &linkToken,
51 sizeof(linkToken),
52 &dwSize
53 );
54
55 // 在连接的令牌中查找是否具有管理员的SID
56 BOOL bIsContain = FALSE; // 用于保存是否包含.
57 CheckTokenMembership(linkToken.LinkedToken, // 在这个令牌中检查
58 &adminSid, // 检查令牌中是否包含此SID
59 &bIsContain); // 输出TRUE则包含,反之不包含
60
61
62
63 if (bIsContain) {
64 printf("权限被阉割的受限制管理员账户, 部分权限被移处理\n");
65 }
66
67
68 return bIsContain; // 不是以管理员权限运行
69 }
70
71 return FALSE;
72 }
73
74 void checkAdmin() {
75 if (!IsAdmin(GetCurrentProcess())) {
76
77 // 以管理员身份运行本进程
78 // 1 获取本进程的文件路径.
79 TCHAR path[MAX_PATH] = { 0 }; // 需要初始化
80 DWORD dwPathSize = MAX_PATH;
81 QueryFullProcessImageName(GetCurrentProcess(), 0,
82 path,
83 &dwPathSize);
84
85 // 2 调用创建进程的API运行本进程.
86 ShellExecute(NULL, // 窗口句柄,没有则填NULL
87 _T("runas"), // 以管理员身份运行的重要参数
88 path, // 所有运行的程序的路径(这里是本进程)
89 NULL, // 命令行参数
90 NULL, // 新进程的工作目录的路径
91 SW_SHOW // 创建后的显示标志(最小化,最大化, 显示,隐藏等)
92 );
93
94 // 退出本进程
95 ExitProcess(0);
96 }
97 }