以下内容参考黑客防线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\n", addr));
                return addr;
            } 
        }
    }
    KdPrint(("find ssdt error\n"));
    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!\n", i,\
                ((ULONGLONG)dwTemp + (ULONGLONG)ServiceTableBase) & 0xffffffff0fffffff);

        }
        else
        {
            DbgPrint("ServiceTableBase is fault!\n");
            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!\n");
        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!!!\n");
    if (!NT_SUCCESS(status))
    {
        DbgPrint("ObReferenceObjectByHandle failed !!!\n");
        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[] = "\x48\xB8\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xE0";
    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\n", real_NtTerminateProcess);
    //DbgPrint("search real_NtTerminateProcess is %p\n", 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\n", (ULONGLONG)KeBugCheckEx);
    DbgPrint("NtTerminateProcess: %p\n", GetSSDTFuncAddrById(NtTerminateProcessId));


}
void unHookSSDT64()
{
    KIRQL irql;
    ULONGLONG dwtemp = 0;
    PULONG ServiceTableBase = 0;
    DbgPrint("enter unHookSSDT64\n ");
    ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
    irql = WPOFFx64();
    ServiceTableBase[NtTerminateProcessId] = real_NtTerminateProcessOffset;
    WPONx64(irql);
    DbgPrint("KeBugCheckEx: %p\n", (ULONGLONG)KeBugCheckEx);
    DbgPrint("NtTerminateProcess: %p\n", GetSSDTFuncAddrById(NtTerminateProcessId));
}