三。如何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,不过为了更加方便和通用,这么做也可以的 休息去咯--- |
shadow ssdt学习笔记(二)
最新推荐文章于 2021-11-20 16:34:58 发布