Kaspersky 7.0 HOOK SSDT分析

本文详细解析了卡巴斯基反病毒软件如何通过逆向工程手段向系统服务函数表(SSDT)注入自定义服务函数的过程。文章深入介绍了驱动程序如何通过修改SSDT表来实现HOOK技术,为读者提供了实现类似功能的指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:Cloud
Email:shangguanwan2@yahoo.cn
2007-11-6

一、 测试版本和环境
卡巴斯基反病毒软件7.0 版本7.0.0.125d (简体中文版)
平台:Windows XP Professional(5.1,版本2600)
   Mobile Inter? Celeron? CPU 1.60GHz
工具:IDA Version 5.0.0.879(32bit)
目标文件:卡巴的核心驱动klif.sys,位于SystemDirectory/system32/drivers目录下

二、目标
通过逆向工程,分析卡巴是怎样向系统服务函数表(SSDT)添加自己的服务函数的,并写出自己的实现。

三、 分析
使用IDA分析在sub_291A0处发现驱动向SSDT添加自己的系统服务函数。基本流程就是分配内存,构造一个自己的SSDT,再把系统的KeServiceDescriptorTable改为指向这个构造的SSDT。最后还要修改一个叫KeAddSystemServiceTable的结构。

下面来一步一步分析:

sub_291A0 proc near

var_pKeAddSystemServiceTable= dword ptr -8
var_NewSerNum= dword ptr -4

sub     esp, 8
mov     eax, ds:KeServiceDescriptorTable
push    ebx
push    ebp
push    esi
mov     esi, [eax+8]
push    edi
add     esi, 0Dh        ; 增加SSDT的服务函数的数目,
                        ; 之后会添加一些自己的系统服务
mov     [esp+18h+var_NewSerNum], esi
call    CheckKeAddSystemServiceTable
test    eax, eax
mov     [esp+18h+var_pKeAddSystemServiceTable], eax
jnz     short loc_291D0

驱动先取得SSDT表的指针,获取系统服务数目,保存在esi中,然后把它增大0Dh(13d),之后会增加13个自己的系统服务到SSDT。然后调用了CheckKeAddSystemServiceTable,在这个函数中将KeAddSystemServiceTable函数代码所在的页进行确认,确保代码全部被交换到内存中。返回后eax保存的就是KeAddSystemServiceTable函数的地址。

loc_291D0:
mov     ecx, ds:KeServiceDescriptorTable
mov     edi, ds:ExAllocatePoolWithTag
lea     eax, ds:0[esi*4]
push    2D536542h       ; Tag
mov     edx, [ecx+8]    ; ecx+8,指向SSDT中系统服务数
push    eax             ; NumberOfBytes
push    0               ; PoolType
mov     ds:NumOfOldSSDT, edx
call    edi ; ExAllocatePoolWithTag ; 在SSDT中分配空间以保存自定义的
                        ; 服务函数
mov     ebx, eax
test    ebx, ebx
jz      loc_29352

然后开始分配内存保存自定义的SSDT,大小等于新的系统服务数*4,返回的地址保存在ebx。

push    2D536542h       ; Tag
push    esi             ; NumberOfBytes
push    0               ; PoolType
call    edi ; ExAllocatePoolWithTag
mov     ebp, eax
test    ebp, ebp
jz      loc_2934B
接着在再次分配内存,大小esi,用于保存参数表。返回的地址在ebp。然后就开始构造SSDT和SSPT。

mov     eax, ds:KeServiceDescriptorTable
mov     edi, ebx
mov     ecx, [eax+8]
mov     esi, [eax]      ; 取得SSDT的基地址
shl     ecx, 2          ; 即ecx*4
mov     eax, ecx
shr     ecx, 2          ; 将整个SSDT复制到
                        ; 刚才第一次分配的内存中
rep movsd
mov     ecx, eax
and     ecx, 3
rep movsb
mov     eax, ds:KeServiceDescriptorTable
mov     edi, ebp
mov     ecx, [eax+8]
mov     esi, [eax+0Ch]  ; [eax+0ch]指向参数表的基地址
mov     edx, ecx        ; 复制参数表
shr     ecx, 2
rep movsd
mov     ecx, edx
and     ecx, 3
rep movsb
mov     eax, ds:KeServiceDescriptorTable
mov     esi, offset off_33D0C ; 这里的off_33D0C指向的就是卡巴自己的
                        ; 系统服务,分析卡巴逻辑最重要的就是这里
