SSDT_HOOK的学习

前言:
使用vs自带的开发人员工具,可以使用dumpbin命令,查看pe文件的导入表等信息 :
这里写图片描述

命令的意思:
使用dumpbin把 ntoskrnl.exe中的导出表 复制到1.txt中

SSDT:system service descriptor table 系统服务描述符表

1.什么是SSDT

网上也有一篇博客讲的不错:
SSDT详解
a.Windows系统中的内核执行层是ntoskrnl.exe
i.不同的版本,ntoskrnl.exe可能是不一样的
ii.这个文档说明都是在win7 sp1 32位下的ntoskrnl.exe
b.windows中,有4张系统服务表,机构体如下:

typedef _KSERVICE_TABLE_DESXRIPTOR{
KSYSTEM_SERVICE_TABLE ntoskrnl;//指向SSDT
KSYSTEM_SERVICE_TABLE win32k;  //shadowSSDT
KSYSTEM_SERVICE_TABLE  notUsed1;
KSYSTEM_SERVICE_TABLE  notUsd2;

}KSERVICRE_TABLE_DESCRIPTOR;
//在KiFastEntry的时候,会判断是ssdt 还是shadowSSD

c.在内核执行层中,有2张服务表,分别叫做:
i.KeServiceDescriptor Table :这就是SSDT的表
ii.KeServiceDescriptorTableShadow:这是SSDTShadow表
iii.kernel32.dll中的函数,都是由SSDT这张表来处理
iv.SSDTShadow这张表主要是用来处理user32.dll和gdi32.dll的函数

d.不管是KeServiceDescriptor Table 还是KeServiceDescriptorTableShadow,它们所指向的结构体都是相同的;

typedef struct _KESERVICE_DESCRIPTOR_Table 
{
PULONG ServiceTableBase;//SSDT或者shadowSSDT的基址
PULONG ServiceCounterTableBase;//用户check builds,包含ssdt中每个服务被调用的次数
ULONG NumberOfServices;//服务函数的个数,NumberOfServices*4就是整个地址表的大小
PUCHAR ParamTableBase;//SSPT(system service Parameter table),参数表的地址

}KESERVICE_DESCRIPTOR_TABLE, *PKESERVICE_DESCRIPTOR_TABLE;

2.怎么找SSDT

a.以OpenProcess为例:

i.进入OD随便打开一个程序
ii.ctrl+g 找到OpenProcess这个函数的位置
这里写图片描述
iii.进入OpenProcess 可以发现,会调用ntdll中的ZwOpenProcess,点击enter进去
这里写图片描述
iv.以发现,mov eax,0xBE ,0xBE这就是SSDT的索引号 0xbe = 190d
通过PCHUNTER可以看一下 :
这里写图片描述
这里写图片描述
V.确实可以看出,SSDT这表中,下标为0xBE处的确是 NtOpenProcess
然后这个call 应该就是进入sysenter 了,od已经跟不进去了

b.首先要知道,这个调用号本身的结构
并未使用服务表号索引号
23位1位12位

i.服务表号就是SSDT表还是shadowssdt表

0SSDT
1shadowSSDT

去看一下ssdt,因为shadow ssdt 之后再有GUI的线程中才可以看到
windbg kernel debug 挂上本机就行:

lkd> dd nt!KeServiceDescriptorTable 

81d869c0  81c8d6f0 00000000 00000191 81c8dd38 

81d869d0  00000000 00000000 00000000 00000000 

81d869e0  81cf9493 00000000 02224c74 000000bb 

81d869f0  00000011 00000100 5385d2ba d717548f 

81d86a00  81c8d6f0 00000000 00000191 81c8dd38 

81d86a10  97715000 00000000 00000339 9771602c 

81d86a20  00000000 00000000 81d86a24 00000240 

81d86a30  00000240 835ad7e0 00000003 00000000 

通过Windbg可以看出,第一行81c8d6f0 00000000 00000191 81c8dd38这一行对应的就是KESERVICE_DESCRIPTOR_TABLE这个结构体 ;
这里写图片描述

0xbe 就是ZwOpenProcess在SSDT表中的索引 :

lkd> dd 81c8d6f0 +0xbe*4 

81c8d9e8  81e9f531 81e5a8f1 81e5a03e 81d9bdc0 

81c8d9f8  86ba4804 81e023ca 81e21cc8 81e9c48a 

81c8da08  81e9de88 81e5a155 81e59c29 81f26edb 

81c8da18  81f0f879 81f10b11 81e06231 81e577fc 

81c8da28  81f0f42a 81f0f14a 81f0f4e2 81f0f202 

