WindowsAPI编程核心技术-注册表监控
前置芝士
CmRegisterCallback
注册注册表监控例程。
1 2 3 4 5
| NTSTATUS CmRegisterCallback( _In_ PEX_CALLBACK_FUNCTION Function, _In_opt_ PVOID Context, _Out_ PLARGE_INTEGER Cookie )
|
PEX_CALLBACK_FUNCTION
回调函数。
1 2 3 4 5
| NTSTATUS RegistryCallback( _In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2 )
|
实现方法
设置注册表回调函数时会拿到Cookie:
1 2 3 4 5 6 7 8 9 10
| NTSTATUS SetRegisterCallback() { NTSTATUS status = CmRegisterCallback(RegisterMonCallback, NULL, &g_liRegCookie); if (!NT_SUCCESS(status)) { ShowError("CmRegisterCallback", status); g_liRegCookie.QuadPart = 0; return status; }; return status; };
|
删除注册表回调函数时直接用Cookie删就好啦:
1 2 3 4 5 6
| VOID RemoveRegisterCallback(VOID) { if (0 < g_liRegCookie.QuadPart) CmUnRegisterCallback(g_liRegCookie); return; };
|
当要拒绝注册表指定键操作时,回调函数直接除STATUS_SUCCESS以外的错误码,如STATUS_ACCESS_DENIED等。
回调函数的第一个参数判断操作类型,RegNtPreCreateKey将要创建注册表,RegNtPreOpenKey将要打开注册表,RegNtPreDeleteKey将要删除注册表,RegNtPreDeleteValueKey将要删除注册表键值,RegNtPreSetValueKey将要修改键值。
第二个参数获取操作类型对应结构体数据,从中获取注册表路径对象,用ObQueryNameString
获取字符串路径。不同操作结构体不同。
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
| NTSTATUS RegisterMonCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING ustrRegPath; LONG lOperateType = (REG_NOTIFY_CLASS)Argument1; ustrRegPath.Length = 0; ustrRegPath.MaximumLength = 1024 * sizeof(WCHAR); ustrRegPath.Buffer = ExAllocatePool(NonPagedPool, ustrRegPath.MaximumLength); if (NULL == ustrRegPath.Buffer) { ShowError("ExAllocatePool", 0); return status; }; RtlZeroMemory(ustrRegPath.Buffer, ustrRegPath.MaximumLength); switch (lOperateType) { case RegNtPreCreateKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject); DbgPrint("[RegNtPreCreateKey][%wZ][%wZ]\n", &ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName); break; }; case RegNtPreOpenKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject); DbgPrint("[RegNtPreOpenKey][%wZ][%wZ]\n", &ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName); break; }; case RegNtPreDeleteKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_DELETE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[RegNtPreDeleteKey][%wZ]\n", &ustrRegPath); break; }; case RegNtPreDeleteValueKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[RegNtPreDeleteValueKey][%wZ][%wZ]\n", &ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->ValueName); break; }; case RegNtPreSetValueKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[RegNtPreSetValueKey][%wZ][%wZ]\n", &ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->ValueName); break; }; default: break; }; if (IsProtectReg(ustrRegPath)) status = STATUS_ACCESS_DENIED; if (NULL != ustrRegPath.Buffer) { ExFreePool(ustrRegPath.Buffer); ustrRegPath.Buffer = NULL; }; PEPROCESS pEProcess = PsGetCurrentProcess(); if (NULL != pEProcess) { UCHAR* lpszProcessName = PsGetProcessImageFileName(pEProcess); if (NULL != lpszProcessName) DbgPrint("Current Process[%s]\n", lpszProcessName); }; return status; };
|
源代码
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
|
NotifyRoutine.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
| #ifndef _NOTIFY_ROUTINE_H_ #define _NOTIFY_ROUTINE_H_
#include <ntddk.h>
PUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess);
NTSTATUS ObQueryNameString( _In_ PVOID Object, _Out_writes_bytes_opt_(Length) POBJECT_NAME_INFORMATION ObjectNameInfo, _In_ ULONG Length, _Out_ PULONG ReturnLength );
NTSTATUS SetRegisterCallback();
VOID RemoveRegisterCallback();
NTSTATUS RegisterMonCallback( _In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2 );
BOOLEAN GetRegisterObjectCompletePath(PUNICODE_STRING pRegistryPath, PVOID pRegistryObject);
BOOLEAN IsProtectReg(UNICODE_STRING ustrRegPath);
LARGE_INTEGER g_liRegCookie;
#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
| #include "Driver.h" #include "NotifyRoutine.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; }
SetRegisterCallback();
DbgPrint("Leave DriverEntry\n"); return status; }
VOID DriverUnload(PDRIVER_OBJECT pDriverObject) { RemoveRegisterCallback(); }
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; }
|
NotifyRoutine.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
| #include "NotifyRoutine.h"
VOID ShowError(PCHAR lpszText, NTSTATUS ntStatus) { DbgPrint("%s Error[0x%x]\n", lpszText, ntStatus); }
NTSTATUS SetRegisterCallback() { NTSTATUS status = CmRegisterCallback(RegisterMonCallback, NULL, &g_liRegCookie); if (!NT_SUCCESS(status)) { ShowError("CmRegisterCallback", status); g_liRegCookie.QuadPart = 0; return status; }
return status; }
VOID RemoveRegisterCallback() { if (0 < g_liRegCookie.QuadPart) { CmUnRegisterCallback(g_liRegCookie); } }
NTSTATUS RegisterMonCallback( _In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2 ) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING ustrRegPath;
LONG lOperateType = (REG_NOTIFY_CLASS)Argument1; ustrRegPath.Length = 0; ustrRegPath.MaximumLength = 1024 * sizeof(WCHAR); ustrRegPath.Buffer = ExAllocatePool(NonPagedPool, ustrRegPath.MaximumLength); if (NULL == ustrRegPath.Buffer) { ShowError("ExAllocatePool", 0); return status; } RtlZeroMemory(ustrRegPath.Buffer, ustrRegPath.MaximumLength); switch (lOperateType) { case RegNtPreCreateKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject); DbgPrint("[RegNtPreCreateKey][%wZ][%wZ]\n", &ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName); break; } case RegNtPreOpenKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject); DbgPrint("[RegNtPreOpenKey][%wZ][%wZ]\n", &ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName); break; } case RegNtPreDeleteKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_DELETE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[RegNtPreDeleteKey][%wZ]\n", &ustrRegPath); break; } case RegNtPreDeleteValueKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[RegNtPreDeleteValueKey][%wZ][%wZ]\n", &ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->ValueName); break; } case RegNtPreSetValueKey: { GetRegisterObjectCompletePath(&ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[RegNtPreSetValueKey][%wZ][%wZ]\n", &ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->ValueName); break; } default: break; } if (IsProtectReg(ustrRegPath)) { status = STATUS_ACCESS_DENIED; } if (NULL != ustrRegPath.Buffer) { ExFreePool(ustrRegPath.Buffer); ustrRegPath.Buffer = NULL; }
PEPROCESS pEProcess = PsGetCurrentProcess(); if (NULL != pEProcess) { UCHAR *lpszProcessName = PsGetProcessImageFileName(pEProcess); if (NULL != lpszProcessName) { DbgPrint("Current Process[%s]\n", lpszProcessName); } }
return status; }
BOOLEAN GetRegisterObjectCompletePath(PUNICODE_STRING pRegistryPath, PVOID pRegistryObject) { if ((FALSE == MmIsAddressValid(pRegistryObject)) || (NULL == pRegistryObject)) { return FALSE; } ULONG ulSize = 512; PVOID lpObjectNameInfo = ExAllocatePool(NonPagedPool, ulSize); if (NULL == lpObjectNameInfo) { ShowError("ExAllocatePool", 0); return FALSE; } ULONG ulRetLen = 0; NTSTATUS status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)lpObjectNameInfo, ulSize, &ulRetLen); if (!NT_SUCCESS(status)) { ExFreePool(lpObjectNameInfo); ShowError("ObQueryNameString", status); return FALSE; } RtlCopyUnicodeString(pRegistryPath, (PUNICODE_STRING)lpObjectNameInfo); ExFreePool(lpObjectNameInfo); return TRUE; }
BOOLEAN IsProtectReg(UNICODE_STRING ustrRegPath) { if (NULL != wcsstr(ustrRegPath.Buffer, L"DemonGan")) { return TRUE; }
return FALSE; }
|
反注册表监控
基本原理
系统里所有通过CmRegisterCallback
设置的注册表回调函数地址和Cookie都存储在以CallbackListHead
为表头的双向链表中。这个CallbackListHead
双向链表指向的数据结构是:
1 2 3 4 5 6 7 8
| typedef struct _CM_NOTIFY_ENTRY { LIST_ENTRY ListEntryHead; ULONG UnKnown1; ULONG UnKnown2; LARGE_INTEGER Cookie; PVOID Context; PVOID Function; }CM_NOTIFY_ENTRY, * PCM_NOTIFY_ENTRY;
|
获取CallbackListHead
表头地址方法:最简单从删除注册表回调函数CmUnRegisterCallback
获取:
1 2 3 4 5 6 7 8 9 10 11
| ;Windows 10 x64 nt!CmUnRegisterCallback+0x44: 45 33 C0 xor r8d, r8d 48 8D 54 24 38 lea rdx, [rsp+38h] 48 8D 0D 39 F5 DB FF lea rcx,[nt!CallbackListHead]
;Windows 7 x64 nt!CmUnRegisterCallback+0xC6: 45 33 C0 xor r8d,r8d 48 8D 54 24 20 lea rdx, [rsp+20h] 48 8D 0D 6B 69 DC FF lea rcx, [nt!CallbackListHead]
|
扫描特征码即可,在x86下获取表头地址,在x64下获取表头偏移地址。
|
Windows 7 |
Windows 8.1 |
Windows 10 |
x86 |
BF |
BE |
B9 |
x64 |
488D54(488D0D出现次数太多) |
488D0D |
488D0D |
获取表头地址具体实现代码如下:
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
| PVOID SearchCallbackListHead(PUCHAR pSpecialData, ULONG ulSpecialDataSize, LONG lSpecialOffset) { UNICODE_STRING ustrFuncName; PVOID pAddress = NULL; LONG lOffset = 0; PVOID pCmUnRegisterCallback = NULL; PVOID pCallbackListHead = NULL; RtlInitUnicodeString(&ustrFuncName, L"CmUnRegisterCallback"); pCmUnRegisterCallback = MmGetSystemRoutineAddress(&ustrFuncName); if (NULL == pCmUnRegisterCallback) { ShowError("MmGetSystemRoutineAddress", 0); return pCallbackListHead; }; pAddress = SearchMemory(pCmUnRegisterCallback, (PVOID)((PUCHAR)pCmUnRegisterCallback + 0xFF), pSpecialData, ulSpecialDataSize); if (NULL == pAddress) { ShowError("SearchMemory", 0); return pCallbackListHead; }; #ifdef _WIN64 lOffset = *(PLONG)((PUCHAR)pAddress + lSpecialOffset); pCallbackListHead = (PVOID)((PUCHAR)pAddress + lSpecialOffset + sizeof(LONG) + lOffset); #else pCallbackListHead = *(PVOID*)((PUCHAR)pAddress + lSpecialOffset); #endif return pCallbackListHead; };
|
枚举系统注册表回调函数:
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
| BOOLEAN EnumCallback(VOID) { ULONG i = 0; PVOID pCallbackListHeadAddress = NULL; PCM_NOTIFY_ENTRY pNotifyEntry = NULL; pCallbackListHeadAddress = GetCallbackListHead(); if (NULL == pCallbackListHeadAddress) { DbgPrint("GetCallbackListHead Error!\n"); return FALSE; }; DbgPrint("pCallbackListHeadAddress=0x%p\n", pCallbackListHeadAddress); pNotifyEntry = (PCM_NOTIFY_ENTRY)pCallbackListHeadAddress; do { if (FALSE == MmIsAddressValid(pNotifyEntry)) break; if (MmIsAddressValid(pNotifyEntry->Function)) DbgPrint("CallbackFunction=0x%p, Cookie=0x%I64X\n", pNotifyEntry->Function, pNotifyEntry->Cookie.QuadPart); pNotifyEntry = (PCM_NOTIFY_ENTRY)pNotifyEntry->ListEntryHead.Flink; } while (pCallbackListHeadAddress != (PVOID)pNotifyEntry); return TRUE; };
|
删除注册表回调函数:
1 2 3 4 5 6 7
| NTSTATUS RemoveCallback(LARGE_INTEGER Cookie) { NTSTATUS status = CmUnRegisterCallback(Cookie); if (!NT_SUCCESS(status)) ShowError("CmUnRegisterCallback", status); return status; };
|
源代码
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
|
EnumRemove.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
| #ifndef _ENUM_REMOVE_H_ #define _ENUM_REMOVE_H_
#include <ntddk.h>
typedef struct _CM_NOTIFY_ENTRY { LIST_ENTRY ListEntryHead; ULONG UnKnown1; ULONG UnKnown2; LARGE_INTEGER Cookie; PVOID Context; PVOID Function; }CM_NOTIFY_ENTRY, *PCM_NOTIFY_ENTRY;
BOOLEAN EnumCallback();
NTSTATUS RemoveCallback(LARGE_INTEGER Cookie);
PVOID GetCallbackListHead();
PVOID SearchCallbackListHead(PUCHAR pSpecialData, ULONG ulSpecialDataSize, LONG lSpecialOffset);
PVOID SearchMemory(PVOID pStartAddress, PVOID pEndAddress, PUCHAR pMemoryData, ULONG ulMemoryDataSize);
#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
| #include "EnumRemove.h" #include "Driver.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; }
EnumCallback();
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; }
|
EnumRemove.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
| #include "EnumRemove.h"
VOID ShowError(PCHAR lpszText, NTSTATUS ntStatus) { DbgPrint("%s Error[0x%X]\n", lpszText, ntStatus); }
BOOLEAN EnumCallback() { ULONG i = 0; PVOID pCallbackListHeadAddress = NULL; PCM_NOTIFY_ENTRY pNotifyEntry = NULL;
pCallbackListHeadAddress = GetCallbackListHead(); if (NULL == pCallbackListHeadAddress) { DbgPrint("GetCallbackListHead Error!\n"); return FALSE; } DbgPrint("pCallbackListHeadAddress=0x%p\n", pCallbackListHeadAddress);
pNotifyEntry = (PCM_NOTIFY_ENTRY)pCallbackListHeadAddress; do { if (FALSE == MmIsAddressValid(pNotifyEntry)) { break; } if (MmIsAddressValid(pNotifyEntry->Function)) { DbgPrint("CallbackFunction=0x%p, Cookie=0x%I64X\n", pNotifyEntry->Function, pNotifyEntry->Cookie.QuadPart); } pNotifyEntry = (PCM_NOTIFY_ENTRY)pNotifyEntry->ListEntryHead.Flink;
} while (pCallbackListHeadAddress != (PVOID)pNotifyEntry);
return TRUE; }
NTSTATUS RemoveCallback(LARGE_INTEGER Cookie) { NTSTATUS status = CmUnRegisterCallback(Cookie); if (!NT_SUCCESS(status)) { ShowError("CmUnRegisterCallback", status); } return status; }
PVOID GetCallbackListHead() { PVOID pCallbackListHeadAddress = NULL; RTL_OSVERSIONINFOW osInfo = { 0 }; UCHAR pSpecialData[50] = { 0 }; ULONG ulSpecialDataSize = 0; LONG lSpecialOffset = 0;
RtlGetVersion(&osInfo); if (6 == osInfo.dwMajorVersion) { if (1 == osInfo.dwMinorVersion) { #ifdef _WIN64 pSpecialData[0] = 0x48; pSpecialData[1] = 0x8D; pSpecialData[2] = 0x54; ulSpecialDataSize = 3; lSpecialOffset = 5; #else pSpecialData[0] = 0xBF; ulSpecialDataSize = 1; #endif } else if (2 == osInfo.dwMinorVersion) { #ifdef _WIN64 #else #endif } else if (3 == osInfo.dwMinorVersion) { #ifdef _WIN64 pSpecialData[0] = 0x48; pSpecialData[1] = 0x8D; pSpecialData[2] = 0x0D; ulSpecialDataSize = 3; #else pSpecialData[0] = 0xBE; ulSpecialDataSize = 1; #endif } } else if (10 == osInfo.dwMajorVersion) { #ifdef _WIN64 pSpecialData[0] = 0x48; pSpecialData[1] = 0x8D; pSpecialData[2] = 0x0D; ulSpecialDataSize = 3; #else pSpecialData[0] = 0xB9; ulSpecialDataSize = 1; #endif }
pCallbackListHeadAddress = SearchCallbackListHead(pSpecialData, ulSpecialDataSize, lSpecialOffset); return pCallbackListHeadAddress; }
PVOID SearchCallbackListHead(PUCHAR pSpecialData, ULONG ulSpecialDataSize, LONG lSpecialOffset) { UNICODE_STRING ustrFuncName; PVOID pAddress = NULL; LONG lOffset = 0; PVOID pCmUnRegisterCallback = NULL; PVOID pCallbackListHead = NULL;
RtlInitUnicodeString(&ustrFuncName, L"CmUnRegisterCallback"); pCmUnRegisterCallback = MmGetSystemRoutineAddress(&ustrFuncName); if (NULL == pCmUnRegisterCallback) { ShowError("MmGetSystemRoutineAddress", 0); return pCallbackListHead; }
pAddress = SearchMemory(pCmUnRegisterCallback, (PVOID)((PUCHAR)pCmUnRegisterCallback + 0xFF), pSpecialData, ulSpecialDataSize); if (NULL == pAddress) { ShowError("SearchMemory", 0); return pCallbackListHead; }
#ifdef _WIN64 lOffset = *(PLONG)((PUCHAR)pAddress + lSpecialOffset); pCallbackListHead = (PVOID)((PUCHAR)pAddress + lSpecialOffset + sizeof(LONG) + lOffset); #else pCallbackListHead = *(PVOID *)((PUCHAR)pAddress + lSpecialOffset); #endif
return pCallbackListHead; }
PVOID SearchMemory(PVOID pStartAddress, PVOID pEndAddress, PUCHAR pMemoryData, ULONG ulMemoryDataSize) { PVOID pAddress = NULL; PUCHAR i = NULL; ULONG m = 0;
for (i = (PUCHAR)pStartAddress; i < (PUCHAR)pEndAddress; i++) { for (m = 0; m < ulMemoryDataSize; m++) { if (*(PUCHAR)(i + m) != pMemoryData[m]) { break; } } if (m >= ulMemoryDataSize) { pAddress = (PVOID)(i + ulMemoryDataSize); break; } }
return pAddress; }
|