• HOOK技术之SSDT hook(x86/x64)


    x86 SSDT Hook

    32位下进行SSDT Hook比较简单,通过修改SSDT表中需要hook的系统服务为自己的函数,在自己的函数中进行过滤判断达到hook的目的。

    获取KeServiceDescriptorTable基地址

    要想进行ssdt hook,首先需要获得SSDT表的基地址。
    因为KeServiceDescriptorTable是ntoskrnl.exe导出的,所以我们可以直接在程序中声明导入符号得到KeServiceDescriptorTable的值。

    typedef struct ServiceDescriptorEntry {
    	unsigned int *ServiceTableBase;
    	unsigned int *ServiceCounterTableBase;
    	unsigned int NumberOfServices;
    	unsigned char *ParamTableBase;
    } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
    
    extern "C" __declspec(dllimport)  ServiceDescriptorTableEntry_t  KeServiceDescriptorTable;
    

    可以通过ntoskrnl.exe的EAT导出表得到KeServiceDescriptorTable的值。

    还可以通过搜索KeAddSystemServiceTable进行硬编码0xB883得到KeServiceDescriptorTable的值

    获取KeServiceDescriptorTableShadow基地址

    因为KiServiceDescriptorTableShadow并未被win32k.sys导出,所以只能通过硬编码搜索KeAddSystemServiceTable/KeRemoteSystemServiceTable得到

    基地址差法,一般KiServiceDescriptorTableShadow就在KiServiceDescriptorTable附近如果xp就是 KeServiceDescriptorTableShadow=KeServiceDescriptorTable-0×40。如果是win7:KeServiceDescriptorTableShadow=KeServiceDescriptorTable+0×40;

    注意KeServiceDescriptorTableShadow表中包含了KeServiceDescriptorTable表的内容

    x64 SSDT Hook

    HOOK思路

    因为x64位中ssdt表是加密的,ssdt中的每一项占4个字节但并不是对应的系统服务的地址,因为x64中地址为64位而ssdt每一项只有4个字节32位所以无法直接存放服务的地址。其实际存储的4个字节的前28位表示的是对应的系统服务相对于SSDT表基地址的偏移,而后4位如果对应的服务的参数个数小于4则其值为0,不小于4则为参数个数减去4。所以我们在ssdt hook时向ssdt表项中填入的函数得在ntoskrnl.exe模块中,原因是因为函数到SSDT表基地址的偏移大小小于4个字节。所以我们选取一个ntoskrnl.exe中很少使用的函数KeBugCheckEx作为中转函数,将需要hook的ssdt项的改为KeBugCheckEx函数,然后在inlinehook KeBugCheck函数,jmp到我们的函数中进行过滤。

    PatchGard

    64系统增加了内核哨兵机制(PatchGard),一旦发现内核关键代码被篡改就会直接蓝屏。所以在64位系统上进行SSDT Hook需要绕过PatchGard。

    获取KeServiceDescriptorTable和KeServiceDescriptorTableShadow基地址

    64位系统调用过程为 syscall --》nt!KiSystemCall64--》nt!KiSystemServiceStart--》nt!KiSystemServiceRepeat--》call r10调用对应的系统服务。

    我们可以通过获取nt!KiSystemCall64函数的地址,然后找到nt!KiSystemServiceRepeat函数通过硬编码得到KeServiceDescriptorTable和KeServiceDescriptorTableShadow的基地址。因为MSR寄存器的0xC0000082被设置为nt!KiSystemCall64函数的地址,所以我们可以通过读取MSR寄存器得到此函数地址。

    ULONGLONG MyGetKeServiceDescriptorTable64()
    {
    	PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);
    	PUCHAR EndSearchAddress = StartSearchAddress + 0x500;
    	PUCHAR i = NULL;
    	UCHAR b1 = 0, b2 = 0, b3 = 0;
    	ULONG templong = 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) //4c8d15
    			{
    				memcpy(&templong, i + 3, 4);
    				addr = (ULONGLONG)templong + (ULONGLONG)i + 7;
    				return addr;
    			}
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    js常用工具函数
    vue-cli跨域问题解决
    charles抓包404问题(左侧不显示配置)
    vuex存储与本地储存(localstorage、sessionstorage)的区别(笔记)
    借助axios的拦截器实现Vue.js中登陆状态校验的思路(笔记)
    cornerstone使用注意点
    本地仓库连接远程仓库,git本地新建项目上传到远程git仓库上正确流程
    做一个不那么差的程序员
    解决 php Call to undefined function shm_attach()
    Redis 常用的数据结构
  • 原文地址:https://www.cnblogs.com/revercc/p/14701592.html
Copyright © 2020-2023  润新知