81c8da38  81e1905c 81de19ba 81dfc03f 81f1126c 

81c8da48  81f11332 86ba3670 81eb4c3c 81e80b48 

81c8da58  81f21afa 81f21f3d 81ce0c6a 81ea2473 

然后查看这个地址 :

lkd> u 81e9f531  

nt!NtOpenProcess: 

81e9f531 8bff            mov     edi,edi 

81e9f533 55              push    ebp 

81e9f534 8bec            mov     ebp,esp 

81e9f536 51              push    ecx 

81e9f537 51              push    ecx 

81e9f538 64a124010000    mov     eax,dword ptr fs:[00000124h] 

81e9f53e 8a803a010000    mov     al,byte ptr [eax+13Ah] 

81e9f544 8b4d14          mov     ecx,dword ptr [ebp+14h] 

这个就是OpenProcess在内核中的函数 ;

3.代码

#include <ntifs.h> 





////////////////////////////////////////////////////////////////////////// 

// hook 目标 

// ZwOpenProcess 

//定义给一个 字节定义的 

typedef NTSTATUS(NTAPI *ZWOPENPROCESS)( 

_Out_     PHANDLE ProcessHandle, 

_In_      ACCESS_MASK DesiredAccess, 

_In_      POBJECT_ATTRIBUTES ObjectAttributes, 

_In_opt_  PCLIENT_ID ClientId 

); 



ZWOPENPROCESS g_OldOpenProcess = 0;//老的openProcess的函数地址 



ULONG g_NeedToProtectProcessID = 0; 





// 定义一个我们自己的OpenProcess 

NTSTATUS NTAPI MyOpenProcess( 

_Out_     PHANDLE ProcessHandle, 

_In_      ACCESS_MASK DesiredAccess, 

_In_      POBJECT_ATTRIBUTES ObjectAttributes, 

_In_opt_  PCLIENT_ID ClientId 

) 

{ 

DbgPrint("Hook Sucess\n"); 

if (ClientId->UniqueProcess == g_NeedToProtectProcessID) 

{ 

//如果判断打开的是我们保护的进程 

//直接把权限改成0 

DesiredAccess = 0; 

} 

//让旧的函数去处理 

return g_OldOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); 

} 









#pragma  pack(1) //设置对齐力度,这里是以1个字节的力度对齐 

typedef struct _ServiceDesriptorEntry 

{ 

ULONG * ServiceTableBase; //服务表基地址 

ULONG * ServiceCounterTableBase;//计数表基址 

ULONG  NumberOfServices; //表中项的个数 

UCHAR* ParamTableBase; //参数表基址 

}SSDTENTRY,*PSSDTENTRY; 

#pragma  pack() 



//导入SSDT  

// 32位下,SSDT直接导入就可以用 

// 64位就不行,没有导出,而且服务表也改变了,里面存的不是地址 

// 而是偏移 

NTSYSAPI  SSDTENTRY KeServiceDescriptorTable; 







//恢复页保护 

void OnProtect(){ 



_asm{ 

push eax; 

mov eax, CR0; //CR0 寄存器主要是跟页的属性的有关 

or eax,0x10000; 

mov CR0, eax; 

pop eax; 

} 

} 



//关掉页保护 

void OffProtect(){ 

_asm{ 

push eax; 

mov eax, CR0; 

and eax, ~0x10000; 

mov CR0, eax; 

pop eax; 

} 

} 



//开始hook函数 

void OnHook(){ 

g_OldOpenProcess = (ZWOPENPROCESS)KeServiceDescriptorTable.ServiceTableBase[190];//获取OpenProcess的函数地址 



OffProtect();//关闭保护 



KeServiceDescriptorTable.ServiceTableBase[190] = (ULONG)MyOpenProcess;//强制更改一波 



OnProtect(); 

} 

void offHook(){ 

OffProtect(); 



KeServiceDescriptorTable.ServiceTableBase[190] = g_OldOpenProcess; 



OnProtect(); 

} 





//驱动卸载函数 

void DriverUnload(PDRIVER_OBJECT pDriver){ 



offHook(); 

UNREFERENCED_PARAMETER(pDriver); 

} 



NTSTATUS DriverEntry(PDRIVER_OBJECT pDirver, PUNICODE_STRING path){ 



UNREFERENCED_PARAMETER(path); 

_asm int 3; 

DbgPrint("entry driver\n"); 

g_NeedToProtectProcessID = 1456;//这里手动设置了需要保护的ID,最好遍历出来 

OnHook(); 

pDirver->DriverUnload = DriverUnload; 

return STATUS_SUCCESS; 

} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值