以下參考黑客防線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; }