三。如何hook
似乎这个问题并不大,shadow ssdt和ssdt本质上都是1个地址表,最为简单的方法是把你的函数替换地址表的对应项,具体hook代码甚至可以完全照抄ssdt的,这里只说1下几个偶遇到的小问题
1。win32k.sys不是常在内存的,如果不是GUI线程,shadow ssdt地址无效
解决办法:
1。在driverdispatch中hokk
driverdispatch是位于执行driveriocontrol的线程上下文的
我们使用1个GUI线程去driveriocontrol
2。attachtoprocess
通常 我们使用cerss.exe
Copy code
HANDLE GetCsrPid()
{
HANDLE Process, hObject;
HANDLE CsrId = (HANDLE)0;
OBJECT_ATTRIBUTES obj;
CLIENT_ID cid;
UCHAR Buff[0x100];
POBJECT_NAME_INFORMATION ObjName = (PVOID)&Buff;
PSYSTEM_HANDLE_INFORMATION_EX Handles;
ULONG r;
Handles = GetInfoTable(SystemHandleInformation);
if (!Handles) return CsrId;
for (r = 0; r < Handles->NumberOfHandles; r++)
{
if (Handles->Information[r].ObjectTypeNumber == 21) //Port object
{
InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId;
cid.UniqueThread = 0;
if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid)))
{
if (NT_SUCCESS(ZwDuplicateObject(Process,
(HANDLE)Handles->Information[r].Handle,
NtCurrentProcess(),
&hObject,
0, 0, DUPLICATE_SAME_ACCESS)))
{
if (NT_SUCCESS(ZwQueryObject(hObject,
ObjectNameInformation,
ObjName,
0x100, NULL)))
{
if (ObjName->Name.Buffer &&
!wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20))
{
CsrId = (HANDLE)Handles->Information[r].ProcessId;
}
}
ZwClose(hObject);
}
ZwClose(Process);
}
}
}
ExFreePool(Handles);
return CsrId;
}
然后我们KeAttachProcess
Copy code
ntStatus = PsLookupProcessByProcessId(GetCsrPid(), &EProcess);
if (!NT_SUCCESS( ntStatus ))
{
DbgPrint("PsLookupProcessByProcessId()\n");
return ntStatus;
}
KeAttachProcess(EProcess);
3.使用MDL映射一块不分页内存,设置成可以写入
不分页内存 ExAllocatePool(NonPagedPool
即为不会被切换到pagefile的内存,是常驻在物理内存的,比较希缺,使用完毕以后记住释放掉
参考regmon的代码
Copy code
PVOID *
RegmonMapServiceTable(
SERVICE_HOOK_DESCRIPTOR **ServiceIsHooked
)
{
*ServiceIsHooked = (SERVICE_HOOK_DESCRIPTOR*)
ExAllocatePool(NonPagedPool, KeServiceDescriptorTable->TableSize);
if( *ServiceIsHooked )
{
RtlZeroMemory(*ServiceIsHooked, KeServiceDescriptorTable->TableSize);
KeServiceTableMdl = MmCreateMdl(0, KeServiceDescriptorTable->ServiceTable, KeServiceDescriptorTable->TableSize << 2);
if( KeServiceTableMdl )
{
MmBuildMdlForNonPagedPool(KeServiceTableMdl);
KeServiceTableMdl->MdlFlags |= 1;
return (PVOID*)MmMapLockedPages(KeServiceTableMdl, KernelMode);
}
}
return NULL;
};
看起来shadowssdt何hook本身并没有什么难度
只要正确定位了地址,hook起来和ssdt完全一样
unhook不在重复 完全抄ssdt的代码即可
四。checkhook
hook用的人多了 难免出现重复hook的情况 为了实现和别人的东西和平共处,最好hook之前做个检测
hook的方法是固定的,就那么2种 改地址表 或者inline hook,我们分别来对待
1。修改地址表的hook
这个对付起来几乎不用特别对待,只是你保存的OldFunc是其他的程序hook函数所在的地址,判断方法很简单,看看这个地址在不在win32k的模块里面,和平共处的办法是你的myfunc里面call别人的hook函数,当然 如果你不想要别人的hook了,直接搜索到原始地址call之也是可行的
另外说1下 在别人的函数里面搜索原始地址 用MmIsAddressValid+ismodulewin32k
可以判断(这个办法好像是在mj文章里面看到的 记不清了)
2。inlinehook
这个比较麻烦了 如果是修改前面5个字节还好,直接替换处理都可以不改变
麻烦是函数中间地方被hook,盲目修改可能直接BSOD了,这个需要1个反汇编引擎来帮助分析代码字节长度,海风大大的hooklib很不错 可以完成这个功能
五,简单说1下restore
Copy code
pWin32k = GetModuleHandle("win32k.sys");
SdtRVA = &KeServiceDescriptorTable->win32k.ServiceTable - pWin32k ;
w32kCopy = LoadPeFile("win32k.sys");
ProcessRelocs(w32kCopy, pWin32k);
memcpy(&KeServiceDescriptorTable->win32k.ServiceTable, w32kCopy + SdtRVA, SdtSize);
不过 其实可以不用ProcessRelocs处理
因为你可以使用lordpe查看1下 win32k.sys的默认基址就是系统加载的基址
可以不需要ProcessRelocs,不过为了更加方便和通用,这么做也可以的
休息去咯---