• win 64 SSDT HOOK


    以下内容参考黑客防线2012合订本第294页

    其实没什么好说的,直接上代码:

    ssdt的结构,和win32差不多,但是要注意这里的指针类型不能用ULONG替代,如果要非要替代应该用ULONGLONG,原因就不说了.

    //SSDT的结构
    typedef struct _SystemServiceDescriptorTable
    {
        PVOID    ServiceTableBase;
        PVOID    ServiceCounterTableBase;
        ULONGLONG    NumberOfService;
        PVOID    ParamTableBase;
    }SystemServiceTable, *PSystemServiceTable;
    PSystemServiceTable KeServiceDescriptorTable;

    获取上面的结构的地址的代码;

    ULONGLONG GetKeSeviceDescriptorTable64()
    {
        /*
            思路是读取0xC0000082 这个寄存器的值是KiSystemCall64函数地址,然后通过特征码搜索即可
            ssdt特征码是 0x4c8d15 接着就是ssdt的地址值的偏移了,然后通过公式:
            真实地址 = 当前地址+当前指令长度+偏移 得到ssdt地址
            找shadow ssdt地址类似
    
        */
        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 == 0x15)
                {
                    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;
    }

    遍历所有Native API 地址:

    void througnAllServiceFuncAddr()
    {
        ULONG dwTemp = 0;
        PULONG ServiceTableBase = 0;
        ULONG i = 0;
        for ( i = 0; i < KeServiceDescriptorTable->NumberOfService; i++)
        {
            if (MmIsAddressValid(KeServiceDescriptorTable->ServiceTableBase))
            {
                ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
                dwTemp = ServiceTableBase[i];
                dwTemp = dwTemp >> 4;
                DbgPrint("the %dth func addr is %p!
    ", i,
                    ((ULONGLONG)dwTemp + (ULONGLONG)ServiceTableBase) & 0xffffffff0fffffff);
    
            }
            else
            {
                DbgPrint("ServiceTableBase is fault!
    ");
                return 0;
            }
        }
    }

    测试结果:

    windbg查看的结果:

    以ZwOpenProcess为例:

    ida中发现他的id是0x23 也就是 35 对应 测试结果是 fffff8000419b038

    windbg结果:

     测试无误.

    但是如果想hook是比win32麻烦很多的, 因为ServiceTableBase这个数组里面的元素只有4字节,在win32下自然能够遍历整个内存空间,
    但是在win64下,内存空间有16T(限制为44bit寻址) 完全可以一个驱动占一个4GB空间,还有大量空间用不到. 所以直接修改这个index根本

    够不着我们的驱动函数地址. 所以可以通过先跳转到一个跳板函数,这个跳板函数的地址在系统nt模块中,也就是在4GB范围内,然后修改那个函数

    的首地址为jmp 我们的驱动hook函数 就能实现hook了.

    比如使用KeBugCheckEx这个函数, 这个函数的功能是在系统挂掉的时候才会调用的函数, 因此可以作为跳板,当然如果能找到其他闲置的

    内存空间也可以作为跳板.

    整理一下思路,下面贴代码. 

    ssdt hook的一个流程:
    1.先调用GetKeSeviceDescriptorTable64给KeServiceDescriptorTable全局变量赋值,也就是找到
    ssdt
    2. 调用GetSSDTFuncAddrById得到目标函数地址并保存到全局变量real_NtTerminateProcess
    3. 在函数Fuck_KeBugCheckEx中修改掉KeBugCheckEx代码前12字节作为跳板
    4. 得到目标函数的偏移并保存到全局变量real_NtTerminateProcessOffset
    5. 计算KeBugCheckEx 函数的偏移并写入到 ssdt表中

    还原hook:
    1.直接将保存的目标函数偏移写入到ssdt表中即可
    这里无需还原KeBugCheckEx 函数,因为这里本来就不会执行到,如果执行到了也蓝屏死机了

    KIRQL WPOFFx64() //类似win32关闭内存写保护
    {
        KIRQL irql = KeRaiseIrqlToDpcLevel();
        UINT64 cr0 = __readcr0();
        cr0 &= 0xfffffffffffeffff;
        __writecr0(cr0);
        _disable();
        return irql;
    }
    void WPONx64(KIRQL irql)//类似win32开启内存写保护
    {
        UINT64 cr0 = __readcr0();
        cr0 |= 0x10000;
        _enable();
        __writecr0(cr0);
        KeLowerIrql(irql);
    }
    ULONGLONG GetSSDTFuncAddrById(ULONG id)
    {
        ULONG dwTemp = 0;
        PULONG ServiceTableBase = 0;
        if (MmIsAddressValid(KeServiceDescriptorTable->ServiceTableBase))
        {
            ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
            dwTemp = ServiceTableBase[id];
            dwTemp = dwTemp >> 4;
            //return ((ULONGLONG)dwTemp + (ULONGLONG)ServiceTableBase) & 0xffffffff0fffffff;
            return ((ULONGLONG)dwTemp + (ULONGLONG)ServiceTableBase);
        }
        else
        {
            DbgPrint("ServiceTableBase is fault!
    ");
            return 0;
        }
        
    }
    
    ULONG GetOffsetBySSDTFuncAddress(ULONGLONG funcAddr)
    {
        ULONG dwtemp = 0;
        PULONG ServiceTableBase = 0;
        ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
        dwtemp = (ULONG)(funcAddr - (ULONGLONG)ServiceTableBase);
        return dwtemp << 4;
    }
    
    NTSTATUS __fastcall Fuck_NtTerminateProcess(
        IN HANDLE  ProcessHandle,
        IN NTSTATUS  ExitStatus
    )
    {
        PEPROCESS pe;
        NTSTATUS status;
        status = ObReferenceObjectByHandle(ProcessHandle, 0, *PsProcessType, KernelMode, &pe, 0);
        DbgPrint("enter Fuck_NtTerminateProcess!!!
    ");
        if (!NT_SUCCESS(status))
        {
            DbgPrint("ObReferenceObjectByHandle failed !!!
    ");
            return real_NtTerminateProcess(ProcessHandle, ExitStatus);
        }
        if (!_stricmp(PsGetProcessImageFileName(pe),"calc.exe"))
        {
            return STATUS_ACCESS_DENIED;
        }
    
        return real_NtTerminateProcess(ProcessHandle, ExitStatus);
    }
    
    
    void Fuck_KeBugCheckEx()
    {
        KIRQL irql;
        ULONGLONG myFunc = (ULONGLONG)Fuck_NtTerminateProcess;
        UCHAR jmp_code[] = "x48xB8xFFxFFxFFxFFxFFxFFxFFx00xFFxE0";
        memcpy(jmp_code + 2, &myFunc, 8);
        irql = WPOFFx64();
        memset(KeBugCheckEx, 0x90, 15);//填充15个nop
        memcpy(KeBugCheckEx, jmp_code, 12);
        WPONx64(irql);
    
    }
    
    void hookSSDT64()
    {
        ULONGLONG dwtemp = 0;
        PULONG ServiceTableBase = 0;
        KIRQL irql;
        //UNICODE_STRING funcName;
        //RtlInitUnicodeString(&funcName, L"NtTerminateProcess");
        real_NtTerminateProcess = GetSSDTFuncAddrById(NtTerminateProcessId); //2
        DbgPrint("real_NtTerminateProcess is %p
    ", real_NtTerminateProcess);
        //DbgPrint("search real_NtTerminateProcess is %p
    ", MmGetSystemRoutineAddress(&funcName));
        Fuck_KeBugCheckEx();  //3
        ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
        real_NtTerminateProcessOffset = ServiceTableBase[NtTerminateProcessId];//4
    
        //进行hook 5
        irql = WPOFFx64();
        ServiceTableBase[NtTerminateProcessId] = GetOffsetBySSDTFuncAddress((ULONGLONG)KeBugCheckEx);
        WPONx64(irql);
        DbgPrint("KeBugCheckEx: %p
    ", (ULONGLONG)KeBugCheckEx);
        DbgPrint("NtTerminateProcess: %p
    ", GetSSDTFuncAddrById(NtTerminateProcessId));
    
    
    }
    void unHookSSDT64()
    {
        KIRQL irql;
        ULONGLONG dwtemp = 0;
        PULONG ServiceTableBase = 0;
        DbgPrint("enter unHookSSDT64
     ");
        ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
        irql = WPOFFx64();
        ServiceTableBase[NtTerminateProcessId] = real_NtTerminateProcessOffset;
        WPONx64(irql);
        DbgPrint("KeBugCheckEx: %p
    ", (ULONGLONG)KeBugCheckEx);
        DbgPrint("NtTerminateProcess: %p
    ", GetSSDTFuncAddrById(NtTerminateProcessId));
    }
  • 相关阅读:
    jquery 使用方法<转载>
    mybatis 使用resultMap实现数据库的操作
    myBatis 实现用户表增删查改操作<方法2 加入接口>(最终版)
    myBatis 实现用户表增删查改操作<方法1 没有使用接口的>(最终版)
    myBatis 实现用户表增操作(复杂型)
    MyBatis 用户表记录数查询
    SpringMVC 返回JSON数据
    springmvc中@PathVariable和@RequestParam的区别(百度收集)
    spring mvc文件上传和下载
    python 网络编程
  • 原文地址:https://www.cnblogs.com/freesec/p/7617752.html
Copyright © 2020-2023  润新知