【SSDT】SSDT hook技术

SSDT:

SSDT全称: System Services Descriptor Table 即系统服务描述表

这个表将Ring3的Win32 API 和 Ring0 的内核 API联系起来。通过修改此表的函数地址可以对常用Windows函数及API进行Hook,从而实现对一些关心的系统动作进行过滤、监控等目的。

在NT4.0 以上的Windpws 操作系统中,默认存在两个系统服务描述表,两个调度表对应两类不同的系统服务。
分别为KeServiceDescriptorTableKeServiceDescriptorTableShadow 其中KeServiceDescriptorTable 主要处理来自Ring3层Kernel32.dll中的系统调用。
KeServiceDescriptorTableShadow则主要处理来自User32.dll和GDI32.dll中的系统调用。

系统服务分发函数KiSystemService

场景:

例如进程保护(驱动)
端口隐藏
文件隐藏等

系统从Ring3 到 Ring0 的执行过程:
在这里插入图片描述
Hook前准备:

要Hook SSDT表,首选需要这个表是可写的,但是在XP之后的系统都是只读的,有三种方式修改内存保护机制。

  1. 更改注册表:
恢复页面保护:HKLM\SYSTEM\CurrentControlset\Control\Session Manger\Memory Management\EnforceWriteProtection=0
去掉页面保护:HKLM\SYSTEM\CurrentControlset\Control\Session Manger\Memory Management\DisablePagingExecutive=1
  1. 改变CR0寄存器的第1位
    Windows对内存的分配,采用分页管理。其中有个CR0寄存器:

在这里插入图片描述
其中第1位叫做保护属性位,控制着页的读或写属性。如果为1,则可以读/写/执行;如果为0,则只能读/执行。

SSDT,IDT(中断描述符表)的页属性在默认情况下只读,可执行,但不能写。

//设置为不可写
void DisableWrite()
{
    __try
    {
        _asm
        {
            mov eax, cr0 
            or  eax, 10000h 
            mov cr0, eax 
            sti 
        }
    }
    __except(1)
    {
        DbgPrint("DisableWrite执行失败!");
    }
}

// 设置为可写
void EnableWrite()
{
    __try
    {
        _asm
        {
            cli
            mov eax,cr0
            and eax,not 10000h //and eax,0FFFEFFFFh
            mov cr0,eax
        }
    }
    __except(1)
    {
        DbgPrint("EnableWrite执行失败!");
    }
}
  1. 通过Memory Descriptor List
    如何获取SSDT中的函数地址

①获取指定服务的索引号:SYSCALL_INDEX
②获取指定服务的当前地址:SYSCALL_FUNCTION

SSDT hook 流程:

在这里插入图片描述
使用SSDT hook 实现进程保护:

#include <ntifs.h>
 
//内核之SSDT-HOOK
//系统服务表
typedef struct _KSYSTEM_SERVICE_TABLE
{
    PULONG ServiceTableBase;       //函数地址表的首地址
    PULONG ServiceCounterTableBase;//函数表中每个函数被调用的次数
    ULONG  NumberOfService;        //服务函数的个数
    ULONG ParamTableBase;          //参数个数表首地址
}KSYSTEM_SERVICE_TABLE;
 
//服务描述符
typedef struct _KSERVICE_TABLE_DESCRIPTOR
{
    KSYSTEM_SERVICE_TABLE ntoskrnl;//ntoskrnl.exe的服务函数,SSDT
    KSYSTEM_SERVICE_TABLE win32k;  //win32k.sys的服务函数,ShadowSSDT
    KSYSTEM_SERVICE_TABLE notUsed1;//暂时没用1
    KSYSTEM_SERVICE_TABLE notUsed2;//暂时没用2
}KSERVICE_TABLE_DESCRIPTOR;
 
//定义HOOK的函数的类型
typedef NTSTATUS (NTAPI*FuZwOpenProcess)(
    _Out_ PHANDLE ProcessHandle,
    _In_ ACCESS_MASK DesiredAccess,
    _In_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID ClientId
);
 
