[原创]Win32Asm 驱动学习笔记《 HOOK SSDT》
1.0 获取对应的SSDT服务序号
我们HOOK一个SSDT服务,首先需要知道它的服务号,网上流传的HOOK SSDT的C代码中,大多使用了一个宏来实现,我们先看下它的代码:
#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
例如取ZwTerminateProcess在SSDK中的服务序号:
SYSCALL_INDEX(ZwTerminateProcess);
这个宏之所以能工作,是因为所有的Zw*函数都开始于opcode:MOV eax, ULONG,这里的ULONG就是系统调用函数在SSDT中的索引.
WinDbg是一个很好的驱动调试工具,我们用它来反编译ZwTerminateProcess的代码如下:
lkd> u nt! ZwTerminateProcess
nt!ZwTerminateProcess:
804dead0 b801010000 mov eax,101h
804dead5 8d542404 lea edx,[esp+4]
804dead9 9c pushfd
804deada 6a08 push 8
804deadc e8500b0000 call nt!KiSystemService (804df631)
804deae1 c20800 ret 8
nt!ZwTerminateThread:
804deae4 b802010000 mov eax,102h
804deae9 8d542404 lea edx,[esp+4]
通过上面的反编译代码,我们就很明白了,ZwTerminateProcess入口地址 +1 的地址存储的就是服务序号了
这里我们假设和C一样,MASM中ZwTerminateProcess返回的就是入口地址, 实现代码如下:
mov eax,ZwTerminateProcess
mov eax,[eax+1] ;NtTerminateProcess Index
invoke DbgPrint, $CTA0("ZwTerminateProcess Index = %08X\n"),eax
可是我得到的却是一个错误的结果,什么原因?
我们调试下:
一步一步来,先看MASM里导出的ZwTerminateProcess是不是入口地址:
mov eax, ZwTerminateProcess
invoke DbgPrint, $CTA0("ZwTerminateProcess Base= %08X\n"),eax
通过KmdManager加载运行驱动,在DebugView输出窗口得到如下信息:
ZwTerminateProcess Base = F7B2435E
WinDbg反编译下这个地址,看看有什么东东:
lkd> u F7B2435E
f7b2435e ff259043b2f7 jmp dword ptr ds:[0F7B24390h]
f7b24364 ff259443b2f7 jmp dword ptr ds:[0F7B24394h]
f7b2436a ff259843b2f7 jmp dword ptr ds:[0F7B24398h]
f7b24370 0000 add byte ptr [eax],al
f7b24372 0000 add byte ptr [eax],al
f7b24374 0000 add byte ptr [eax],al
f7b24376 0000 add byte ptr [eax],al
f7b24378 0000 add byte ptr [eax],al
看着好像导出表,
看下0F7B24390处的数据内容:
lkd> dd 0F7B24390
f7b24390 804dead0 805000b9 804e4c06 00000000
f7b243a0 0044005c 00760065 00630069 005c0065
f7b243b0 006f0068 006b006f 00730073 00740064
f7b243c0 00000000 00220020 f7b243a0 003f005c
f7b243d0 005c003f 006f0068 006b006f 00730073
f7b243e0 00740064 00000000 001a0018 f7b243cc
f7b243f0 cdcba2b7 c6d6d8bf a6b9c9b3 0020a1a3
f7b24400 afb6fdc7 d8d4d3bc a6b9c9b3 0020a1a3
804dead0应该就是ZwTerminateProcess的入口地址,反编译下:
lkd> u 804dead0
nt!ZwTerminateProcess:
804dead0 b801010000 mov eax,101h
804dead5 8d542404 lea edx,[esp+4]
804dead9 9c pushfd
804deada 6a08 push 8
804deadc e8500b0000 call nt!KiSystemService (804df631)
804deae1 c20800 ret 8
nt!ZwTerminateThread:
804deae4 b802010000 mov eax,102h
804deae9 8d542404 lea edx,[esp+4]
果然,这下代码就简单了:
mov eax, ZwTerminateProcess
mov eax,[eax+2] ;jmp dword ptr ds:[0F7B24390h]
mov eax,[eax] ; ZwTerminateProcess Base
mov eax,[eax+1] ;NtTerminateProcess Index
MASM 用的SYSCALL_INDEX宏代码如下:
调用:
SYSCALL_INDEX MACRO lpZwproc:REQ
mov eax, lpZwproc
mov eax,[eax+2] ;jmp dword ptr ds:[0F7B24390h]
mov eax,[eax] ; ZwTerminateProcess Base
mov eax,[eax+1] ;NtTerminateProcess Index
EXITM <eax>
endm
mov eax,SYSCALL_INDEX(ZwTerminateProcess)
invoke DbgPrint, $CTA0("ZwTerminateProcess Index = %08X\n"),eax
另外,要说的是硬编码也是不错的方法,我们大概只需要3套就可以了。
2.0 一个简单的HOOK SSDT框架
以HOOK NtTerminateProcess 为例,核心代码如下:
;***************************************************************************
; 一个简单的HOOK SSDT 框架 by nohacks WebHome: http://hi.baidu.com/nohacks
;***************************************************************************
.386
.model flat, stdcall
option casemap:none
include w2k\ntstatus.inc
include w2k\ntddk.inc
include w2k\ntoskrnl.inc
include w2k\w2kundoc.inc
includelib \RadASM\masm32\lib\w2k\ntoskrnl.lib
include \RadASM\masm32\Macros\Strings.mac
;******************************************************************************
; 根据给出的服务对应的Zw函数返回服务号,例如:SYSCALL_INDEX(ZwTerminateProcess)
;******************************************************************************
SYSCALL_INDEX MACRO lpZwproc:REQ
mov eax, lpZwproc
mov eax,[eax+2] ;jmp dword ptr ds:[0F7B24390h]
mov eax,[eax] ; ZwTerminateProcess Base
mov eax,[eax+1] ;NtTerminateProcess Index
EXITM <eax>
endm
.data ?
OldProc dd ? ;用来保存原来的服务地址
.code
;***************************************************************************
; 根据给出的服务序号和替代服务地址修改ssdt表,返回值为原服务地址
;***************************************************************************
EditSSDT proc uses ecx dwIndex:dword,lpNowProc:dword
mov ecx, dwIndex ;服务号
mov eax, KeServiceDescriptorTable ;KSDT ,ntoskrnel SYSTEM_SERVICE_TABLE
mov eax,[eax] ; KSDT的指针
.if ecx>[eax+8] ;判断服务序号是否超出服务总数
mov eax,FALSE
ret
.endif
mov eax,[eax] ;SSDT的指针
pop [eax+ecx*4] ;保存原来的ServerBase
lea ecx,[eax+ecx*4] ;取序号地址 也就是 mov ecx,eax+ecx*4
push ecx ;保护ecx, MmIsAddressValid函数会修改ECX的值
invoke MmIsAddressValid,[ecx] ;检查地址是否有效
pop ecx
.if al== FALSE
jmp retun
.endif
;去掉写保护
push eax
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
pop eax
;修改 SSDT
push lpNowProc
pop [ecx]
;恢复写保护
push eax
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
pop eax
retun:
pop eax ;原来的ServerBase
ret
EditSSDT endp
调用代码如下:
;替代函数
MyNtTerminateProcess proc ProcessHandle,ExitStatus
invoke DbgPrint, $CTA0("call MyNtTerminateProcess\n")
mov eax ,STATUS_UNSUCCESSFUL
ret
MyNtTerminateProcess endp
开发环境:RadAsm(Masm+Kmdkit)整合版 + Win7/ Winxp3 32bit
;HOOK NtTerminateProcess
invoke EditSSDT,SYSCALL_INDEX(ZwTerminateProcess),offset MyNtTerminateProcess
mov OldProc,eax
;还原SSDT的修改
invoke EditSSDT,SYSCALL_INDEX(ZwTerminateProcess),OldProc
相关Win32Asm 驱动学习笔记一《驱动开发环境的搭建》
