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\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));
}

 

转载于:https://www.cnblogs.com/freesec/p/7617752.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vt hook ssdt是一种技术,用于在操作系统内核中拦截和修改系统服务调用。通过Vt(Virtualization Technology)技术,可以在操作系统运行时对系统服务进行动态修改,从而实现对系统行为的控制和修改。 以下是一个Vt hook ssdt的示例代码: ```c #include <ntddk.h> ULONG_PTR OriginalServiceAddress = 0; NTSTATUS HookServiceCall(IN PUNICODE_STRING ServiceName, IN ULONG_PTR NewServiceAddress) { NTSTATUS status = STATUS_SUCCESS; ULONG_PTR serviceAddress = 0; // 获取系统服务地址 status = ZwQuerySystemInformation(SystemModuleInformation, NULL, 0, &serviceAddress); if (status != STATUS_INFO_LENGTH_MISMATCH) { return status; } // 遍历系统服务表 PSYSTEM_MODULE_INFORMATION pModuleInfo = (PSYSTEM_MODULE_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, serviceAddress, 'hook'); if (pModuleInfo == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } status = ZwQuerySystemInformation(SystemModuleInformation, pModuleInfo, serviceAddress, NULL); if (!NT_SUCCESS(status)) { ExFreePoolWithTag(pModuleInfo, 'hook'); return status; } for (ULONG i = 0; i < pModuleInfo->NumberOfModules; i++) { PRTL_PROCESS_MODULES pModule = &pModuleInfo->Modules[i]; // 找到ntoskrnl.exe模块 if (wcsstr(pModule->FullPathName, L"ntoskrnl.exe") != NULL) { // 计算SSDT地址 ULONG_PTR ssdtAddress = (ULONG_PTR)pModule->ImageBase + pModule->OffsetToFileName; // 保存原始的系统服务地址 OriginalServiceAddress = *(ULONG_PTR*)ssdtAddress; // 修改系统服务地址为新的地址 *(ULONG_PTR*)ssdtAddress = NewServiceAddress; break; } } ExFreePoolWithTag(pModuleInfo, 'hook'); return status; } NTSTATUS UnhookServiceCall() { if (OriginalServiceAddress != 0) { // 恢复原始的系统服务地址 *(ULONG_PTR*)ssdtAddress = OriginalServiceAddress; OriginalServiceAddress = 0; } return STATUS_SUCCESS; } ``` 以上代码是一个简单的Vt hook ssdt的示例,通过调用`HookServiceCall`函数可以将指定的系统服务地址替换为新的地址,通过调用`UnhookServiceCall`函数可以恢复原始的系统服务地址。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值