win32k!ValidateHwnd这个函数大概是win32k.sys中调用频次最高的一个函数,所以我就华丽丽的蓝了,如果哪位能成功hook并且分享下,在下感激不尽
为了节约大家时间,我贴出 shadow ssdt 寻址,ValidateHwnd 寻址 , shadow ssdt hook 模板的代码,希望能为你节约一些时间~
///////////////////////////shadow ssdt寻址////////////////////////////////
/////////////////////////KeServiceDescriptorTable是ssdt,即主表的地址,另外KeServiceDescriptorTableShadow是个全局ULONG
NTSTATUS GetServiceTableShadowAddr(
OUT ULONG* Address)
{
PLIST_ENTRY CurrentProcessLink=NULL,CurrentThreadLink=NULL,StartProcessLink=NULL,StartThreadLink=NULL;
ULONG CurrentProcess=(ULONG)PsGetCurrentProcess();
ULONG CurrentServiceTable,LastRecord=0;
ULONG* pCurrentServiceTable=NULL;
CurrentProcessLink=StartProcessLink=(LIST_ENTRY*)((ULONG)CurrentProcess+PROCESS_LINK_OFFSET);
do
{
CurrentThreadLink=StartThreadLink=(LIST_ENTRY*)(*(ULONG*)((ULONG)CurrentProcessLink-PROCESS_LINK_OFFSET+THREAD_LIST_HEAD));
do
{
pCurrentServiceTable=(ULONG*)((ULONG)CurrentThreadLink-THREAD_LINK_OFFSET+SERVICE_TABLE_OFFSET);
if(MmIsAddressValid((PVOID)pCurrentServiceTable))
{
CurrentServiceTable=*pCurrentServiceTable;
KdPrint(("CurrentThread's Service Table: %X \n",CurrentServiceTable));
//不指向KeServiceDescriptorTable 就指向 KeServiceDescriptorTableShadow
if(CurrentServiceTable!=(ULONG)KeServiceDescriptorTable)
{
if(LastRecord)
{
//只有当两次相邻的不相等数据吻合,才可以认为是shadow ssdt
if(LastRecord==CurrentServiceTable)
{
*Address=CurrentServiceTable;
KdPrint(("KeServiceDescriptorTableShadow: %X \n",CurrentServiceTable));
return STATUS_SUCCESS;
}
}
//记录上一次不相等的数据
LastRecord=CurrentServiceTable;
}
}
CurrentThreadLink=CurrentThreadLink->Flink;
}
while(CurrentThreadLink!=StartThreadLink);
CurrentProcessLink=CurrentProcessLink->Flink;
}
while(CurrentProcessLink!=StartProcessLink);
return STATUS_UNSUCCESSFUL;
}
////////////////////////////////ValidateHwnd寻址//////////////////////
//////////////////////////传入参数是NtUserQueryWindow的地址
/////////////////////////这个地址在后面的shadow sdt hook中代码中会出现
ULONG GetValidateHwndAddr(const ULONG NtUserQueryWindow)
{
ULONG Addr=NtUserQueryWindow;
ULONG offset;
int calc=0;
while(calc<2) //第二个E8 CALL就是ValidateHwnd的地址
{
Addr++;
if(MmIsAddressValid((PVOID)Addr))
{
if(*(PBYTE)Addr==0xe8) calc++;
}
}
offset=*(ULONG*)(Addr+1);
if(offset) return (offset+Addr+5);
else return 0;
}
//////////////////////////////shadow sdt hook代码///////////////
void HookShadowSdt()
{
PEPROCESS Target=NULL;
NTSTATUS status;
KIRQL irql;
KSPIN_LOCK lock;
KAPC_STATE ApcState;
status=LookUpProcessPointerByName("csrss.exe",&Target);
if(NT_SUCCESS(status))
{
status=GetServiceTableShadowAddr(&KeServiceDescriptorTableShadow);
if(NT_SUCCESS(status))
{
status=ObReferenceObjectByPointer((PVOID)Target,
0,
*PsProcessType,
KernelMode);
if(NT_SUCCESS(status))
{
KeStackAttachProcess(Target,&ApcState);
KeInitializeSpinLock(&lock);
PPOFF();
KeAcquireSpinLock(&lock,&irql);
//这里加上对win32k.sys的修改,如sdt hook,inline hook
KeReleaseSpinLock(&lock,irql);
PPON();
KeUnstackDetachProcess(&ApcState);
ObDereferenceObject((PVOID)Target);
}
}
}
}
////////////////////////注解: LookUpProcessPointerByName是遍历链表得到EPROCESS指针, PPON ,PPOFF 分别是开关页保护
好了,就这些。希望你能成功hook 掉win32k!ValidateHwnd,然后共享下~ 谢了
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)