zoukankan      html  css  js  c++  java
  • win 64 Shadow ssdt hook

    以下参考黑客防线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
    ", pid);
        if (pid == MyProcessId && PsGetCurrentProcessId() != (HANDLE)MyProcessId)
        {
            DbgPrint("Do not fuck with me!
    ");
            return 0;
        }
        else
        {
            DbgPrint("OriNtUserPostMessage called!
    ");
            return NtUserPostMessage(hWnd, Msg, wParam, lParam);
        }
    }
    
    VOID UNHOOK_SSSDT()
    {
        ModifySSSDT(IndexOfNtUserPostMessage, (ULONG64)NtUserPostMessage);
        DbgPrint("UNHOOK_SSSDT OK!
    ");
    }
    
    VOID HOOK_SSSDT()
    {
        KIRQL irql;
        ULONG64 myfun;
        UCHAR jmp_code[] = "xFFx25x00x00x00x00x90x90x90x90x90x90x90x90";
    
        //代理函数地址
        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!
    ");
    }
    
    VOID FuckFunc()
    {
        KIRQL irql;
        UCHAR fuckcode[] = "x48x33xC0xC3x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90";
        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
    ", KeServiceDescriptorTableShadow);
        DbgPrint("pWin32k->ServiceTableBase is %p
    ", 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
    ", addr));
                    return addr;
                }
            }
        }
        KdPrint(("find ssdt error
    "));
        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!
    "));
        //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
    ", NtUserQueryWindow);
            DbgPrint("NtUserPostMessage :%p
    ", NtUserPostMessage);
            DbgPrint("AddressNtUserWindowFromPhysicalPoint :%p
    ", 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
    "));
    
    
        //KeServiceDescriptorTable = GetKeSeviceDescriptorTable64();//1
        RtlInitUnicodeString(&DeviceName, DEVNAME);
        RtlInitUnicodeString(&DosDeviceName, LINKNAME);
        //througnAllServiceFuncAddr();
        //hookSSDT64();
        //初始化
        //initAll();
    //    KeServiceDescriptorTableShadow = GetKeSeviceDescriptorTableShadow64(); //1
        //DbgPrint("param is %d
    ", IndexOfNtUserPostMessage);
        //NtUserPostMessage = GetSSSDTFuncCurAddr64(IndexOfNtUserPostMessage);//备份被写入函数地址
        //DbgPrint("NtUserPostMessage is %p
    ", NtUserPostMessage);
        //NtUserQueryWindow = GetSSSDTFuncCurAddr64(IndexOfNtUserQueryWindow);
        //DbgPrint("NtUserPostMessage is %p
    ", 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;
    }
  • 相关阅读:
    常用Dos 命令
    Expect: 100continue
    Sql Server 文件和文件组体系结构
    Build Action
    regasm.exe 程序集注册工具
    获得user account的SID,GUID
    sp_change_users_login
    Regsvr32
    ASP.NET IIS 注册工具 (Aspnet_regiis.exe)
    随机生成300道四则运算
  • 原文地址:https://www.cnblogs.com/freesec/p/7622860.html
Copyright © 2011-2022 走看看