以下参考黑客防线2012合订本 339页
//下午调代码
搞了这个一天,总是蓝屏,不断检查代码,后来发现了很怪的现象.
自己写的代码不能读取shadow ssdt的偏移内容,但是通过和调试作者的代码输出发现地址确实是一模一样的,但是自己的读不出来,而作者的能
读出来,当直接使用windbg调试时也读不出来. 后来将作者的代码完全复制过来,发现能读取了, ,但是又找不到原因, 只能等以后再看看了.
//晚上调代码
晚上时还是想解决调用后来仔细再看看代码发现自己的代码调用sssdt hook时是在DriverEntry中的, 而shadow ssdt中的函数全是在有窗口程序时
调用时才有意义的. 而作者的代码正是通过应用层mfc程序通过发送io控制码通知驱动进行hook的,这时调用hook的代码的当前进程实际上是mfc程序
,是有窗口的. 而DriverEntry是由system调用的,没有窗口自然蓝屏.
测试如下:
想通了之后修改代码如下.
//hookSSSDT.h #include <ntddk.h> #pragma intrinsic(__readmsr) /* 流程: 1.通过GetKeServiceDescriptorTableShadow64 获取sssdt基址 2.通过index获取sssdt函数地址 ,通过GetSSSDTFuncCurAddr64函数实现 3.写好自己的假的对应的函数,并将跳板函数前若干字节修改为跳转到假函数地址 4.获得跳板函数的sssdt偏移地址 并将其写入对应的sssdt位置,这里已实现hook 通过将原来的sssdt函数偏移写回去即可 */ typedef struct _SYSTEM_SERVICE_TABLE { PVOID ServiceTableBase; PVOID ServiceCounterTableBase; ULONGLONG NumberOfServices; PVOID ParamTableBase; } SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE; extern PSYSTEM_SERVICE_TABLE KeServiceDescriptorTableShadow; typedef ULONG64(*NTUSERQUERYWINDOW) ( IN HWND WindowHandle, IN ULONG64 TypeInformation ); typedef ULONG64(*NTUSERPOSTMESSAGE) ( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ); //hook sssdt的变量 PSYSTEM_SERVICE_TABLE KeServiceDescriptorTableShadow = NULL; ULONG64 ul64W32pServiceTable = 0; ULONG64 IndexOfNtUserPostMessage = 0x100f; ULONG64 IndexOfNtUserQueryWindow = 0x1010; NTUSERQUERYWINDOW NtUserQueryWindow = NULL; NTUSERPOSTMESSAGE NtUserPostMessage = NULL; ULONG64 MyProcessId = 0; //ULONG64 Win32kBase = 0; ULONG64 IndexOfNtUserWindowFromPhysicalPoint = 0x1337; ULONG64 AddressNtUserWindowFromPhysicalPoint = 0; //声明后就能用 NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation ( IN ULONG SystemInformationClass, OUT PVOID SystemInformation, IN ULONG Length, OUT PULONG ReturnLength ); ULONG64 FUCKNtUserPostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); VOID UNHOOK_SSSDT(); VOID HOOK_SSSDT(); VOID FuckFunc(); ULONGLONG GetSSSDTFuncCurAddr64(ULONG64 Index); VOID ModifySSSDT(ULONG64 Index, ULONG64 Address); ULONGLONG GetKeSeviceDescriptorTableShadow64(); KIRQL WPOFFx64() { KIRQL irql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); cr0 &= 0xfffffffffffeffff; __writecr0(cr0); _disable(); return irql; } void WPONx64(KIRQL irql) { UINT64 cr0 = __readcr0(); cr0 |= 0x10000; _enable(); __writecr0(cr0); KeLowerIrql(irql); } ULONG64 FUCKNtUserPostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { ULONG pid = NtUserQueryWindow(hWnd, 0); DbgPrint("called pid is %d\n", pid); if (pid == MyProcessId && PsGetCurrentProcessId() != (HANDLE)MyProcessId) { DbgPrint("Do not fuck with me!\n"); return 0; } else { DbgPrint("OriNtUserPostMessage called!\n"); return NtUserPostMessage(hWnd, Msg, wParam, lParam); } } VOID UNHOOK_SSSDT() { ModifySSSDT(IndexOfNtUserPostMessage, (ULONG64)NtUserPostMessage); DbgPrint("UNHOOK_SSSDT OK!\n"); } VOID HOOK_SSSDT() { KIRQL irql; ULONG64 myfun; UCHAR jmp_code[] = "\xFF\x25\x00\x00\x00\x00\x90\x90\x90\x90\x90\x90\x90\x90"; //代理函数地址 myfun = (ULONGLONG)FUCKNtUserPostMessage; //填充 shellcode memcpy(jmp_code + 6, &myfun, 8); //x先写入 准备的shellcode FuckFunc(); irql = WPOFFx64(); //再次写入跳转指令 memcpy((PVOID)(AddressNtUserWindowFromPhysicalPoint + 4), jmp_code, 14); WPONx64(irql); //修改记录原始地址的地方 ModifySSSDT(IndexOfNtUserPostMessage, AddressNtUserWindowFromPhysicalPoint + 4); DbgPrint("HOOK_SSSDT OK!\n"); } VOID FuckFunc() { KIRQL irql; UCHAR fuckcode[] = "\x48\x33\xC0\xC3\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; irql = WPOFFx64(); memcpy((PVOID)AddressNtUserWindowFromPhysicalPoint, fuckcode, 23); WPONx64(irql); } ULONGLONG GetSSSDTFuncCurAddr64(ULONG64 Index) { ULONGLONG W32pServiceTable = 0, qwTemp = 0; LONG dwTemp = 0; PSYSTEM_SERVICE_TABLE pWin32k; //DbgBreakPoint(); pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE)); DbgPrint("(ULONG64)KeServiceDescriptorTableShadow is %p\n", KeServiceDescriptorTableShadow); DbgPrint("pWin32k->ServiceTableBase is %p\n", pWin32k->ServiceTableBase); W32pServiceTable = (ULONGLONG)(pWin32k->ServiceTableBase); ul64W32pServiceTable = W32pServiceTable; qwTemp = W32pServiceTable + 4 * (Index - 0x1000); //这里是获得偏移地址的位置,要HOOK的话修改这里即可 dwTemp = *(PLONG)qwTemp; dwTemp = dwTemp >> 4; qwTemp = W32pServiceTable + (LONG64)dwTemp; return qwTemp; } VOID ModifySSSDT(ULONG64 Index, ULONG64 Address) { ULONGLONG W32pServiceTable = 0, qwTemp = 0; LONG dwTemp = 0; PSYSTEM_SERVICE_TABLE pWin32k; KIRQL irql; pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE)); //4*8 W32pServiceTable = (ULONGLONG)(pWin32k->ServiceTableBase); qwTemp = W32pServiceTable + 4 * (Index - 0x1000); //获取要被写入的地址 dwTemp = (LONG)(Address - W32pServiceTable); dwTemp = dwTemp << 4; //计算将写入目标位置的内容 DbgPrint("*(PLONG)qwTemp: %x,dwTemp: %x",*(PLONG)qwTemp,dwTemp); irql=WPOFFx64(); *(PLONG)qwTemp = dwTemp; WPONx64(irql); } ULONGLONG GetKeSeviceDescriptorTableShadow64() { PUCHAR startSearchAddress = (PUCHAR)__readmsr(0xC0000082); PUCHAR endSearchAddress = startSearchAddress + 0x500; PUCHAR i = 0; UCHAR b1 = 0, b2 = 0, b3 = 0; ULONG temp = 0; ULONGLONG addr = 0; for (i = startSearchAddress; i < endSearchAddress; i++) { if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2)) { b1 = *i; b2 = *(i + 1); b3 = *(i + 2); if (b1 == 0x4c && b2 == 0x8d && b3 == 0x1d) { memcpy(&temp, i + 3, 4); addr = (ULONGLONG)temp + (ULONGLONG)i + 7;//加上指令长度 KdPrint(("find ssdt is %p\n", addr)); return addr; } } } KdPrint(("find ssdt error\n")); return 0; }
//hs64.c #include "header.h" #include "hookSSSDT.h" /* ssdt hook的一个流程: 1.先调用GetKeSeviceDescriptorTable64给KeServiceDescriptorTable全局变量赋值,也就是找到 ssdt 2. 调用GetSSDTFuncAddrById得到目标函数地址并保存到全局变量real_NtTerminateProcess 3. 修改掉Fuck_KeBugCheckEx前12字节作为跳板 4. 得到目标函数的偏移并保存到全局变量real_NtTerminateProcessOffset 5. 计算KeBugCheckEx 函数的偏移并写入到 ssdt表中 还原hook: 1.直接将保存的目标函数偏移写入到ssdt表中即可 这里无需还原KeBugCheckEx 函数,因为这里本来就不会执行到 */ //DWORD isSHooked; VOID DriverUnload(PDRIVER_OBJECT DriverObject) { UNICODE_STRING DeviceName; UNICODE_STRING DosDeviceName; //删除符号链接 RtlInitUnicodeString(&DosDeviceName, LINKNAME); IoDeleteSymbolicLink(&DosDeviceName); if (DriverObject->DeviceObject != NULL) IoDeleteDevice(DriverObject->DeviceObject); KdPrint(("DriverUnload!\r\n")); //unHookSSDT64(); } NTSTATUS IOControl(PDEVICE_OBJECT DeviceObject, PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; ULONG uLen = 4; PIO_STACK_LOCATION ios = IoGetCurrentIrpStackLocation(pIrp); ULONG ccode = ios->Parameters.DeviceIoControl.IoControlCode; char result = 0; switch (ccode) { case IOCTL_HOOK: MyProcessId = PsGetCurrentProcessId(); NtUserQueryWindow = (NTUSERQUERYWINDOW)GetSSSDTFuncCurAddr64(IndexOfNtUserQueryWindow); DbgPrint("NtUserQueryWindow: %llx", (ULONG64)NtUserQueryWindow); NtUserPostMessage = (NTUSERPOSTMESSAGE)GetSSSDTFuncCurAddr64(IndexOfNtUserPostMessage); DbgPrint("NtUserPostMessage: %llx", (ULONG64)NtUserPostMessage); AddressNtUserWindowFromPhysicalPoint = GetSSSDTFuncCurAddr64(IndexOfNtUserWindowFromPhysicalPoint); DbgPrint("AddressNtUserWindowFromPhysicalPoint: %llx", (ULONG64)AddressNtUserWindowFromPhysicalPoint); DbgPrint("NtUserQueryWindow :%p\n", NtUserQueryWindow); DbgPrint("NtUserPostMessage :%p\n", NtUserPostMessage); DbgPrint("AddressNtUserWindowFromPhysicalPoint :%p\n", AddressNtUserWindowFromPhysicalPoint); HOOK_SSSDT(); //isSHooked = 1; break; case IOCTL_UNHOOK: UNHOOK_SSSDT(); //isSHooked = 0; break; default: break; } pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = uLen; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return pIrp->IoStatus.Status; } NTSTATUS IODispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING theRegistryPath) { UNICODE_STRING DeviceName; UNICODE_STRING DosDeviceName; NTSTATUS status; PVOID64 pvoid_driver_object; ULONG_PTR ul_driver_object; PDEVICE_OBJECT DriverDeviceObject; KdPrint(("Hello World WinX64\r\n")); //KeServiceDescriptorTable = GetKeSeviceDescriptorTable64();//1 RtlInitUnicodeString(&DeviceName, DEVNAME); RtlInitUnicodeString(&DosDeviceName, LINKNAME); //througnAllServiceFuncAddr(); //hookSSDT64(); //初始化 //initAll(); // KeServiceDescriptorTableShadow = GetKeSeviceDescriptorTableShadow64(); //1 //DbgPrint("param is %d\n", IndexOfNtUserPostMessage); //NtUserPostMessage = GetSSSDTFuncCurAddr64(IndexOfNtUserPostMessage);//备份被写入函数地址 //DbgPrint("NtUserPostMessage is %p\n", NtUserPostMessage); //NtUserQueryWindow = GetSSSDTFuncCurAddr64(IndexOfNtUserQueryWindow); //DbgPrint("NtUserPostMessage is %p\n", NtUserQueryWindow); //AddressNtUserWindowFromPhysicalPoint = GetSSSDTFuncCurAddr64(IndexOfNtUserWindowFromPhysicalPoint); KeServiceDescriptorTableShadow = (PSYSTEM_SERVICE_TABLE)GetKeSeviceDescriptorTableShadow64(); status = IoCreateDevice( DriverObject, // ptr to caller object 0, // extension device allocated byte number &DeviceName, // device name FILE_DEVICE_UNKNOWN, 0, // no special caracteristics FALSE, // we can open many handles in same time &DriverDeviceObject); // [OUT] ptr to the created object if (!NT_SUCCESS(status)) { return STATUS_NO_SUCH_DEVICE; } status = IoCreateSymbolicLink(&DosDeviceName, &DeviceName); if (!NT_SUCCESS(status)) { IoDeleteDevice(DriverDeviceObject); return STATUS_NO_SUCH_DEVICE; } DriverObject->DriverUnload = DriverUnload; DriverObject->MajorFunction[IRP_MJ_CREATE] = IODispatch; DriverObject->MajorFunction[IRP_MJ_CLOSE] = IODispatch; DriverObject->MajorFunction[IRP_MJ_READ] = IODispatch; DriverObject->MajorFunction[IRP_MJ_WRITE] = IODispatch; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOControl; return STATUS_SUCCESS; }