平常用的最多的dll注入技术就是远程线程,刚刚逛看雪,看到有人写的面试的时候被问到的问题,其中就有dll注入的方法,我突然想到我开始面试的时候也被问了dll注入的方法,当时也是就只知道一个远程线程,答的也不好,然后就想把一些注入技术写个总结。接下来讲的注入技术,有ring3层的lld的远程线程和apc注入,还有ring0的apc注入,此外还有更为隐蔽的代码注入。
先写最广泛的,也是相对简单的注入方式,远程线程。
一 ring3 dll的远程线程
我写的涉及到x86和x64的注入,因为x64的系统本身增加了较多权限的校验,需要进行提权处理。所以先进行系统版本的校验:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61typedef enum _WIN_VERSION { WindowsNT, Windows2000, WindowsXP, Windows2003, WindowsVista, Windows7, Windows8, WinUnknown }WIN_VERSION; WIN_VERSION GetWindowsVersion() { OSVERSIONINFOEX OsVerInfoEx; OsVerInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((OSVERSIONINFO *)&OsVerInfoEx); // 注意转换类型 switch (OsVerInfoEx.dwPlatformId) { case VER_PLATFORM_WIN32_NT: { if (OsVerInfoEx.dwMajorVersion <= 4 ) { return WindowsNT; } if (OsVerInfoEx.dwMajorVersion == 5 && OsVerInfoEx.dwMinorVersion == 0) { return Windows2000; } if (OsVerInfoEx.dwMajorVersion == 5 && OsVerInfoEx.dwMinorVersion == 1) { return WindowsXP; } if (OsVerInfoEx.dwMajorVersion == 5 && OsVerInfoEx.dwMinorVersion == 2) { return Windows2003; } if (OsVerInfoEx.dwMajorVersion == 6 && OsVerInfoEx.dwMinorVersion == 0) { return WindowsVista; } if (OsVerInfoEx.dwMajorVersion == 6 && OsVerInfoEx.dwMinorVersion == 1) { return Windows7; } if (OsVerInfoEx.dwMajorVersion == 6 && OsVerInfoEx.dwMinorVersion == 2 ) { return Windows8; } break; } default: { return WinUnknown; } } }
x86和x64的注入最主要的不同点就是对于x64的提权处理,接下来先讲x64的提权处理。
x64的提权主要就是用到了ntdll.dll中未导出的一个函数,RtlAdjustPrivilege(),这个函数的作用是很大的,之前的瞬间关机的代码就是用了这个函数进行提权。
1
2
3
4
5
6/* .常量 SE_BACKUP_PRIVILEGE, "17", 公开 .常量 SE_RESTORE_PRIVILEGE, "18", 公开 .常量 SE_SHUTDOWN_PRIVILEGE, "19", 公开 .常量 SE_DEBUG_PRIVILEGE, "20", 公开 */
我们提升的权限就是SE_DEBUG_PRIVILEGE 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285//程序编译成64位可以注入64位 编译成32位可以注入32位 CWinApp theApp; typedef enum _WIN_VERSION { WindowsNT, Windows2000, WindowsXP, Windows2003, WindowsVista, Windows7, Windows8, WinUnknown }WIN_VERSION; VOID InjectDll(ULONG_PTR ProcessID); WIN_VERSION GetWindowsVersion(); BOOL InjectDllByRemoteThread32(const TCHAR* wzDllFile, ULONG_PTR ProcessId); WIN_VERSION WinVersion = WinUnknown; BOOL InjectDllByRemoteThread64(const TCHAR* wzDllFile, ULONG_PTR ProcessId); typedef long (__fastcall *pfnRtlAdjustPrivilege64)(ULONG,ULONG,ULONG,PVOID); pfnRtlAdjustPrivilege64 RtlAdjustPrivilege; int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { cout<<"查看要注入进程的ID"<<endl; ULONG_PTR ProcessID = 0; WinVersion = GetWindowsVersion(); printf("Input ProcessIDrn"); cin>>ProcessID; InjectDll(ProcessID); return 0; } VOID InjectDll(ULONG_PTR ProcessID) { CString strPath32 = L"MessageBox32.dll"; //32位dll注入32位系统 CString strPath64 = L"MessageBox64.dll"; if (ProcessID == 0) { return; } if (PathFileExists(strPath32)&&PathFileExists(strPath64)) { switch(WinVersion) { case Windows7: //这里用的是Win7 x64 sp1 { WCHAR wzPath[MAX_PATH] = {0}; GetCurrentDirectory(260,wzPath); wcsncat_s(wzPath, L"\", 2); wcsncat_s(wzPath, strPath64.GetBuffer(), strPath64.GetLength());//dll完整路径 strPath32.ReleaseBuffer(); if (!InjectDllByRemoteThread64(wzPath,ProcessID)) printf("Inject Failrn"); else printf ("Inject Successrn"); break; } case WindowsXP: //WinXp x86 sp3 { WCHAR wzPath[MAX_PATH] = {0}; GetCurrentDirectory(260,wzPath); wcsncat_s(wzPath, L"\", 2); wcsncat_s(wzPath, strPath32.GetBuffer(), strPath32.GetLength()); strPath32.ReleaseBuffer(); if (!InjectDllByRemoteThread32(wzPath,ProcessID)) printf("Inject Failrn"); else printf("Inject Successrn"); break; } } } } BOOL InjectDllByRemoteThread64(const TCHAR* wzDllFile, ULONG_PTR ProcessId) { if (NULL == wzDllFile || 0 == ::_tcslen(wzDllFile) || ProcessId == 0 || -1 == _taccess(wzDllFile, 0)) { return FALSE; } HANDLE hProcess = NULL; HANDLE hThread = NULL; DWORD dwRetVal = 0; LPTHREAD_START_ROUTINE FuncAddress = NULL; DWORD dwSize = 0; TCHAR* VirtualAddress = NULL; //预编译,支持Unicode #ifdef _UNICODE FuncAddress = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryW"); #else FuncAddress = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryA"); #endif if (FuncAddress==NULL) { return FALSE; } RtlAdjustPrivilege=(pfnRtlAdjustPrivilege64)GetProcAddress((HMODULE)(FuncAddress(L"ntdll.dll")),"RtlAdjustPrivilege"); if (RtlAdjustPrivilege==NULL) { return FALSE; } /* .常量 SE_BACKUP_PRIVILEGE, "17", 公开 .常量 SE_RESTORE_PRIVILEGE, "18", 公开 .常量 SE_SHUTDOWN_PRIVILEGE, "19", 公开 .常量 SE_DEBUG_PRIVILEGE, "20", 公开 */ RtlAdjustPrivilege(20,1,0,&dwRetVal); //19 hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, ProcessId); if (NULL == hProcess) { printf("Open Process Failrn"); return FALSE; } // 在目标进程中分配内存空间 dwSize = (DWORD)::_tcslen(wzDllFile) + 1; VirtualAddress = (TCHAR*)::VirtualAllocEx(hProcess, NULL, dwSize * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE); if (NULL == VirtualAddress) { printf("Virtual Process Memory Failrn"); CloseHandle(hProcess); return FALSE; } // 在目标进程的内存空间中写入所需参数(模块名) if (FALSE == ::WriteProcessMemory(hProcess, VirtualAddress, (LPVOID)wzDllFile, dwSize * sizeof(TCHAR), NULL)) { printf("Write Data Failrn"); VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); CloseHandle(hProcess); return FALSE; } hThread = ::CreateRemoteThread(hProcess, NULL, 0, FuncAddress, VirtualAddress, 0, NULL); if (NULL == hThread) { printf("CreateRemoteThread Failrn"); VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); CloseHandle(hProcess); return FALSE; } // 等待远程线程结束 WaitForSingleObject(hThread, INFINITE); // 清理资源 VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); CloseHandle(hThread); CloseHandle(hProcess); return TRUE; } BOOL InjectDllByRemoteThread32(const TCHAR* wzDllFile, ULONG_PTR ProcessId) { // 参数无效 if (NULL == wzDllFile || 0 == ::_tcslen(wzDllFile) || ProcessId == 0 || -1 == _taccess(wzDllFile, 0)) { return FALSE; } HANDLE hProcess = NULL; HANDLE hThread = NULL; DWORD dwSize = 0; TCHAR* VirtualAddress = NULL; LPTHREAD_START_ROUTINE FuncAddress = NULL; // 获取目标进程句柄 hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, ProcessId); if (NULL == hProcess) { printf("Open Process Failrn"); return FALSE; } // 在目标进程中分配内存空间 dwSize = (DWORD)::_tcslen(wzDllFile) + 1; VirtualAddress = (TCHAR*)::VirtualAllocEx(hProcess, NULL, dwSize * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE); if (NULL == VirtualAddress) { printf("Virtual Process Memory Failrn"); CloseHandle(hProcess); return FALSE; } // 在目标进程的内存空间中写入所需参数(模块名) if (FALSE == ::WriteProcessMemory(hProcess, VirtualAddress, (LPVOID)wzDllFile, dwSize * sizeof(TCHAR), NULL)) { printf("Write Data Failrn"); VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); CloseHandle(hProcess); return FALSE; } // 从 Kernel32.dll 中获取 LoadLibrary 函数地址 #ifdef _UNICODE FuncAddress = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryW"); #else FuncAddress = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryA"); #endif if (NULL == FuncAddress) { printf("Get LoadLibrary Failrn"); VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); CloseHandle(hProcess); return false; } // 创建远程线程调用 LoadLibrary hThread = ::CreateRemoteThread(hProcess, NULL, 0, FuncAddress, VirtualAddress, 0, NULL); if (NULL == hThread) { printf("CreateRemoteThread Failrn"); VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); CloseHandle(hProcess); return FALSE; } // 等待远程线程结束 WaitForSingleObject(hThread, INFINITE); // 清理 VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); CloseHandle(hThread); CloseHandle(hProcess); return TRUE; } WIN_VERSION GetWindowsVersion() { OSVERSIONINFOEX OsVerInfoEx; OsVerInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((OSVERSIONINFO *)&OsVerInfoEx); // 注意转换类型 switch (OsVerInfoEx.dwPlatformId) { case VER_PLATFORM_WIN32_NT: { if (OsVerInfoEx.dwMajorVersion <= 4 ) { return WindowsNT; } if (OsVerInfoEx.dwMajorVersion == 5 && OsVerInfoEx.dwMinorVersion == 0) { return Windows2000; } if (OsVerInfoEx.dwMajorVersion == 5 && OsVerInfoEx.dwMinorVersion == 1) { return WindowsXP; } if (OsVerInfoEx.dwMajorVersion == 5 && OsVerInfoEx.dwMinorVersion == 2) { return Windows2003; } if (OsVerInfoEx.dwMajorVersion == 6 && OsVerInfoEx.dwMinorVersion == 0) { return WindowsVista; } if (OsVerInfoEx.dwMajorVersion == 6 && OsVerInfoEx.dwMinorVersion == 1) { return Windows7; } if (OsVerInfoEx.dwMajorVersion == 6 && OsVerInfoEx.dwMinorVersion == 2 ) { return Windows8; } break; } default: { return WinUnknown; } } }
二 ring3 apc注入
APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下:
1)当EXE里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断。
2)当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数。
3)利用QueueUserAPC()这个API可以在软中断时向线程的APC队列插入一个函数指针,如果我们插入的是Loadlibrary()执行函数的话,就能达到注入DLL的目的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105#define _WIN32_WINNT 0x0400 #include <windows.h> #include <TlHelp32.h> #include <iostream> #include <string> using namespace std; #define DEF_BUF_SIZE 1024 typedef long (__fastcall *pfnRtlAdjustPrivilege64)(ULONG,ULONG,ULONG,PVOID); pfnRtlAdjustPrivilege64 RtlAdjustPrivilege; // 用于存储注入模块DLL的路径全名 char szDllPath[DEF_BUF_SIZE] = {0} ; // 使用APC机制向指定ID的进程注入模块 BOOL InjectModuleToProcessById ( DWORD dwProcessId ) { DWORD dwRet = 0 ; BOOL bStatus = FALSE ; LPVOID lpData = NULL ; UINT uLen = strlen(szDllPath) + 1; #ifdef _WIN64 // x64 OpenProcess提权操作 RtlAdjustPrivilege=(pfnRtlAdjustPrivilege64)GetProcAddress((HMODULE)(FuncAddress(L"ntdll.dll")),"RtlAdjustPrivilege"); if (RtlAdjustPrivilege==NULL) { return FALSE; } /* .常量 SE_BACKUP_PRIVILEGE, "17", 公开 .常量 SE_RESTORE_PRIVILEGE, "18", 公开 .常量 SE_SHUTDOWN_PRIVILEGE, "19", 公开 .常量 SE_DEBUG_PRIVILEGE, "20", 公开 */ RtlAdjustPrivilege(20,1,0,&dwRetVal); //19 #endif // 打开目标进程 HANDLE hProcess = OpenProcess ( PROCESS_ALL_ACCESS, FALSE, dwProcessId ) ; if ( hProcess ) { // 分配空间 lpData = VirtualAllocEx ( hProcess, NULL, uLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE ) ; if ( lpData ) { // 写入需要注入的模块路径全名 bStatus = WriteProcessMemory ( hProcess, lpData, szDllPath, uLen, &dwRet ) ; } CloseHandle ( hProcess ) ; } if ( bStatus == FALSE ) return FALSE ; // 创建线程快照 THREADENTRY32 te32 = { sizeof(THREADENTRY32) } ; HANDLE hThreadSnap = CreateToolhelp32Snapshot ( TH32CS_SNAPTHREAD, 0 ) ; if ( hThreadSnap == INVALID_HANDLE_VALUE ) return FALSE ; bStatus = FALSE ; // 枚举所有线程 if ( Thread32First ( hThreadSnap, &te32 ) ) { do{ // 判断是否目标进程中的线程 if ( te32.th32OwnerProcessID == dwProcessId ) { // 打开线程 HANDLE hThread = OpenThread ( THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID ) ; if ( hThread ) { // 向指定线程添加APC DWORD dwRet = QueueUserAPC ( (PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)lpData ) ; if ( dwRet > 0 ) bStatus = TRUE ; CloseHandle ( hThread ) ; } } }while ( Thread32Next ( hThreadSnap, &te32 ) ) ; } CloseHandle ( hThreadSnap ) ; return bStatus; } int _tmain(int argc, _TCHAR* argv[]) { // 取得当前工作目录路径 GetCurrentDirectoryA ( DEF_BUF_SIZE, szDllPath ) ; // 生成注入模块DLL的路径全名 strcat ( szDllPath, "\DLLSample.dll" ) ; DWORD dwProcessId = 0 ; // 接收用户输入的目标进程ID while ( cout << "请输入目标进程ID:" && cin >> dwProcessId && dwProcessId > 0 ) { BOOL bRet = InjectModuleToProcessById ( dwProcessId ) ; cout << (bRet ? "注入成功!":"注入失败!") << endl ; } return 0; }
三ring3层的远程线程的代码注入
代码是成功,但是每次运行就explorer直接崩溃。我开始还以为是我程序写的有问题,后来用WinDbg Attach到explorer进程调试,才发现问题,就是函数调用的问题,在汇编中call调用函数时不是绝对地址,机器码是相对偏移,这就涉及到函数的便宜重新重定位的问题,得不偿失,代价太大。仅仅以学习为目的的话,可以考虑用0day中非常经典的类似于GetProcAddress()函数实现的191个字节的shellcode来获取函数地址。先放上代码吧,在Windbg中对explorer中的RemoteCodeAddr下断点,是可以执行到那的,然后执行到call MessageBox就崩溃,就是函数的偏移的问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71#include "stdafx.h" #include <iostream> #include <Windows.h> using namespace std; typedef long (__fastcall *pfnRtlAdjustPrivilege64)(ULONG,ULONG,ULONG,PVOID); pfnRtlAdjustPrivilege64 RtlAdjustPrivilege; static DWORD WINAPI MyFunc (LPVOID pData) { //do something //... //pData输入项可以是任何类型值 // ::MessageBoxA(NULL,(char*)pData,"INJECT",0); //不能直接调用 //调用函数时要考虑call RVA 都是相对的偏移, return *(DWORD*)pData; } static void AfterMyFunc (void) { } int _tmain(int argc, _TCHAR* argv[]) { DWORD cbCodeSize = (ULONG_PTR)AfterMyFunc-(ULONG_PTR)MyFunc +0x100; DWORD ProcessId = 0; cin>>ProcessId; #ifdef _WIN64 // x64 OpenProcess提权操作 RtlAdjustPrivilege=(pfnRtlAdjustPrivilege64)GetProcAddress((HMODULE)(GetModuleHandle(L"ntdll.dll")),"RtlAdjustPrivilege"); if (RtlAdjustPrivilege==NULL) { return FALSE; } /* .常量 SE_BACKUP_PRIVILEGE, "17", 公开 .常量 SE_RESTORE_PRIVILEGE, "18", 公开 .常量 SE_SHUTDOWN_PRIVILEGE, "19", 公开 .常量 SE_DEBUG_PRIVILEGE, "20", 公开 */ DWORD dwReturnVal; RtlAdjustPrivilege(20,1,0,&dwReturnVal); //19 #endif HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, ProcessId); //申请放置代码的内存 PVOID RemoteCodeAddr = (PVOID)VirtualAllocEx( hProcess, 0, cbCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); WriteProcessMemory( hProcess, RemoteCodeAddr, &MyFunc, cbCodeSize, NULL); char szBuffer[] = "HelloWorld"; PVOID RemoteDataAddr = (PVOID)VirtualAllocEx( hProcess, 0, sizeof(szBuffer), MEM_COMMIT, PAGE_READWRITE ); WriteProcessMemory( hProcess, RemoteDataAddr, szBuffer, sizeof(szBuffer), NULL); HANDLE hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) RemoteCodeAddr, RemoteDataAddr, 0 , NULL); DWORD h; if (hThread) { ::WaitForSingleObject( hThread, INFINITE ); ::CloseHandle( hThread ); } //cout<<dwSizeOfMyFunc<<endl; return 0; }
四ring0的apc注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652#include "stdafx.h" #include <iostream> #include <Windows.h> #include <WinIoCtl.h> using namespace std; #define CTL_KEINJECTAPC CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS) typedef struct _INJECT_INFO { ULONG ProcessId; wchar_t DllName[1024]; }INJECT_INFO,*PINJECT_INFO; int _tmain(int argc, _TCHAR* argv[]) { HANDLE hFile; INJECT_INFO InjectInfo; hFile=CreateFile(L"\\.\DriverLink", GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_EXISTING,0,NULL); if(hFile==INVALID_HANDLE_VALUE) { printf("nError: Unable to connect to the driver (%d)n",GetLastError()); return -1; } memset(&InjectInfo,0,sizeof(INJECT_INFO)); scanf("%d",&(InjectInfo.ProcessId)); wscanf(L"%s",InjectInfo.DllName); DWORD dwReturnSize = 0; DWORD dwRet = 0; dwRet = DeviceIoControl(hFile,CTL_KEINJECTAPC, // &InjectInfo, sizeof(INJECT_INFO), NULL, NULL, &dwReturnSize, NULL); CloseHandle(hFile); return 0; } #include <ntifs.h> #include <devioctl.h> #include <ntimage.h> #endif #define DEVICE_NAME L"\Device\DriverDevice" #define LINK_NAME L"\DosDevices\DriverLink" #define CTL_KEINJECTAPC CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_ANY_ACCESS) typedef struct _SYSTEM_THREAD_INFORMATION { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER CreateTime; ULONG WaitTime; PVOID StartAddress; CLIENT_ID ClientId; KPRIORITY Priority; LONG BasePriority; ULONG ContextSwitches; ULONG ThreadState; KWAIT_REASON WaitReason; }SYSTEM_THREAD_INFORMATION,*PSYSTEM_THREAD_INFORMATION; typedef struct _SYSTEM_PROCESS_INFO { ULONG NextEntryOffset; ULONG NumberOfThreads; LARGE_INTEGER WorkingSetPrivateSize; ULONG HardFaultCount; ULONG NumberOfThreadsHighWatermark; ULONGLONG CycleTime; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ImageName; KPRIORITY BasePriority; HANDLE UniqueProcessId; HANDLE InheritedFromUniqueProcessId; ULONG HandleCount; ULONG SessionId; ULONG_PTR UniqueProcessKey; SIZE_T PeakVirtualSize; SIZE_T VirtualSize; ULONG PageFaultCount; SIZE_T PeakWorkingSetSize; SIZE_T WorkingSetSize; SIZE_T QuotaPeakPagedPoolUsage; SIZE_T QuotaPagedPoolUsage; SIZE_T QuotaPeakNonPagedPoolUsage; SIZE_T QuotaNonPagedPoolUsage; SIZE_T PagefileUsage; SIZE_T PeakPagefileUsage; SIZE_T PrivatePageCount; LARGE_INTEGER ReadOperationCount; LARGE_INTEGER WriteOperationCount; LARGE_INTEGER OtherOperationCount; LARGE_INTEGER ReadTransferCount; LARGE_INTEGER WriteTransferCount; LARGE_INTEGER OtherTransferCount; SYSTEM_THREAD_INFORMATION Threads[1]; }SYSTEM_PROCESS_INFO,*PSYSTEM_PROCESS_INFO; typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; }; union { ULONG TimeDateStamp; PVOID LoadedImports; }; struct _ACTIVATION_CONTEXT * EntryPointActivationContext; PVOID PatchInformation; LIST_ENTRY ForwarderLinks; LIST_ENTRY ServiceTagLinks; LIST_ENTRY StaticLinks; }LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY; typedef struct _INJECT_INFO { ULONG ProcessId; wchar_t DllName[1024]; }INJECT_INFO,*PINJECT_INFO; typedef NTSTATUS (*PLDR_LOAD_DLL)(PWSTR,PULONG,PUNICODE_STRING,PVOID*); typedef struct _KINJECT { UNICODE_STRING DllName; wchar_t Buffer[1024]; PLDR_LOAD_DLL LdrLoadDll; PVOID DllBase; ULONG Executed; }KINJECT,*PKINJECT; typedef enum _KAPC_ENVIRONMENT { OriginalApcEnvironment, AttachedApcEnvironment, CurrentApcEnvironment, InsertApcEnvironment }KAPC_ENVIRONMENT,*PKAPC_ENVIRONMENT; typedef VOID (NTAPI *PKNORMAL_ROUTINE)( PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2 ); typedef VOID KKERNEL_ROUTINE( PRKAPC Apc, PKNORMAL_ROUTINE *NormalRoutine, PVOID *NormalContext, PVOID *SystemArgument1, PVOID *SystemArgument2 ); typedef KKERNEL_ROUTINE (NTAPI *PKKERNEL_ROUTINE); typedef VOID (NTAPI *PKRUNDOWN_ROUTINE)( PRKAPC Apc ); void KeInitializeApc( PRKAPC Apc, PRKTHREAD Thread, KAPC_ENVIRONMENT Environment, PKKERNEL_ROUTINE KernelRoutine, PKRUNDOWN_ROUTINE RundownRoutine, PKNORMAL_ROUTINE NormalRoutine, KPROCESSOR_MODE ProcessorMode, PVOID NormalContext ); BOOLEAN KeInsertQueueApc( PRKAPC Apc, PVOID SystemArgument1, PVOID SystemArgument2, KPRIORITY Increment ); NTSTATUS ZwQuerySystemInformation(ULONG InfoClass,PVOID Buffer,ULONG Length,PULONG ReturnLength); LPSTR PsGetProcessImageFileName(PEPROCESS Process); NTSTATUS DefaultPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp); void UnloadDriver(PDRIVER_OBJECT DriverObject); NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject,PIRP Irp); ULONG ApcStateOffset; PLDR_LOAD_DLL LdrLoadDll; NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING pRegistryPath) { NTSTATUS Status; PDEVICE_OBJECT DeviceObject; PEPROCESS Process; PETHREAD Thread; PKAPC_STATE ApcState; PVOID KdVersionBlock,NtdllBase; PULONG ptr,Functions,Names; PUSHORT Ordinals; PLDR_DATA_TABLE_ENTRY MmLoadedUserImageList,ModuleEntry; ULONG i; PIMAGE_DOS_HEADER pIDH; PIMAGE_NT_HEADERS pINH; PIMAGE_EXPORT_DIRECTORY pIED; UNICODE_STRING uniDeviceName; UNICODE_STRING uniLinkName; RtlInitUnicodeString(&uniDeviceName,DEVICE_NAME); RtlInitUnicodeString(&uniLinkName,LINK_NAME); for (i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++) { DriverObject->MajorFunction[i] = DefaultPassThrough; } DriverObject->DriverUnload = UnloadDriver; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatch; //创建设备对象 Status = IoCreateDevice(DriverObject,0,&uniDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,&DeviceObject); if (!NT_SUCCESS(Status)) { return Status; } Status = IoCreateSymbolicLink(&uniLinkName,&uniDeviceName); if (!NT_SUCCESS(Status)) { IoDeleteDevice(DeviceObject); return Status; } //使当前线程运行在第一个处理器上 KeSetSystemAffinityThread(1); KdVersionBlock=(PVOID)__readfsdword(0x34); //得到KdVersionBlock KeRevertToUserAffinityThread();//恢复线程运行的处理器 MmLoadedUserImageList=*(PLDR_DATA_TABLE_ENTRY*)((PUCHAR)KdVersionBlock+0x228); // Get the MmLoadUserImageList /* kd> !pcr KPCR for Processor 0 at 83f3ec00: kd> dt _kpcr 83f3ec00 +0x034 KdVersionBlock : 0x83f3dc00 Void kd> dd 0x83f3dc00+0x228 83f3de28 83f5de38 00000000 83e5dfa8 00000000 83f3de38 00000000 00000000 83f7d8c0 00000000 83f3de48 83f7d560 00000000 83f5d84c 00000000 kd> dd 83f5de38 83f5de38 8706b1e8 877cb660 00000000 00000000 83f5de48 00000000 00000000 00040107 00000000 83f5de58 865d0690 865d0690 c0403188 0007ff7e kd> dt _LDR_DATA_TABLE_ENTRY 8706b1e8 nt!_LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x8713b4e0 - 0x83f5de38 ] +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ] +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ] +0x018 DllBase : 0x77ce0000 Void +0x01c EntryPoint : (null) +0x020 SizeOfImage : 0x13c000 +0x024 FullDllName : _UNICODE_STRING "WindowsSystem32ntdll.dll" +0x02c BaseDllName : _UNICODE_STRING "" +0x034 Flags : 0 +0x038 LoadCount : 1 +0x03a TlsIndex : 0 +0x03c HashLinks : _LIST_ENTRY [ 0x0 - 0x1490d9 ] +0x03c SectionPointer : (null) +0x040 CheckSum : 0x1490d9 +0x044 TimeDateStamp : 0 +0x044 LoadedImports : (null) +0x048 EntryPointActivationContext : (null) +0x04c PatchInformation : (null) +0x050 ForwarderLinks : _LIST_ENTRY [ 0x0 - 0x0 ] +0x058 ServiceTagLinks : _LIST_ENTRY [ 0x0 - 0x57005c ] +0x060 StaticLinks : _LIST_ENTRY [ 0x6e0069 - 0x6f0064 ] +0x068 ContextInformation : 0x00730077 Void +0x06c OriginalBase : 0x53005c +0x070 LoadTime : _LARGE_INTEGER 0x650074`00730079 */ DbgPrint("KdVersionBlock address: %#x",KdVersionBlock); DbgPrint("MmLoadedUserImageList address: %#x",MmLoadedUserImageList); ModuleEntry=(PLDR_DATA_TABLE_ENTRY)MmLoadedUserImageList->InLoadOrderLinks.Flink; //第一模块 NtdllBase=ModuleEntry->DllBase; //ntdll基地址 DbgPrint("ntdll base address: %#x",NtdllBase); pIDH=(PIMAGE_DOS_HEADER)NtdllBase; pINH=(PIMAGE_NT_HEADERS)((PUCHAR)NtdllBase+pIDH->e_lfanew); pIED=(PIMAGE_EXPORT_DIRECTORY)((PUCHAR)NtdllBase+pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); Functions=(PULONG)((PUCHAR)NtdllBase+pIED->AddressOfFunctions); Names=(PULONG)((PUCHAR)NtdllBase+pIED->AddressOfNames); Ordinals=(PUSHORT)((PUCHAR)NtdllBase+pIED->AddressOfNameOrdinals); //搜索LdrLoadDll for(i=0;i<pIED->NumberOfNames;i++) { if(!strcmp((char*)NtdllBase+Names[i],"LdrLoadDll")) { LdrLoadDll=(PLDR_LOAD_DLL)((PUCHAR)NtdllBase+Functions[Ordinals[i]]); break; } } DbgPrint("LdrLoadDll address: %#x",LdrLoadDll); Process=PsGetCurrentProcess(); Thread=PsGetCurrentThread(); ptr=(PULONG)Thread; //确定ApcState在EThread中的偏移 for(i=0;i<512;i++) { if(ptr[i]==(ULONG)Process) { ApcState=CONTAINING_RECORD(&ptr[i],KAPC_STATE,Process); ApcStateOffset=(ULONG)ApcState-(ULONG)Thread; break; } } DbgPrint("ApcState offset: %#x",ApcStateOffset); DbgPrint("DLL injection driver loaded."); return STATUS_SUCCESS; } NTSTATUS DefaultPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp) { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp,IO_NO_INCREMENT); return STATUS_SUCCESS; } void UnloadDriver(PDRIVER_OBJECT DriverObject) { UNICODE_STRING uniLinkName; PDEVICE_OBJECT CurrentDeviceObject; PDEVICE_OBJECT NextDeviceObject; RtlInitUnicodeString(&uniLinkName,LINK_NAME); IoDeleteSymbolicLink(&uniLinkName); if (DriverObject->DeviceObject!=NULL) { CurrentDeviceObject = DriverObject->DeviceObject; while(CurrentDeviceObject!=NULL) { NextDeviceObject = CurrentDeviceObject->NextDevice; IoDeleteDevice(CurrentDeviceObject); CurrentDeviceObject = NextDeviceObject; } } DbgPrint("UnloadDriverrn"); } void NTAPI InjectDllApc(PVOID NormalContext,PVOID SystemArgument1,PVOID SystemArgument2) { PKINJECT inject=(PKINJECT)NormalContext; inject->LdrLoadDll(NULL,NULL,&inject->DllName,&inject->DllBase); inject->Executed=TRUE; } void NTAPI KernelRoutine(PKAPC apc,PKNORMAL_ROUTINE* NormalRoutine,PVOID* NormalContext, PVOID* SystemArgument1,PVOID* SystemArgument2) { ExFreePool(apc); } BOOLEAN InjectDll(PINJECT_INFO InjectInfo) { PEPROCESS Process; PETHREAD Thread; PKINJECT mem; ULONG size; PKAPC_STATE ApcState; PKAPC apc; PVOID buffer; PSYSTEM_PROCESS_INFO pSpi; LARGE_INTEGER delay; buffer=ExAllocatePool(NonPagedPool,1024*1024); if(!buffer) { DbgPrint("Error: Unable to allocate memory for the process thread list."); return FALSE; } //5 SystemProcessInformation, if(!NT_SUCCESS(ZwQuerySystemInformation(5,buffer,1024*1024,NULL))) { DbgPrint("Error: Unable to query process thread list."); ExFreePool(buffer); return FALSE; } pSpi=(PSYSTEM_PROCESS_INFO)buffer; //找到目标进程 while(pSpi->NextEntryOffset) { if(pSpi->UniqueProcessId==InjectInfo->ProcessId) { DbgPrint("Target thread found. TID: %d",pSpi->Threads[0].ClientId.UniqueThread); break; } pSpi=(PSYSTEM_PROCESS_INFO)((PUCHAR)pSpi+pSpi->NextEntryOffset); } // 引用目标进程EProcess, if(!NT_SUCCESS(PsLookupProcessByProcessId(InjectInfo->ProcessId,&Process))) { DbgPrint("Error: Unable to reference the target process."); ExFreePool(buffer); return FALSE; } DbgPrint("Process name: %s",PsGetProcessImageFileName(Process)); DbgPrint("EPROCESS address: %#x",Process); //目标进程主线程 if(!NT_SUCCESS(PsLookupThreadByThreadId(pSpi->Threads[0].ClientId.UniqueThread,&Thread))) { DbgPrint("Error: Unable to reference the target thread."); ObDereferenceObject(Process); ExFreePool(buffer); return FALSE; } DbgPrint("ETHREAD address: %#x",Thread); ExFreePool(buffer); //切入到目标进程 KeAttachProcess(Process); mem=NULL; size=4096; //在目标进程申请内存 if(!NT_SUCCESS(ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,0,&size,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE))) { DbgPrint("Error: Unable to allocate memory in the target process."); KeDetachProcess(); ObDereferenceObject(Process); ObDereferenceObject(Thread); return FALSE; } DbgPrint("Memory allocated at %#x",mem); mem->LdrLoadDll=LdrLoadDll; wcscpy(mem->Buffer,InjectInfo->DllName); RtlInitUnicodeString(&mem->DllName,mem->Buffer); ApcState=(PKAPC_STATE)((PUCHAR)Thread+ApcStateOffset); ApcState->UserApcPending=TRUE; memcpy((PKINJECT)(mem+1),InjectDllApc,(ULONG)KernelRoutine-(ULONG)InjectDllApc); DbgPrint("APC code address: %#x",(PKINJECT)(mem+1)); //申请apc对象 apc=(PKAPC)ExAllocatePool(NonPagedPool,sizeof(KAPC)); if(!apc) { DbgPrint("Error: Unable to allocate the APC object."); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); KeDetachProcess(); ObDereferenceObject(Process); ObDereferenceObject(Thread); return FALSE; } KeInitializeApc(apc, Thread, //目标进程主线程 OriginalApcEnvironment, //目标apcz状态 KernelRoutine, //内核apc总入口 NULL, //Rundown Rounine=NULL (PKNORMAL_ROUTINE)((PKINJECT)mem+1), //用户空间的总apc UserMode, //插入到用户apc队列 mem); // 自己的apc队列 DbgPrint("Inserting APC to target thread"); // 插入apc队列 if(!KeInsertQueueApc(apc,NULL,NULL,IO_NO_INCREMENT)) { DbgPrint("Error: Unable to insert APC to target thread."); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); KeDetachProcess(); ObDereferenceObject(Process); ObDereferenceObject(Thread); ExFreePool(apc); return FALSE; } delay.QuadPart=-100*10000; while(!mem->Executed) { KeDelayExecutionThread(KernelMode,FALSE,&delay); //等待apc执行 } if(!mem->DllBase) { DbgPrint("Error: Unable to inject DLL into target process."); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); KeDetachProcess(); ObDereferenceObject(Process); ObDereferenceObject(Thread); return FALSE; } DbgPrint("DLL injected at %#x",mem->DllBase); size=0; ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); ObDereferenceObject(Process); ObDereferenceObject(Thread); return TRUE; } NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject,PIRP Irp) { PIO_STACK_LOCATION io; PINJECT_INFO InjectInfo; NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp; PVOID InputBuffer = NULL; PVOID OutputBuffer = NULL; ULONG_PTR InputSize = 0; ULONG_PTR OutputSize = 0; ULONG_PTR IoControlCode = 0; IrpSp = IoGetCurrentIrpStackLocation(Irp); InputBuffer = OutputBuffer = Irp->AssociatedIrp.SystemBuffer; InputSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength; OutputSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; switch(IoControlCode) { case CTL_KEINJECTAPC: InjectInfo=(PINJECT_INFO)InputBuffer; if(!InjectInfo) { Status=STATUS_INSUFFICIENT_RESOURCES; break; } if(!InjectDll(InjectInfo)) { Status=STATUS_UNSUCCESSFUL; break; } Status=STATUS_SUCCESS; Irp->IoStatus.Information=0; break; default: Status=STATUS_INVALID_DEVICE_REQUEST; break; } Irp->IoStatus.Status=Status; IoCompleteRequest(Irp,IO_NO_INCREMENT); return Status; }
转载于:https://www.cnblogs.com/lanrenxinxin/p/4662364.html
最后
以上就是闪闪魔镜最近收集整理的关于注入小结的全部内容,更多相关注入小结内容请搜索靠谱客的其他文章。
发表评论 取消回复