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