mov     ecx, [eax+8]
lea     edi, [ebx+ecx*4]
mov     ecx, 0Dh        ; 复制自定义系统服务到刚才
                        ; 第一次分配的内存中去
rep movsd
mov     edx, ds:KeServiceDescriptorTable
mov     ecx, dword_33D40 ; 这是卡巴自己的服务函数的参数信息
                        ; 拷贝这些信息到SSPT中去
xor     esi, esi
mov     eax, [edx+8]
add     eax, ebp
mov     [eax], ecx
mov     edx, dword_33D44
mov     [eax+4], edx
mov     ecx, dword_33D48
mov     [eax+8], ecx
mov     dl, byte_33D4C
mov     [eax+0Ch], dl   ; 至此,已经构造了一个完整的SSDT
mov     eax, ds:KeServiceDescriptorTable
cmp     [eax+4], esi
jz      short loc_29310

以上注释写得很清楚,就不说了。最后的地方它测试KeServiceDescriptorTable结构的ServiceCounterTableBase成员,等于零就可以修改KeServiceDescriptorTable,完成HOOK。不等于零的情况下会重新分配内存换一种方式构造SSDT,如果你有兴趣可以自己分析。

loc_29314:
mov     ecx, ds:KeServiceDescriptorTable
pop     edi
pop     esi
mov     [ecx], ebx      ; 修改SSDT entry,指向卡巴构建的SSDT
mov     edx, ds:KeServiceDescriptorTable
mov     ecx, [esp+10h+var_NewSSDTNum]
mov     [edx+0Ch], ebp  ; 修改参数表地址
mov     edx, ds:KeServiceDescriptorTable
mov     [edx+8], ecx    ; 更新服务数目
mov     [eax+0Ch], ebp
mov     [eax], ebx
mov     [eax+8], ecx
pop     ebp             ; 从这里的操作来看,KeAddSystemServiceTable
                        ; 和KeServiceDescriptorTable的结构应该是相同的
mov     ds:flag_bSuccess, 1 ; 修改标志,成功
xor     eax, eax
pop     ebx
add     esp, 8
retn

OK,分析完毕。根据以上分析,你完全可以写一个自己的实现代码。 

本实例由VS2008开发,在提供了一套驱动开发框架的同时,又演示了如何获取Shadow SSDT表函数原始地址的办法。 主要函数:ULONG GetShadowSSDT_Function_OriAddr(ULONG index); 原理说明: 根据特征码搜索导出函数KeAddSystemServiceTable来获取Shadow SSDT基址,以及通过ZwQuerySystemInformation()函数获取win32k.sys基址,然后解析PE定位到Shadow SSDT在win32k.sys的偏移地址,并通过进一步计算来得到Shadow SSDT表函数的原始地址。 这里只测试了三个函数:(460)NtUserMessageCall、(475)NtUserPostMessage和(502)NtUserSendInput,具体使用时可以举一反三,网上完整的源代码实例并不太多,希望可以帮到真正有需要的朋友。 系统环境: 在WinXP SP3系统 + 瑞星杀毒软件 打印输出: [ LemonInfo : Loading Shadow SSDT Original Address Driver... ] [ LemonInfo : 创建“设备”值为:0 ] [ LemonInfo : 创建“设备”成功... ] [ LemonInfo : 创建“符号链接”状态值为:0 ] [ LemonInfo : 创建“符号链接”成功... ] [ LemonInfo : 驱动加载成功... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP 开始... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP Enter IRP_MJ_DEVICE_CONTROL... ] [ LemonInfo : 获取ShadowSSDT表 (460)NtUserMessageCall 函数的“当前地址”为:0xB83ECFC4,“起源地址”为:0xBF80EE6B ] [ LemonInfo : 获取ShadowSSDT表 (475)NtUserPostMessage 函数的“当前地址”为:0xB83ECFA3,“起源地址”为:0xBF8089B4 ] [ LemonInfo : 获取ShadowSSDT表 (502)NtUserSendInput 函数的“当前地址”为:0xBF8C31E7,“起源地址”为:0xBF8C31E7 ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP_MJ_DEVICE_CONTROL 成功执行... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP 结束... ] [ LemonInfo : UnLoading Shadow SSDT Original Address Driver... ] [ LemonInfo : 删除“符号链接”成功... ] [ LemonInfo : 删除“设备”成功... ] [ LemonInfo : 驱动卸载成功... ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值