首页
论坛
课程
招聘
[原创]Win32Asm 驱动学习笔记《 HOOK SSDT》
2013-8-6 12:00 10775

[原创]Win32Asm 驱动学习笔记《 HOOK SSDT》

2013-8-6 12:00
10775
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
调用代码如下:


;HOOK NtTerminateProcess

invoke EditSSDT,SYSCALL_INDEX(ZwTerminateProcess),offset MyNtTerminateProcess
mov OldProc,eax

;还原SSDT的修改

invoke EditSSDT,SYSCALL_INDEX(ZwTerminateProcess),OldProc

开发环境:RadAsm(Masm+Kmdkit)整合版 + Win7/ Winxp3 32bit

相关链接:Win32Asm 驱动学习笔记一《驱动开发环境的搭建》

[培训] 优秀毕业生寄语:恭喜id咸鱼炒白菜拿到远超3W月薪的offer,《安卓高级研修班》火热招生!!!

收藏
点赞0
打赏
分享
最新回复 (22)
雪    币: 49
活跃值: 活跃值 (16)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
邓韬 活跃值 9 2013-8-6 12:05
2
0
汇编很好玩吗?
雪    币: 35757
活跃值: 活跃值 (153657)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
linhanshi 活跃值 2013-8-6 12:15
3
0
+1
雪    币: 177
活跃值: 活跃值 (255)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
viphack 活跃值 4 2013-8-6 12:40
4
0
+2
雪    币: 71
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mumaren 活跃值 2013-8-6 12:53
5
0
感谢共享
谢谢
雪    币: 346
活跃值: 活跃值 (27)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
学雄 活跃值 1 2013-8-6 13:26
6
0
汇编很好玩吗?
如果没有后面的注释,可读性一塌糊涂,敢不敢后面不写注释
雪    币: 578
活跃值: 活跃值 (31)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
非安全 活跃值 17 2013-8-6 13:32
7
0
呵呵,每个人的环境不一样,我是业余玩家,写驱动只会W32ASM不会其它。

写注释是因为照顾象我一样的新手朋友

因为我的代码完全是能用API就用API

所以有点汇编基础的人应该都能看懂

希望我的回答你能满意,谢谢!
雪    币: 245
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
八十客车 活跃值 2013-8-6 14:00
8
0
谢谢楼主分享
雪    币: 154
活跃值: 活跃值 (25)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
小烦 活跃值 1 2013-8-6 14:27
9
0
汇编很好玩  汇编能力强 读程序代码能力不可能弱!
雪    币: 578
活跃值: 活跃值 (31)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
非安全 活跃值 17 2013-8-6 14:39
10
0
还不错。。。。
雪    币: 224
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
leelittle 活跃值 2013-8-6 15:48
11
0
正在学习琢石成器,希望能早日看懂楼主的大作
雪    币: 1568
活跃值: 活跃值 (677)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
pxhb 活跃值 2 2013-8-6 17:01
12
0
还可以,很喜欢用RadAsm
雪    币: 31
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hilylwz 活跃值 2013-8-7 11:22
13
0
楼主能否把开发环境“RadAsm(Masm+Kmdkit)整合版”共享一下啊:)
雪    币: 578
活跃值: 活跃值 (31)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
非安全 活跃值 17 2013-8-7 11:26
14
0
雪    币: 29
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
路独行 活跃值 2013-8-8 21:48
15
0
看来还有人玩汇编驱动....找到同类的感觉确实不错.  另回答上面的问题  汇编确实好玩....像我这类新手  除了汇编容易一点入门外  其它怕是想搞清楚来龙去脉还是相当的麻烦
雪    币: 793
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
zyr零零发 活跃值 1 2013-8-9 08:05
16
0
汇编接触系统底层,用多了感觉和c没有区别。
radasm非常不错。
雪    币: 458
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小龙程序 活跃值 2013-8-10 01:38
17
0
非常不错的贴子!我喜欢汇编
雪    币: 470
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cnxxm 活跃值 2013-8-10 03:38
18
0
学习中。。。。。
雪    币: 114
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
skyercao 活跃值 2013-8-11 12:57
19
0
冷嘲热讽很好玩么?
雪    币: 57
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
AsmCoder 活跃值 2013-8-12 15:02
20
0
push [eax+ecx*4]                         ;压入原来的ServerBase                              

   lea ecx,[eax+ecx*4]                    ;取序号地址 也就是 mov ecx,eax+ecx*4

   push ecx                                ;保护ecx, MmIsAddressValid函数会修改ECX的值
   invoke MmIsAddressValid,ecx             ;检查地址是否有效

    .if al== FALSE                  
      ;建议加上add esp,8  
      
      ret
      
    .endif

这样的写法很危险. 当al为false的时候,未平衡堆栈直接使用了ret ,当然这个函数因为有参数不会出错
如果没有参数和变量,当al为false的时候会出错.

例:

将生成:


test1 将出错, test2 与 test3 正常
上传的附件:
雪    币: 57
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
AsmCoder 活跃值 2013-8-12 15:17
21
0
仔细的读了下,发现lz取ssdt序号的思路不错. 我以前是用内核工具查看对应函数的序号直接拿来用.受教了。

一点小建议,SYSCALL_INDEX 宏里直接使用eax就可以不用去注意保存ecx了.
雪    币: 578
活跃值: 活跃值 (31)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
非安全 活跃值 17 2013-8-12 16:47
22
0
[QUOTE=AsmCoder;1208932]push [eax+ecx*4]                         ;压入原来的ServerBase                              

   lea ecx,[eax+ecx*4]                    ;取序号地址 也就是 mov e...[/QUOTE]

受教了,一直没注意这方面的问题。

我修改了下代码 ,在判断返回前就恢复堆栈。
雪    币: 578
活跃值: 活跃值 (31)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
非安全 活跃值 17 2013-8-12 17:03
23
0
谢谢你的建议,已经修改。

之前是出于调用程序可能用EAX和SYSCALL_INDEX宏同时做为参数的考虑。
游客
登录 | 注册 方可回帖
返回