最近在学HookSSDT和针对Hook的ResumeSSDT,避免自己理解有所偏差,把它们写出来,希望大家不吝赐教。(虽然已经是过时了的技术,但是最起码了解其中的原理,嘿嘿嘿。)
转载注明出处:http://www.cnblogs.com/littlepear/p/6664637.html
一 HookSSDT:
我们以Hook NtOpenProcess函数为例。首先是寻找SSDT表,32位下已经导出KeServiceDescriptorTable,而64位下没有导出,所以我们先暴力寻找SSDT的地址。
先讨论64位:
1.寻找SSDT表
我们通过读取MSR的0xC0000082处的地址,,里面保存的是64位的syscall,当我们u一下这个地址,发现这个就是x64系统调用的入口KiSystemCall64,我们把它作为搜索起始地址。
然后向下搜寻,以它的lea指令作为特征码,如图
0x00238c47是它的偏移,KeServiceDescriptorTable的地址 = 0xfffff800`03e91cf2+0x00238c47+7 = 0xfffff800`040ca940。
我们把SSDT保存在此结构体中。
typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_
{
PVOID ServiceTableBase; //SSDT(System Service Dispatch Table)服务表的基地址
PVOID ServiceCounterTableBase; //用于checked builds,包含SSDT中每个服务被调用的次数
PVOID NumberOfServices; //服务函数的个数,NumberOfService * 4就是整个地址表的大小 64位 0x191, 32位 0x11c
PVOID ParamTableBase; //SSPT(System Service Parameter Table)的基地址
}SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE;
2.寻找NtOpenProcess在SSDT表中的系统调用号。
NtOpenProcess和ZwOpenProcess在Ntoskrnl.exe和ntdll.dll中都有导出,那么它们之间有什么区别呢?
先来看ntdll下的两个
发现NtOpenProcess就是ZwOpenProcess的一个别名,我们记他们为ntdll!ZwProcess,它们只把调用号mov到eax中,然后syscall.
看Ntoskrnl下的两个,
又发现内核空间中的ZwOpenProcess只是NtOpenProcess的一个跳板,它只是把系统调用号(rsp)Mov到eax中,然后调用nt!KiSystemServiceLinkage,真正的实现是通过NtOpenProcess,调用nt!PsOpenProcess
所以大体流程是: Kernel32.dll(API)--->ntdll.dll(Nt/Zw)--->用户模式转内核模式--->Ntoskrnl.exe(Nt)--->完成I/O请求(原路返回)
此处参考博客:http://www.cnblogs.com/uAreKongqi/p/6597701.html
然后64位调用号被rsp代替,所以我们只能从ntdll中查找ntdll!ZwOpenProcess,方法就是从ntdll导出表中查找到处函数,然后寻找调用号23h(函数地址+4),我们把它记为__NtOpenProcessIndex
3.保留原NtOpenProcess的偏移和地址。
我们记__OldNtOpenProcessOffset = __ServiceTableBase[__NtOpenProcessIndex]表示64位下NtOpenProcess的偏移,__ServiceTableBase为SSDT的第一个参数,此偏移是相对于 __ServiceTableBase的,
64位下,比如0x02e80205,最后一个数字为(函数参数-4),这里涉及到64位函数的调用约定和压参,不予讨论。我们需要__OldNtOpenProcessOffset >> 4+__ServiceTableBase获得函数的地址。
4.Hook NtOpenProcess函数。
原理就是:将SSDT表中NtOpenProcess的偏移替换成自己的函数的偏移,但是这里就出现问题了,64位下,函数的地址是16位,到__ServiceTableBase的偏移已经远远超过8位,不能放在表里,那怎么办呢? 我们选择InlineHook,就是把一个不经常用的函数,这里选择KeBugCheckEx(这就是64位下这种方法过时的原因,谁知道KeBugCheckEx这个函数不用呢),替换掉NtOpenProcess的偏移,然后我们在KeBugCheckEx函数中实现跳跃到自己的函数中,这就解决问题啦。
以上是64位的,32位需要注意,
第一点:Ntoskrnl.exe中导出了KeServiceDescriptorTable,不需要暴力找。
第二点:__NtOpenProcessIndex这次可以从Ntoskrnl.exe中找了,32位比较好,没用其他东西替代。
第三就是就是__ServiceTableBase[__NtOpenProcessIndex]中储存的是地址,而不是偏移,也不需要找像KeBugCheckEx的跳板函数,直接就可以放我函数的地址,比较方便。
细节看代码:
1 #include <ntifs.h> 2 3 #define SEC_IMAGE 0x001000000 4 5 6 extern 7 PIMAGE_NT_HEADERS 8 NTAPI 9 RtlImageNtHeader(PVOID BaseAddress); 10 11 extern 12 char* PsGetProcessImageFileName(PEPROCESS EProcess); 13 14 typedef 15 NTSTATUS(*pfnNtOpenProcess)( 16 _Out_ PHANDLE ProcessHandle, 17 _In_ ACCESS_MASK DesiredAccess, 18 _In_ POBJECT_ATTRIBUTES ObjectAttributes, 19 _In_opt_ PCLIENT_ID ClientId 20 ); 21 22 typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_ 23 { 24 PVOID ServiceTableBase; //SSDT(System Service Dispatch Table)服务表的基地址 25 PVOID ServiceCounterTableBase; //用于checked builds,包含SSDT中每个服务被调用的次数 26 PVOID NumberOfServices; //服务函数的个数,NumberOfService * 4就是整个地址表的大小 64位 0x191, 32位 0x11c 27 PVOID ParamTableBase; //SSPT(System Service Parameter Table)的基地址 28 }SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE; 29 30 BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress); 31 BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress); 32 VOID DriverUnload(PDRIVER_OBJECT DriverObject); 33 BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG32* SSDTFunctionIndex); 34 PVOID 35 GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName); 36 BOOLEAN Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize); 37 ULONG32 CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParamterCount); 38 VOID HookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID MyFunctionAddress, 39 PVOID OldFuntionAddress, ULONG32 OldFunctionParamterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength); 40 VOID HookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 MyFunctionAddress); 41 VOID InlineHook(ULONG64 OldFuntionAddress, ULONG64 MyFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength); 42 NTSTATUS MyOpenProcess( 43 _Out_ PHANDLE ProcessHandle, 44 _In_ ACCESS_MASK DesiredAccess, 45 _In_ POBJECT_ATTRIBUTES ObjectAttributes, 46 _In_opt_ PCLIENT_ID ClientId 47 ); 48 VOID WPOFF(); 49 VOID WPON(); 50 51 VOID UnHookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress, 52 UCHAR* OldFunctionCode, ULONG32 PatchCodeLength); 53 VOID UnHookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionAddress); 54 VOID UnlineHook(PVOID OldFunctionAddress, CHAR* OldFunctionCode, ULONG32 PatchCodeLength);
1 #include "HookSSDT.h" 2 #include <ntimage.h> 3 #include <Ntstrsafe.h> 4 5 ULONG32 __NtOpenProcessIndex = 0; 6 PVOID __ServiceTableBase = NULL; 7 ULONG32 __OldNtOpenProcessOffset = 0; 8 pfnNtOpenProcess __OldNtOpenProcessAddress = NULL; //这里无所谓,PVOID也可以 9 BOOLEAN __IsHook = FALSE; 10 UCHAR __OldCode[15] = { 0 }; 11 12 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath) 13 { 14 NTSTATUS Status = STATUS_UNSUCCESSFUL; 15 char szFunctionName[] = "ZwOpenProcess"; 16 ULONG_PTR SSDTAddress = 0; //保存整个SSDT基地址 KeServiceDescriptorTable 17 ULONG32 TempOffset = 0; 18 DriverObject->DriverUnload = DriverUnload; 19 20 #ifdef _WIN64 21 if (GetSSDTAddressInWin7_x64(&SSDTAddress) == FALSE) 22 { 23 return Status; 24 } 25 #else 26 if (GetSSDTAddressInWin7_x86(&SSDTAddress) == FALSE) 27 { 28 return Status; 29 } 30 #endif 31 32 DbgPrint("SSDT:%p ", SSDTAddress); //0x23h 33 if (GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(szFunctionName, &__NtOpenProcessIndex) == FALSE) 34 { 35 return Status; 36 } 37 38 __ServiceTableBase = ((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase; 39 #ifdef _WIN64 40 __OldNtOpenProcessOffset = ((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex]; 41 TempOffset = __OldNtOpenProcessOffset >> 4; //抹掉最右边的一位 42 __OldNtOpenProcessAddress = (PVOID)((ULONG64)__ServiceTableBase + TempOffset); 43 HookSSDTInWin7_x64(__ServiceTableBase, __NtOpenProcessIndex, MyOpenProcess, KeBugCheckEx, 5, __OldCode, 15); 44 #else 45 __OldNtOpenProcessAddress = (pfnNtOpenProcess)(((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex]); 46 /*kd > u 0x84016ba1 47 nt!NtOpenProcess: 48 84016ba1 8bff mov edi, edi 49 84016ba3 55 push ebp 50 84016ba4 8bec mov ebp, esp 51 84016ba6 51 push ecx 52 84016ba7 51 push ecx 53 84016ba8 64a124010000 mov eax, dword ptr fs : [00000124h] 54 84016bae 8a803a010000 mov al, byte ptr[eax + 13Ah] 55 84016bb4 8b4d14 mov ecx, dword ptr[ebp + 14h]*/ 56 57 //0x00145dc8 58 59 HookSSDTInWin7_x86(__ServiceTableBase, __NtOpenProcessIndex, (ULONG32)MyOpenProcess);//强制转换后,MyOpenProcess才可以传,真奇怪 60 #endif 61 return STATUS_SUCCESS; 62 } 63 64 VOID DriverUnload(PDRIVER_OBJECT DriverObject) 65 { 66 DbgPrint("ByeBye,Driver! "); 67 68 if (__IsHook) 69 { 70 #ifdef _WIN64 71 72 UnHookSSDTInWin7_x64(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessOffset, KeBugCheckEx, 73 __OldCode, 15); 74 #else 75 UnHookSSDTInWin7_x86(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessAddress); 76 #endif 77 78 __IsHook = FALSE; 79 } 80 } 81 82 BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress) 83 { 84 //rdmsr c0000082 85 CHAR* StartSearchAddress = (char*)__readmsr(0xc0000082); 86 CHAR* EndSearchAddress = StartSearchAddress + PAGE_SIZE; //4KB 87 CHAR* i = NULL; 88 UCHAR v1 = 0, v2 = 0, v3 = 0; 89 //必须用UCHAR类型,因为Char的范围是 -128~127 0x80-0x7F 90 INT64 Offset = 0; 91 *SSDTAddress = NULL; 92 for (i = StartSearchAddress; i < EndSearchAddress; i++) 93 { 94 if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2)) 95 { 96 v1 = *i; 97 v2 = *(i + 1); 98 v3 = *(i + 2); 99 if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15) 100 { 101 // 4c8d15238f4700 102 memcpy(&Offset, i+3, 4); 103 *SSDTAddress = Offset + (ULONG64)i+7; 104 break; 105 } 106 } 107 } 108 if (*SSDTAddress == NULL) 109 { 110 return FALSE; 111 } 112 return TRUE; 113 } 114 115 BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress) 116 { 117 //32位下Ntoskrnl.exe有导出 KeServiceDescriptorTable,直接查找即可 118 *SSDTAddress = NULL; 119 *SSDTAddress = (ULONG32)GetExportVariableAddressFromNtosKrnlExportTableByVariableName(L"KeServiceDescriptorTable"); 120 if (*SSDTAddress != NULL) 121 { 122 return TRUE; 123 } 124 return FALSE; 125 } 126 127 PVOID 128 GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName) 129 { 130 //通过导出变量名字从NtosKrnl中获得导出变量地址 131 UNICODE_STRING uniVariableName; 132 PVOID VariableAddress = NULL; 133 134 if (wzVariableName&&wcslen(wzVariableName) > 0) 135 { 136 RtlUnicodeStringInit(&uniVariableName, wzVariableName); 137 //从Ntos模块的导出表中获得导出变量的地址 138 VariableAddress = MmGetSystemRoutineAddress(&uniVariableName); 139 } 140 return VariableAddress; 141 } 142 143 BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG32* SSDTFunctionIndex) 144 { 145 WCHAR szFileFullPath[] = L"\SystemRoot\System32\ntdll.dll"; //C:Windows 146 ULONG_PTR MappingViewSize = 0; 147 PVOID MappingBaseAddress = 0; 148 BOOLEAN IsOk = FALSE; 149 PIMAGE_NT_HEADERS Image_Nt_Headers = NULL; 150 PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL; //导出表 151 //因为不识别DWORD,所以用UINT32 152 UINT32* AddressOfFunctions = NULL; 153 UINT32* AddressOfNames = NULL; 154 UINT16* AddressOfNameOrdinals = NULL; 155 int i = 0; 156 char* v1 = NULL; 157 ULONG32 OrdinalOfFunction = 0; 158 PVOID AddressOfFunction = 0; 159 #ifdef _WIN64 160 /* 161 0:004> u zwopenprocess 162 ntdll!NtOpenProcess: 163 00000000`774ddc10 4c8bd1 mov r10,rcx 164 00000000`774ddc13 b823000000 mov eax,23h 165 00000000`774ddc18 0f05 syscall 166 00000000`774ddc1a c3 ret 167 00000000`774ddc1b 0f1f440000 nop dword ptr [rax+rax] 168 */ 169 ULONG32 Offset_SSDTFunctionIndex = 4; 170 #else 171 /* 172 0:004> u zwopenprocess 173 ntdll!NtOpenProcess: 174 00000000`774ddc10 4c8bd1 mov r10,rcx 175 00000000`774ddc13 b823000000 mov eax,23h 176 00000000`774ddc18 0f05 syscall 177 00000000`774ddc1a c3 ret 178 00000000`774ddc1b 0f1f440000 nop dword ptr [rax+rax] 179 */ 180 ULONG32 Offset_SSDTFunctionIndex = 1; 181 #endif 182 183 184 *SSDTFunctionIndex = -1; 185 IsOk = Ring0MappingPEFile(szFileFullPath, &MappingBaseAddress, &MappingViewSize); 186 if (IsOk == FALSE) 187 { 188 return FALSE; 189 } 190 else 191 { 192 __try { 193 Image_Nt_Headers = RtlImageNtHeader(MappingBaseAddress); //extern进来 194 if (Image_Nt_Headers&&Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) 195 { 196 ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((char*)MappingBaseAddress 197 + Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 198 199 AddressOfFunctions = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions); 200 //函数的地址(RVA) 201 AddressOfNames = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);; 202 //函数名字的地址(RVA) 203 AddressOfNameOrdinals = (UINT16*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals); 204 //有名字的序号的首地址(RVA) 205 for (i = 0; i < ImageExportDirectory->NumberOfNames; i++) 206 { 207 v1 = (char*)((char*)MappingBaseAddress + AddressOfNames[i]); //可以这样写 ImageExportDirectory->AddressOfNames + i * 4 208 if (_stricmp(szFuntionName, v1) == 0) 209 { 210 OrdinalOfFunction = AddressOfNameOrdinals[i]; 211 AddressOfFunction = (PVOID)((char*)MappingBaseAddress + AddressOfFunctions[OrdinalOfFunction]);//AddressOfFunctions[AddressOfNameOrdinals[i]] 212 *SSDTFunctionIndex = *(ULONG32*)((char*)AddressOfFunction + Offset_SSDTFunctionIndex); 213 break; 214 } 215 } 216 } 217 } 218 __except(EXCEPTION_EXECUTE_HANDLER) 219 {} 220 221 } 222 ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress); 223 if (*SSDTFunctionIndex == -1) 224 { 225 return FALSE; 226 } 227 return TRUE; 228 } 229 //函数需要,所以传双字 二维指针 230 BOOLEAN Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize) 231 { 232 NTSTATUS Status; 233 UNICODE_STRING Temp; 234 OBJECT_ATTRIBUTES oa; 235 HANDLE hFile = NULL; 236 HANDLE hSection = NULL; 237 IO_STATUS_BLOCK IoStatusBlock; 238 239 if (!szFileFullPath&&MmIsAddressValid(szFileFullPath)) 240 { 241 return FALSE; 242 } 243 if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress)) 244 { 245 return FALSE; 246 } 247 RtlUnicodeStringInit(&Temp, szFileFullPath); 248 InitializeObjectAttributes(&oa, //out 249 &Temp, //in ObjectName 250 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,//被系统在和ObjectName比较匹配时不区分大小写||此句柄只能用于内核模式下 251 NULL, //与ObjectName参数匹配的根目录对象,如果ObjectName是对象的全路径则设置此参数为NULL 252 NULL //驱动程序可以使用NULL用于创建一个具有默认安全描述符的对象 253 ); 254 //打开文件,获得文件句柄 255 Status = IoCreateFile(&hFile, 256 GENERIC_READ | SYNCHRONIZE, //可读|同步 257 &oa, 258 &IoStatusBlock, //返回I/O请求的完成情况 259 NULL, 260 FILE_ATTRIBUTE_NORMAL, 261 FILE_SHARE_READ, 262 FILE_OPEN, 263 FILE_SYNCHRONOUS_IO_NONALERT, 264 NULL, 265 0, 266 CreateFileTypeNone, 267 NULL, 268 IO_NO_PARAMETER_CHECKING 269 ); 270 if (!NT_SUCCESS(Status)) 271 { 272 return FALSE; 273 } 274 oa.ObjectName = NULL; 275 Status = ZwCreateSection(&hSection, 276 SECTION_QUERY | SECTION_MAP_READ, 277 &oa, 278 NULL, 279 PAGE_WRITECOPY, 280 SEC_IMAGE,//内存按1M对齐 0x1000 000 281 hFile 282 ); 283 ZwClose(hFile); 284 if (!NT_SUCCESS(Status)) 285 { 286 return FALSE; 287 } 288 Status = ZwMapViewOfSection(hSection, 289 NtCurrentProcess(), 290 MappingBaseAddress, 291 0, 292 0, 293 0, 294 MappingViewSize, 295 ViewUnmap, //不能被映射到子进程中 296 0, 297 PAGE_WRITECOPY 298 ); 299 ZwClose(hSection); 300 if (!NT_SUCCESS(Status)) 301 { 302 return FALSE; 303 } 304 return TRUE; 305 } 306 307 ULONG32 CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParamterCount) 308 { 309 //完全没必要像下面这样折腾,就是一个做个SSDT表中类似的地址,有时间自己写一个 310 ULONG32 Offset = 0; 311 CHAR Temp = 0; 312 CHAR Bits[4] = { 0 }; 313 int i = 0; 314 Offset = (ULONG32)((ULONG64)FunctionAddress - (ULONG64)ServiceTableBase); 315 Offset = Offset << 4; 316 if (ParamterCount > 4) 317 { 318 ParamterCount = ParamterCount-4; //NtReadFile 9个参数 和参数压栈有关 319 } 320 else 321 { 322 ParamterCount = 0; 323 } 324 memcpy(&Temp, &Offset, 1); // 1010 0010 <<4-----> 0010 0000 后面处理参数 325 #define SETBIT(x,y) x|=(1<<y) //将X的第Y位置1 326 #define CLRBIT(x,y) x&=~(1<<y) //将X的第Y位清0 327 #define GETBIT(x,y) (x & (1 << y)) //取X的第Y位,返回0或非0 328 329 for (i = 0; i < 4; i++) 330 { 331 Bits[i] = GETBIT(ParamterCount, i); 332 if (Bits[i]) 333 { 334 SETBIT(Temp, i); 335 } 336 else 337 { 338 CLRBIT(Temp, i); 339 } 340 } 341 memcpy(&Offset, &Temp, 1); 342 return Offset; 343 } 344 345 //write protect 第17位 346 VOID WPOFF() 347 { 348 _disable(); 349 __writecr0(__readcr0() & (~(0x10000))); 350 351 } 352 353 VOID WPON() 354 { 355 __writecr0(__readcr0() ^ 0x10000); 356 _enable(); 357 } 358 359 VOID HookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID MyFunctionAddress, 360 PVOID OldFuntionAddress, ULONG32 OldFunctionParamterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength) 361 { 362 ULONG32 MyOffset = 0; 363 WPOFF(); 364 InlineHook(OldFuntionAddress, MyFunctionAddress, OldFunctionCode, PatchCodeLength); 365 WPON(); 366 367 MyOffset = CalcFunctionOffsetInSSDT(ServiceTableBase, OldFuntionAddress, OldFunctionParamterCount); 368 WPOFF(); 369 ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = MyOffset; 370 WPON(); 371 372 __IsHook = TRUE; 373 } 374 375 VOID HookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 MyFunctionAddress) 376 { 377 WPOFF(); 378 ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)MyFunctionAddress; 379 WPON(); 380 381 __IsHook = TRUE; 382 } 383 384 VOID InlineHook(ULONG64 OldFuntionAddress, ULONG64 MyFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength) 385 { 386 CHAR PatchCode[] = "xFFx25x00x00x00x00xFFxFFxFFxFFxFFxFFxFFxFF"; //神坑啊,脑残啊,写成PatchCode 到memcpy才崩溃 387 ULONG64 Temp = MyFunctionAddress; 388 memcpy(OldFunctionCode, (PVOID)OldFuntionAddress, PatchCodeLength); //保存原来的函数指令 389 memcpy(PatchCode + 6, &Temp, 8); 390 DbgPrint("%s ", PatchCode); 391 memset((PVOID)OldFuntionAddress, 0x90, PatchCodeLength); //先全部打上NOP(计组) 392 memcpy((PVOID)OldFuntionAddress, PatchCode, 14); 393 } 394 395 396 //SSDT HOOK的替换函数如何对访问进行过滤”比“如何实现SSDT HOOK”要复杂多了,详见ediary HookNtOpenProcess后的事情 397 NTSTATUS MyOpenProcess( 398 _Out_ PHANDLE ProcessHandle, 399 _In_ ACCESS_MASK DesiredAccess, 400 _In_ POBJECT_ATTRIBUTES ObjectAttributes, 401 _In_opt_ PCLIENT_ID ClientId 402 ) 403 { 404 //EnumProcessByForce.exe 405 //调用OpenProcess---->去NtDll导出表中寻找ntdll!NtOpenProcess或者ntdll!ZwOpenProcess 导出表有名称的索引---->切入内核-->跳板nt!ZwOpenProcess Ntoskernl.exe(NtOpenProcess mov eax,23h SSDT[23h]) 406 // ---->KeCheckBugEx ---->Jmp MyOpenProcess 407 PEPROCESS EProcess = PsGetCurrentProcess(); //EnumProcessByForce.exe 408 if (EProcess != NULL && MmIsAddressValid(EProcess)) 409 { 410 char *szProcessImageFileName = PsGetProcessImageFileName(EProcess); 411 if (strstr(szProcessImageFileName, "EnumProcess") != 0) 412 { 413 return STATUS_ACCESS_DENIED; //黑名单中返回 414 } 415 } 416 __OldNtOpenProcessAddress(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); //白名单 417 //OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, i) 418 //return STATUS_SUCCESS; 死循环 419 //return STATUS_UNSUCCESSFUL; 阻塞 很有趣 420 } 421 422 VOID UnHookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress, 423 UCHAR* OldFunctionCode, ULONG32 PatchCodeLength) 424 { 425 WPOFF(); 426 UnlineHook(OldFunctionAddress, OldFunctionCode, PatchCodeLength); 427 WPON(); 428 429 WPOFF(); 430 ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionOffset; 431 WPON(); 432 } 433 434 VOID UnlineHook(PVOID OldFunctionAddress, CHAR* OldFunctionCode, ULONG32 PatchCodeLength) 435 { 436 memcpy((PVOID)OldFunctionAddress, OldFunctionCode, PatchCodeLength); 437 } 438 439 VOID UnHookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionAddress) 440 { 441 WPOFF(); 442 ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionAddress; 443 WPON(); 444 }
ResumeSSDT:
原理:因为我们Hook的是模块中的NtOpenProcess, 所以我们可以寻找Ntoskrnl.exe文件中NtOpenProcess的地址,再替换掉已经被替换掉的。
先谈64位:
1.找SSDT表和调用号和Hook的过程一样。
2.关键是找NtOpenProcess的真正地址。
有两种方法:
1.因为NtOpenProcess已经在Ntoskrnl.exe中导出了,所以我们直接从导出表中找到它的函数地址,只不过这个地址是文件中的,需要转换成在内存中的,那怎么转换呢?
我们首先要了解这个文件中的函数地址是怎么回事,《WindowsPE权威指南》上92页上有讲,IMAGE_OPTIONAL_HEADER32.ImageBase的地址是映像基地址的优先装入地址,exe文件被装入到起始地址为0x400000h的虚拟内存地址处。
再看《WindowsPE权威指南》80页上,链接器在产生可执行文件的时候,都是对应ImageBase(32位下是0x400000, 64位下是0x00000001`40000000)来生成机器码的,好比其中的一个函数NtOpenProcess,直接查看ntoskrnl.exe导出表中它的地址,也就是它在产生可执行文件的时候,所有东西都是对照这个地址生成机器码的,并且这个地址是它假想映射到内存的地址,即按0x1000对齐过的地址。
PS: 用PECheck小工具查看NtOpenProcess,注意偏移值和上述假想地址-ImageBase相等
但是对于EXE来说,每个文件使用的都是独立的虚拟地址空间,所以,优先装入的地址通常不会被其他模块占据,也就是说,如果再来新的模块,前面那个值被占领了,操作系统会做出调整,找到合适的地址,这个地址就是真正的内存中的模块基地址。
那好了,我们可以来计算真正的内存中的地址。我们先计算文件中函数的偏移,即 0x00000001`403473d0-0x00000001`40000000, 再加上真正的模块基地址ModuleBase,不就得到了真正的函数地址了?
然后再和现在内存中SSDT 0x23h的位置比较,看看是否被Hook了。
2.第二种找NtOpenProcess的方法,就是通过将内存中SSDT->ServiceTableBase的偏移(RVA)转换为文件中文件中它的偏移(FOA),然后通过调用号再找到文件中NtOpenProcess的地址,然后转换为内存中的地址方法和上述步骤一样。 那么怎么将RVA转换为FVA呢?
《WindowsPE权威指南》93页上,
(1) 首先判断RVA落在哪个节内。
(2) 求出该节的起始 RVA0 = IMAGE_SRCTION_HEADER->VirtualAddress
(3) 求出偏移量Offset = RVA-RVA0. 这个偏移在文件中和内存中都是一样的(因为对齐是在节的数据后面补0,而不是前面)。
(4) 求出FOA = IMAGE_SECTION_HEADER.PointerToRawData+Offset
好了,64位的两种方法就介绍完了,32位的话,有几个地方需要注意:
1.Ntoskrnl.exe在32位下有几种不同的模式,
参考博客:http://www.tuicool.com/articles/UrqIZv
所以要判断当下系统是哪一个。
2.就是NtOpenProcess在SSDT表中以地址的形式保存,就是和64位的一般区别了。
细节看代码吧:
1 #include <ntifs.h> 2 3 #define SEC_IMAGE 0x001000000 4 5 extern 6 PIMAGE_NT_HEADERS 7 NTAPI 8 RtlImageNtHeader(PVOID BaseAddress); 9 10 typedef enum _SYSTEM_INFORMATION_CLASS_ 11 { 12 SystemBasicInformation = 0x0, 13 SystemProcessorInformation = 0x1, 14 SystemPerformanceInformation = 0x2, 15 SystemTimeOfDayInformation = 0x3, 16 SystemPathInformation = 0x4, 17 SystemProcessInformation = 0x5, 18 SystemCallCountInformation = 0x6, 19 SystemDeviceInformation = 0x7, 20 SystemProcessorPerformanceInformation = 0x8, 21 SystemFlagsInformation = 0x9, 22 SystemCallTimeInformation = 0xa, 23 SystemModuleInformation = 0xb, 24 SystemLocksInformation = 0xc, 25 SystemStackTraceInformation = 0xd, 26 SystemPagedPoolInformation = 0xe, 27 SystemNonPagedPoolInformation = 0xf, 28 SystemHandleInformation = 0x10, 29 SystemObjectInformation = 0x11, 30 SystemPageFileInformation = 0x12, 31 SystemVdmInstemulInformation = 0x13, 32 SystemVdmBopInformation = 0x14, 33 SystemFileCacheInformation = 0x15, 34 SystemPoolTagInformation = 0x16, 35 SystemInterruptInformation = 0x17, 36 SystemDpcBehaviorInformation = 0x18, 37 SystemFullMemoryInformation = 0x19, 38 SystemLoadGdiDriverInformation = 0x1a, 39 SystemUnloadGdiDriverInformation = 0x1b, 40 SystemTimeAdjustmentInformation = 0x1c, 41 SystemSummaryMemoryInformation = 0x1d, 42 SystemMirrorMemoryInformation = 0x1e, 43 SystemPerformanceTraceInformation = 0x1f, 44 SystemObsolete0 = 0x20, 45 SystemExceptionInformation = 0x21, 46 SystemCrashDumpStateInformation = 0x22, 47 SystemKernelDebuggerInformation = 0x23, 48 SystemContextSwitchInformation = 0x24, 49 SystemRegistryQuotaInformation = 0x25, 50 SystemExtendServiceTableInformation = 0x26, 51 SystemPrioritySeperation = 0x27, 52 SystemVerifierAddDriverInformation = 0x28, 53 SystemVerifierRemoveDriverInformation = 0x29, 54 SystemProcessorIdleInformation = 0x2a, 55 SystemLegacyDriverInformation = 0x2b, 56 SystemCurrentTimeZoneInformation = 0x2c, 57 SystemLookasideInformation = 0x2d, 58 SystemTimeSlipNotification = 0x2e, 59 SystemSessionCreate = 0x2f, 60 SystemSessionDetach = 0x30, 61 SystemSessionInformation = 0x31, 62 SystemRangeStartInformation = 0x32, 63 SystemVerifierInformation = 0x33, 64 SystemVerifierThunkExtend = 0x34, 65 SystemSessionProcessInformation = 0x35, 66 SystemLoadGdiDriverInSystemSpace = 0x36, 67 SystemNumaProcessorMap = 0x37, 68 SystemPrefetcherInformation = 0x38, 69 SystemExtendedProcessInformation = 0x39, 70 SystemRecommendedSharedDataAlignment = 0x3a, 71 SystemComPlusPackage = 0x3b, 72 SystemNumaAvailableMemory = 0x3c, 73 SystemProcessorPowerInformation = 0x3d, 74 SystemEmulationBasicInformation = 0x3e, 75 SystemEmulationProcessorInformation = 0x3f, 76 SystemExtendedHandleInformation = 0x40, 77 SystemLostDelayedWriteInformation = 0x41, 78 SystemBigPoolInformation = 0x42, 79 SystemSessionPoolTagInformation = 0x43, 80 SystemSessionMappedViewInformation = 0x44, 81 SystemHotpatchInformation = 0x45, 82 SystemObjectSecurityMode = 0x46, 83 SystemWatchdogTimerHandler = 0x47, 84 SystemWatchdogTimerInformation = 0x48, 85 SystemLogicalProcessorInformation = 0x49, 86 SystemWow64SharedInformationObsolete = 0x4a, 87 SystemRegisterFirmwareTableInformationHandler = 0x4b, 88 SystemFirmwareTableInformation = 0x4c, 89 SystemModuleInformationEx = 0x4d, 90 SystemVerifierTriageInformation = 0x4e, 91 SystemSuperfetchInformation = 0x4f, 92 SystemMemoryListInformation = 0x50, 93 SystemFileCacheInformationEx = 0x51, 94 SystemThreadPriorityClientIdInformation = 0x52, 95 SystemProcessorIdleCycleTimeInformation = 0x53, 96 SystemVerifierCancellationInformation = 0x54, 97 SystemProcessorPowerInformationEx = 0x55, 98 SystemRefTraceInformation = 0x56, 99 SystemSpecialPoolInformation = 0x57, 100 SystemProcessIdInformation = 0x58, 101 SystemErrorPortInformation = 0x59, 102 SystemBootEnvironmentInformation = 0x5a, 103 SystemHypervisorInformation = 0x5b, 104 SystemVerifierInformationEx = 0x5c, 105 SystemTimeZoneInformation = 0x5d, 106 SystemImageFileExecutionOptionsInformation = 0x5e, 107 SystemCoverageInformation = 0x5f, 108 SystemPrefetchPatchInformation = 0x60, 109 SystemVerifierFaultsInformation = 0x61, 110 SystemSystemPartitionInformation = 0x62, 111 SystemSystemDiskInformation = 0x63, 112 SystemProcessorPerformanceDistribution = 0x64, 113 SystemNumaProximityNodeInformation = 0x65, 114 SystemDynamicTimeZoneInformation = 0x66, 115 SystemCodeIntegrityInformation = 0x67, 116 SystemProcessorMicrocodeUpdateInformation = 0x68, 117 SystemProcessorBrandString = 0x69, 118 SystemVirtualAddressInformation = 0x6a, 119 SystemLogicalProcessorAndGroupInformation = 0x6b, 120 SystemProcessorCycleTimeInformation = 0x6c, 121 SystemStoreInformation = 0x6d, 122 SystemRegistryAppendString = 0x6e, 123 SystemAitSamplingValue = 0x6f, 124 SystemVhdBootInformation = 0x70, 125 SystemCpuQuotaInformation = 0x71, 126 SystemNativeBasicInformation = 0x72, 127 SystemErrorPortTimeouts = 0x73, 128 SystemLowPriorityIoInformation = 0x74, 129 SystemBootEntropyInformation = 0x75, 130 SystemVerifierCountersInformation = 0x76, 131 SystemPagedPoolInformationEx = 0x77, 132 SystemSystemPtesInformationEx = 0x78, 133 SystemNodeDistanceInformation = 0x79, 134 SystemAcpiAuditInformation = 0x7a, 135 SystemBasicPerformanceInformation = 0x7b, 136 SystemQueryPerformanceCounterInformation = 0x7c, 137 SystemSessionBigPoolInformation = 0x7d, 138 SystemBootGraphicsInformation = 0x7e, 139 SystemScrubPhysicalMemoryInformation = 0x7f, 140 SystemBadPageInformation = 0x80, 141 SystemProcessorProfileControlArea = 0x81, 142 SystemCombinePhysicalMemoryInformation = 0x82, 143 SystemEntropyInterruptTimingInformation = 0x83, 144 SystemConsoleInformation = 0x84, 145 SystemPlatformBinaryInformation = 0x85, 146 SystemThrottleNotificationInformation = 0x86, 147 SystemHypervisorProcessorCountInformation = 0x87, 148 SystemDeviceDataInformation = 0x88, 149 SystemDeviceDataEnumerationInformation = 0x89, 150 SystemMemoryTopologyInformation = 0x8a, 151 SystemMemoryChannelInformation = 0x8b, 152 SystemBootLogoInformation = 0x8c, 153 SystemProcessorPerformanceInformationEx = 0x8d, 154 SystemSpare0 = 0x8e, 155 SystemSecureBootPolicyInformation = 0x8f, 156 SystemPageFileInformationEx = 0x90, 157 SystemSecureBootInformation = 0x91, 158 SystemEntropyInterruptTimingRawInformation = 0x92, 159 SystemPortableWorkspaceEfiLauncherInformation = 0x93, 160 SystemFullProcessInformation = 0x94, 161 SystemKernelDebuggerInformationEx = 0x95, 162 SystemBootMetadataInformation = 0x96, 163 SystemSoftRebootInformation = 0x97, 164 SystemElamCertificateInformation = 0x98, 165 SystemOfflineDumpConfigInformation = 0x99, 166 SystemProcessorFeaturesInformation = 0x9a, 167 SystemRegistryReconciliationInformation = 0x9b, 168 MaxSystemInfoClass = 0x9c, 169 } SYSTEM_INFORMATION_CLASS; 170 171 172 typedef struct _SYSTEM_MODULE_INFORMATION 173 { 174 ULONG Reserved[2]; 175 #ifdef _WIN64 176 ULONG Reserved2[2]; 177 #endif 178 179 PVOID Base; 180 ULONG Size; 181 ULONG Flags; 182 USHORT Index; 183 USHORT Unknown; 184 USHORT LoadCount; 185 USHORT ModuleNameOffset; 186 CHAR ImageName[256]; 187 }SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION; 188 189 typedef struct 190 { 191 ULONG ulNumberOfModules; 192 SYSTEM_MODULE_INFORMATION smi; //我只取Ntoskrnl一个 193 }MODULES,*PMODULES; 194 195 196 typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_ 197 { 198 PVOID ServiceTableBase; //SSDT(System Service Dispatch Table)服务表的基地址 199 PVOID ServiceCounterTableBase; //用于checked builds,包含SSDT中每个服务被调用的次数 200 PVOID NumberOfServices; //服务函数的个数,NumberOfService * 4就是整个地址表的大小 64位 0x191, 32位 0x11c 201 PVOID ParamTableBase; //SSPT(System Service Parameter Table)的基地址 202 }SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE; 203 204 extern 205 NTSTATUS 206 ZwQuerySystemInformation( 207 IN ULONG SystemInformationClass, 208 IN PVOID SystemInformation, 209 IN ULONG SystemInformationLength, 210 OUT PULONG ReturnLength); 211 212 void chartowchar(char* src, WCHAR* dst); 213 214 VOID UnloadDriver(PDRIVER_OBJECT DriverObject); 215 216 BOOLEAN GetModuleInfoByModuleName(PVOID* ModuleBase, ULONG64* ModuleSize); 217 218 219 220 BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress); 221 222 BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress); 223 224 PVOID GetExportVariableAddressFromNtoskrnlExportTableByVariableName(WCHAR* wzVariableName); 225 226 BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG* SSDTFunctionIndex); 227 228 VOID WPOFF(); 229 230 VOID WPON(); 231 232 BOOLEAN Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize); 233 234 BOOLEAN ResumeSSDTInWin7(ULONG_PTR SSDTAddress, ULONG_PTR ModuleBase, ULONG32 SSDTFunctionIndex, ULONG32 ParameterCount); 235 236 BOOLEAN ReadingFileInRing0Space(WCHAR* wzFileFullPath, PVOID* szBuffer); 237 238 VOID CharToWchar(PCHAR src, PWCHAR dst);
1 #include "ResumeSSDT.h" 2 #include <ntstrsafe.h> 3 #include <ntimage.h> 4 5 PVOID __NtosModuleBaseAddress = 0; 6 PVOID __NtosModuleSize = 0; 7 ULONG __NtOpenProcessIndex = 0; 8 char __szNtosName[15] = { 0 }; 9 WCHAR __wzNtosName[15] = { 0 }; 10 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverEntry, PUNICODE_STRING RegisterPath) 11 { 12 13 ULONG_PTR SSDTAddress = 0; 14 char szFunctionName[] = "NtOpenProcess"; 15 DriverEntry->DriverUnload = UnloadDriver; 16 if (GetModuleInfoByModuleName( 17 &__NtosModuleBaseAddress, &__NtosModuleSize) == FALSE) 18 { 19 return STATUS_UNSUCCESSFUL; 20 } 21 DbgPrint("_Ntos:%p", __NtosModuleBaseAddress); 22 23 24 #ifdef _WIN64 25 if (GetSSDTAddressInWin7_x64(&SSDTAddress) == FALSE) 26 { 27 DbgPrint("U "); 28 return STATUS_UNSUCCESSFUL; 29 } 30 #else 31 if (GetSSDTAddressInWin7_x86(&SSDTAddress) == FALSE) 32 { 33 return STATUS_UNSUCCESSFUL; 34 } 35 #endif 36 if (GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(szFunctionName, &__NtOpenProcessIndex) == FALSE) 37 { 38 return STATUS_UNSUCCESSFUL; 39 } 40 41 if (ResumeSSDTInWin7(SSDTAddress, __NtosModuleBaseAddress, __NtOpenProcessIndex, 4) == TRUE) 42 { 43 DbgPrint("Success "); 44 return STATUS_SUCCESS; 45 } 46 47 return STATUS_UNSUCCESSFUL; 48 } 49 50 VOID UnloadDriver(PDRIVER_OBJECT DriverObject) 51 { 52 DbgPrint("UnloadDriver Success! "); 53 } 54 55 //下面这个函数是根据模块名字得到模块信息 56 BOOLEAN GetModuleInfoByModuleName(PVOID* ModuleBase, ULONG64* ModuleSize) 57 { 58 NTSTATUS Status = STATUS_SUCCESS; 59 ULONG ulReturnLength = 0; 60 PVOID szBufferData = 0; 61 62 Status = ZwQuerySystemInformation(SystemModuleInformation,NULL, 0, &ulReturnLength); 63 if (Status != STATUS_INFO_LENGTH_MISMATCH) //此返回值的意思是 返回的长度不等于你要求的长度,因为我们传0,所以正好判断一下是否读取成功 64 { 65 return FALSE; 66 } 67 szBufferData = ExAllocatePool(PagedPool, ulReturnLength); //一般数据可以用PagedPool,ShellCode用NoPagedPool 68 if (szBufferData == NULL) 69 { 70 return FALSE; 71 } 72 Status = ZwQuerySystemInformation(SystemModuleInformation, szBufferData, ulReturnLength, &ulReturnLength); 73 if (!NT_SUCCESS(Status)) 74 { 75 ExFreePool(szBufferData); 76 return FALSE; 77 } 78 for (int i = 0; i < ((PMODULES)szBufferData)->ulNumberOfModules; i++) 79 { 80 if (strstr(((PMODULES)szBufferData)->smi.ImageName,"ntoskrnl.exe") != NULL) 81 { 82 strcpy(__szNtosName, "ntoskrnl.exe"); 83 *ModuleBase = ((PMODULES)szBufferData)->smi.Base; 84 *ModuleSize = ((PMODULES)szBufferData)->smi.Size; 85 break; 86 } 87 else if (strstr(((PMODULES)szBufferData)->smi.ImageName, "ntkrnlpa.exe") != NULL) 88 { 89 strcpy(__szNtosName, "ntkrnlpa.exe"); 90 *ModuleBase = ((PMODULES)szBufferData)->smi.Base; 91 *ModuleSize = ((PMODULES)szBufferData)->smi.Size; 92 break; 93 } 94 else if (strstr(((PMODULES)szBufferData)->smi.ImageName, "ntkrnlmp.exe") != NULL) 95 { 96 strcpy(__szNtosName, "ntkrnlmp.exe"); 97 *ModuleBase = ((PMODULES)szBufferData)->smi.Base; 98 *ModuleSize = ((PMODULES)szBufferData)->smi.Size; 99 break; 100 } 101 else if (strstr(((PMODULES)szBufferData)->smi.ImageName, "ntkrpamp.exe") != NULL) 102 { 103 strcpy(__szNtosName, "ntkrpamp.exe"); 104 *ModuleBase = ((PMODULES)szBufferData)->smi.Base; 105 *ModuleSize = ((PMODULES)szBufferData)->smi.Size; 106 break; 107 } 108 } 109 chartowchar(__szNtosName, __wzNtosName); 110 if (szBufferData != NULL) 111 { 112 ExFreePool(szBufferData); 113 szBufferData = NULL; 114 } 115 if (*ModuleBase != 0) 116 { 117 return TRUE; 118 } 119 return FALSE; 120 } 121 122 123 //BOOLEAN GetNtosModule(PVOID* ModuleBase, ULONG64* ModuleSize) 124 //{ 125 // NTSTATUS Status = STATUS_SUCCESS; 126 // ULONG ulReturnLength = 0; 127 // PVOID szBufferData = 0; 128 // 129 // Status = ZwQuerySystemInformation(SystemModuleInformation,NULL, 0, &ulReturnLength); 130 // if (Status != STATUS_INFO_LENGTH_MISMATCH) //此返回值的意思是 返回的长度不等于你要求的长度,因为我们传0,所以正好判断一下是否读取成功 131 // { 132 // return FALSE; 133 // } 134 // szBufferData = ExAllocatePool(PagedPool, ulReturnLength); //一般数据可以用PagedPool,ShellCode用NoPagedPool 135 // if (szBufferData == NULL) 136 // { 137 // return FALSE; 138 // } 139 // Status = ZwQuerySystemInformation(SystemModuleInformation, szBufferData, ulReturnLength, &ulReturnLength); 140 // if (!NT_SUCCESS(Status)) 141 // { 142 // ExFreePool(szBufferData); 143 // return FALSE; 144 // } 145 // for (int i = 0; i < ((PMODULES)szBufferData)->ulNumberOfModules; i++) 146 // { 147 // strcpy(__szNtosName, ((PMODULES)szBufferData)->smi.ImageName); //依据的原理就是ZwQuerySystemInformation读的第一个模块就是Ntos系列的,这样不用比对,直接取第一个,大大方便了32位的编程 148 // CharToWchar(__szNtosName, __wzNtosName); 149 // *ModuleBase = ((PMODULES)szBufferData)->smi.Base; 150 // *ModuleSize = ((PMODULES)szBufferData)->smi.Size; 151 // break; 152 // } 153 // if (szBufferData != NULL) 154 // { 155 // ExFreePool(szBufferData); 156 // szBufferData = NULL; 157 // } 158 // if (*ModuleBase != 0) 159 // { 160 // return TRUE; 161 // } 162 // return FALSE; 163 //} 164 //char*转 wchar* 165 //输入窄字符串首地址,输出宽字符串,buffer 需要已经分配好空间 166 167 void chartowchar(char* src, WCHAR* dst) 168 { 169 UNICODE_STRING ustring; 170 ANSI_STRING astring; 171 RtlInitAnsiString(&astring, src); 172 RtlAnsiStringToUnicodeString(&ustring, &astring, TRUE); 173 wcscpy(dst, ustring.Buffer); 174 RtlFreeUnicodeString(&ustring); 175 } 176 177 BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress) 178 { 179 CHAR* StartSearchAddress = (char*)__readmsr(0xc0000082); 180 CHAR* EndSearchAddress = StartSearchAddress + PAGE_SIZE; 181 CHAR* i = NULL; 182 UCHAR v1 = 0, v2 = 0, v3 = 0; 183 INT64 Offset = 0; 184 *SSDTAddress = NULL; 185 for (i = StartSearchAddress; i < EndSearchAddress; i++) 186 { 187 if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2)) 188 { 189 v1 = *i; 190 v2 = *(i + 1); 191 v3 = *(i + 2); 192 if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15) 193 { 194 memcpy(&Offset, i + 3, 4); 195 *SSDTAddress = Offset + (ULONG64)i + 7; 196 return TRUE; 197 } 198 } 199 } 200 return FALSE; 201 } 202 203 BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress) 204 { 205 //直接查找KeServiceDescriptorTable 206 *SSDTAddress = (ULONG32)GetExportVariableAddressFromNtoskrnlExportTableByVariableName(L"KeServiceDescriptorTable"); 207 if (*SSDTAddress != 0) 208 { 209 return TRUE; 210 } 211 return FALSE; 212 } 213 214 PVOID GetExportVariableAddressFromNtoskrnlExportTableByVariableName(WCHAR* wzVariableName) 215 { 216 UNICODE_STRING uniVariableName; 217 PVOID VariableAddress = NULL; 218 if (wzVariableName&&wcslen(wzVariableName) > 0) 219 { 220 RtlUnicodeStringInit(&uniVariableName, wzVariableName); 221 VariableAddress = MmGetSystemRoutineAddress(&uniVariableName); 222 } 223 return VariableAddress; 224 } 225 226 BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG* SSDTFunctionIndex) 227 { 228 WCHAR szFileFullPath[] = L"\SystemRoot\System32\ntdll.dll"; 229 ULONG32 Offset_SSDTFunctionIndex = 0; 230 PVOID MappingBaseAddress = 0; 231 BOOLEAN IsOk = FALSE; 232 ULONG_PTR MappingViewSize = 0; 233 PIMAGE_NT_HEADERS Image_Nt_Headers = NULL; 234 PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL; 235 //因为不识别DWORD,所以用UINT32 236 UINT32* AddressOfFunctions = NULL; 237 UINT32* AddressOfNames = NULL; 238 UINT16* AddressOfNameOrdinals = NULL; 239 int i = 0; 240 char* v1 = NULL; 241 ULONG32 OrdinalOfFunction = 0; 242 PVOID AddressOfFunction = 0; 243 #ifdef _WIN64 244 Offset_SSDTFunctionIndex = 4; 245 #else 246 Offset_SSDTFunctionIndex = 1; 247 #endif 248 *SSDTFunctionIndex = -1; 249 IsOk = Ring0MappingPEFile(szFileFullPath, &MappingBaseAddress, &MappingViewSize); 250 if (IsOk == FALSE) 251 { 252 return FALSE; 253 } 254 else 255 { 256 __try 257 { 258 Image_Nt_Headers = RtlImageNtHeader(MappingBaseAddress); 259 if (Image_Nt_Headers&&Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) 260 { 261 ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((char*)MappingBaseAddress 262 + Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 263 264 AddressOfFunctions = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions); 265 //函数的地址(RVA) 266 AddressOfNames = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);; 267 //函数名字的地址(RVA) 268 AddressOfNameOrdinals = (UINT16*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals); 269 //有名字的序号的首地址(RVA) 270 for (i = 0; i < ImageExportDirectory->NumberOfNames; i++) 271 { 272 v1 = (char*)((char*)MappingBaseAddress + AddressOfNames[i]); //可以这样写 ImageExportDirectory->AddressOfNames + i * 4 273 if (_stricmp(szFuntionName, v1) == 0) 274 { 275 OrdinalOfFunction = AddressOfNameOrdinals[i]; 276 AddressOfFunction = (PVOID)((char*)MappingBaseAddress + AddressOfFunctions[OrdinalOfFunction]);//AddressOfFunctions[AddressOfNameOrdinals[i]] 277 *SSDTFunctionIndex = *(ULONG32*)((char*)AddressOfFunction + Offset_SSDTFunctionIndex); 278 break; 279 } 280 } 281 } 282 } 283 __except (EXCEPTION_EXECUTE_HANDLER) 284 {} 285 } 286 ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress); 287 if (*SSDTFunctionIndex == -1) 288 { 289 return FALSE; 290 } 291 return TRUE; 292 } 293 294 BOOLEAN Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize) 295 { 296 UNICODE_STRING v1; 297 OBJECT_ATTRIBUTES oa; 298 NTSTATUS Status; 299 HANDLE hFile = NULL; 300 HANDLE hSection = NULL; 301 IO_STATUS_BLOCK IoStatusBlock; 302 if (!szFileFullPath&&MmIsAddressValid(szFileFullPath)) 303 { 304 return FALSE; 305 } 306 if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress)) 307 { 308 return FALSE; 309 } 310 RtlUnicodeStringInit(&v1, szFileFullPath); 311 InitializeObjectAttributes(&oa, 312 &v1, 313 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 314 NULL, 315 NULL 316 ); 317 Status = IoCreateFile(&hFile, 318 GENERIC_READ | SYNCHRONIZE, 319 &oa, 320 &IoStatusBlock, 321 NULL, 322 FILE_ATTRIBUTE_NORMAL, 323 FILE_SHARE_READ, 324 FILE_OPEN, 325 FILE_SYNCHRONOUS_IO_NONALERT, 326 NULL, 327 0, 328 CreateFileTypeNone, 329 NULL, 330 IO_NO_PARAMETER_CHECKING); 331 if (!NT_SUCCESS(Status)) 332 { 333 return FALSE; 334 } 335 oa.ObjectName = NULL; 336 Status = ZwCreateSection(&hSection, 337 SECTION_QUERY | SECTION_MAP_READ, 338 &oa, 339 NULL, 340 PAGE_WRITECOPY, 341 SEC_IMAGE, 342 hFile); 343 ZwClose(hFile); 344 if (!NT_SUCCESS(Status)) 345 { 346 return FALSE; 347 } 348 Status = ZwMapViewOfSection(hSection, 349 NtCurrentProcess(), 350 MappingBaseAddress, 351 0, 352 0, 353 0, 354 MappingViewSize, 355 ViewUnmap, //不能被映射到子进程中 356 0, 357 PAGE_WRITECOPY 358 ); 359 ZwClose(hSection); 360 if (!NT_SUCCESS(Status)) 361 { 362 return FALSE; 363 } 364 return TRUE; 365 } 366 367 368 BOOLEAN ResumeSSDTInWin7(ULONG_PTR SSDTAddress, ULONG_PTR ModuleBase, ULONG32 SSDTFunctionIndex, ULONG32 ParameterCount) 369 { 370 PUCHAR RVAOfSSDTBase = 0; 371 PVOID szBuffer = NULL; 372 PVOID PresupposeOfImageBase = 0; 373 PVOID AddressOfSSDTBaseInFile = 0; 374 PVOID Temp = 0; 375 CHAR TempByte = 0; 376 CHAR Bits[4] = { 0 }; 377 ULONG32 HookedOffset = 0; 378 PIMAGE_DOS_HEADER Image_Dos_Header = NULL; 379 PIMAGE_NT_HEADERS Image_Nt_Headers = NULL; 380 PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL; 381 PIMAGE_SECTION_HEADER SectionHeader = NULL; 382 WCHAR wzFileFullPath[0x100] = L"\SystemRoot\System32\"; // C:\ 383 int i = 0; 384 wcscat(wzFileFullPath, __wzNtosName); 385 RVAOfSSDTBase = (PUCHAR)(((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase) - (PUCHAR)ModuleBase; 386 if (ReadingFileInRing0Space(wzFileFullPath, &szBuffer) == FALSE) 387 { 388 return FALSE; 389 } 390 Image_Dos_Header = (PIMAGE_DOS_HEADER)szBuffer; 391 Image_Nt_Headers = (PIMAGE_NT_HEADERS)(Image_Dos_Header->e_lfanew + (PUCHAR)szBuffer); 392 OptionalHeader = &(Image_Nt_Headers->OptionalHeader); 393 PresupposeOfImageBase = OptionalHeader->ImageBase; //64位为0x00000001`40000000,假想值,希望EXE文件加载到内存后就是这个值,并且文件中所有的机器码都是按照这个地址对齐的 394 395 SectionHeader = (PIMAGE_SECTION_HEADER)((char*)Image_Nt_Headers + sizeof(IMAGE_NT_HEADERS)); 396 for (i = 0; i < Image_Nt_Headers->FileHeader.NumberOfSections; i++) 397 { 398 if (RVAOfSSDTBase >= SectionHeader[i].VirtualAddress && RVAOfSSDTBase < (SectionHeader[i].VirtualAddress + SectionHeader[i].SizeOfRawData)) 399 { //内存映像中的RVA 400 AddressOfSSDTBaseInFile = (PVOID)((PUCHAR)szBuffer + (RVAOfSSDTBase - (PUCHAR)(SectionHeader[i].VirtualAddress)) + (SectionHeader[i].PointerToRawData)); 401 break; 402 } //0xfffff7fe`c3e5a040 403 } 404 Temp = (PUCHAR)(((PULONG_PTR)AddressOfSSDTBaseInFile)[SSDTFunctionIndex]) - (PUCHAR)PresupposeOfImageBase + (PUCHAR)ModuleBase; 405 406 #ifdef _WIN64 407 //重定位函数地址 内存中的函数地址 = 预想的函数基地址 - 预想的模块基地址 + 真实的模块基地址 预想的基地址是由操作系统自己完成,链接器在产生可执行文件的时候,是对应ImageBase来生成机器码的 408 Temp = (PUCHAR)Temp - (PUCHAR)(((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase); 409 Temp = (ULONG32)Temp << 4; 410 //处理参数个数 411 412 if (ParameterCount > 4) 413 { 414 ParameterCount = ParameterCount - 4; 415 } 416 else 417 { 418 ParameterCount = 0; 419 } 420 memcpy(&TempByte, &Temp, 1); 421 #define SETBIT(x, y) x |= (1 << y) //将X的第Y位置1 422 #define CLRBIT(x,y) x&=~(1<<y) //将X的第Y位清0 423 #define GETBIT(x,y) (x & (1 << y)) //取X的第Y位,返回0或非0 424 for (i = 0; i < 4; i++) 425 { 426 Bits[i] = GETBIT(ParameterCount, i); 427 if (Bits[i]) 428 { 429 SETBIT(TempByte, i); 430 } 431 else 432 { 433 CLRBIT(TempByte, i); 434 } 435 } 436 memcpy(&Temp, &TempByte, 1); 437 #endif // _WIN64 438 //获得当前已经被Hook了的地址 439 HookedOffset = ((PULONG32)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase)[SSDTFunctionIndex]; 440 if (Temp != HookedOffset) 441 { 442 WPOFF(); 443 ((PLONG32)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)Temp; 444 WPON(); 445 } 446 if (szBuffer != NULL) 447 { 448 ExFreePool(szBuffer); 449 szBuffer = NULL; 450 } 451 return TRUE; 452 } 453 454 455 456 BOOLEAN ReadingFileInRing0Space(WCHAR* wzFileFullPath, PVOID* szBuffer) 457 { 458 NTSTATUS Status; 459 UNICODE_STRING Temp; 460 OBJECT_ATTRIBUTES oa; 461 HANDLE hFile; 462 IO_STATUS_BLOCK IoStatusBlock; 463 LARGE_INTEGER liReturnLength = { 0 }; 464 FILE_STANDARD_INFORMATION fsi = { 0 }; 465 if (wzFileFullPath == NULL&&*szBuffer != NULL) 466 { 467 return FALSE; 468 } 469 RtlUnicodeStringInit(&Temp, wzFileFullPath); 470 InitializeObjectAttributes(&oa, &Temp, OBJ_CASE_INSENSITIVE, NULL, NULL); 471 Status = ZwCreateFile(&hFile, 472 SYNCHRONIZE, //异步 473 &oa, 474 &IoStatusBlock, 475 NULL, 476 FILE_ATTRIBUTE_NORMAL, 477 FILE_SHARE_READ, 478 FILE_OPEN, 479 FILE_SYNCHRONOUS_IO_NONALERT, 480 NULL, 481 0); 482 if (!NT_SUCCESS(Status)) 483 { 484 return FALSE; 485 } 486 Status = ZwQueryInformationFile(hFile, 487 &IoStatusBlock, 488 &fsi, 489 sizeof(FILE_STANDARD_INFORMATION), 490 FileStandardInformation); 491 if (!NT_SUCCESS(Status)) 492 { 493 ZwClose(hFile); 494 return FALSE; 495 } 496 *szBuffer = ExAllocatePool(PagedPool, fsi.EndOfFile.LowPart); 497 if (*szBuffer == NULL) 498 { 499 ZwClose(hFile); 500 return FALSE; 501 } 502 Status = ZwReadFile(hFile, 503 NULL, 504 NULL, 505 NULL, 506 &IoStatusBlock, 507 *szBuffer, 508 fsi.EndOfFile.LowPart, 509 &liReturnLength, 510 NULL); 511 512 if (!NT_SUCCESS(Status)) 513 { 514 ExFreePool(*szBuffer); 515 ZwClose(hFile); 516 return FALSE; 517 } 518 ZwClose(hFile); 519 return TRUE; 520 } 521 522 523 524 525 VOID WPOFF() 526 { 527 _disable(); 528 __writecr0(__readcr0() & (~(0x10000))); 529 530 } 531 VOID WPON() 532 { 533 __writecr0(__readcr0() ^ 0x10000); 534 _enable(); 535 }
这几个终于做完了,做驱动的代码,我感觉有个坑,因为内核的地址都比较大,都达到0xFFFF8000_00000000以上了,所以一般如果表示成十进制有符号数,都是负数了,你如果直接和某个数加,如果这个数是ULONG类型的,则那个地址必须转换了,就出错了,看下面的例子:
PointerToRawData是ULONG类型,如果前面几个变量用PCHAR的话,根据C语言的默认的强制类型转换规则,char,short --> int --> unsigned --> long --> double <-- float。 内核层的地址都成负数了,一加肯定错了,坑了好几次,引以为戒吧。
最后如果我哪里有理解错的地方,欢迎大家指正,我将虚心求教。