//自写的函数声明
NTSTATUS NTAPI MyZwOpenProcess(
    _Out_ PHANDLE ProcessHandle,
    _In_ ACCESS_MASK DesiredAccess,
    _In_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID ClientId
);
 
//记录系统的该函数
FuZwOpenProcess g_OldZwOpenProcess;
//服务描述符表指针
KSERVICE_TABLE_DESCRIPTOR* g_pServiceTable = NULL;
//要保护进程的ID
ULONG g_Pid = 9527;
 
//安装钩子
void InstallHook();
//卸载钩子
void UninstallHook();
//关闭页写入保护
void ShutPageProtect();
//开启页写入保护
void OpenPageProtect();
 
//卸载驱动
void OutLoad(DRIVER_OBJECT* obj);
 
 
 
***驱动入口主函数***/
NTSTATUS DriverEntry(DRIVER_OBJECT* driver, UNICODE_STRING* path)
{
    path;
    KdPrint(("驱动启动成功!\n"));
    //DbgBreakPoint();
 
    //安装钩子
    InstallHook();
 
    driver->DriverUnload = OutLoad;
    return STATUS_SUCCESS;
}
 
//卸载驱动
void OutLoad(DRIVER_OBJECT* obj)
{
    obj;
    //卸载钩子
    UninstallHook();
}
 
//安装钩子
void InstallHook()
{
    //1.获取KTHREAD
    PETHREAD pNowThread = PsGetCurrentThread();
    //2.获取ServiceTable表
    g_pServiceTable = (KSERVICE_TABLE_DESCRIPTOR*)
        (*(ULONG*)((ULONG)pNowThread + 0xbc));
    //3.保存旧的函数
    g_OldZwOpenProcess = (FuZwOpenProcess)
        g_pServiceTable->ntoskrnl.ServiceTableBase[0xbe];
    //4.关闭页只读保护
    ShutPageProtect();
    //5.写入自己的函数到SSDT表内
    g_pServiceTable->ntoskrnl.ServiceTableBase[0xbe]
        = (ULONG)MyZwOpenProcess;
    //6.开启页只读保护
    OpenPageProtect();
}
 
//卸载钩子
void UninstallHook()
{
    //1.关闭页只读保护
    ShutPageProtect();
    //2.写入原来的函数到SSDT表内
    g_pServiceTable->ntoskrnl.ServiceTableBase[0xbe]
        = (ULONG)g_OldZwOpenProcess;
    //3.开启页只读保护
    OpenPageProtect();
}
 
//关闭页只读保护
void _declspec(naked) ShutPageProtect()
{
    __asm
    {
        push eax;
        mov eax, cr0;
        and eax, ~0x10000;
        mov cr0, eax;
        pop eax;
        ret;
    }
}
 
//开启页只读保护
void _declspec(naked) OpenPageProtect()
{
    __asm
    {
        push eax;
        mov eax, cr0;
        or eax, 0x10000;
        mov cr0, eax;
        pop eax;
        ret;
    }
}
 
//自写的函数
NTSTATUS NTAPI MyZwOpenProcess(
    _Out_ PHANDLE ProcessHandle,
    _In_ ACCESS_MASK DesiredAccess,
    _In_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID ClientId
)
{
    //当此进程为要保护的进程时
    if (ClientId->UniqueProcess == (HANDLE)g_Pid &&
        DesiredAccess == PROCESS_TERMINATE)
    {
        //设为拒绝访问
        DesiredAccess = 0;
    }
    //调用原函数
    return g_OldZwOpenProcess(
        ProcessHandle,
        DesiredAccess,
        ObjectAttributes,
        ClientId);
}

参考文章

https://blog.csdn.net/flydragonhero/article/details/61193692
https://blog.csdn.net/php_fly/article/details/9180591
https://blog.csdn.net/php_fly/article/details/9202379

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值