首页
社区
课程
招聘
[原创] AntiShutdown.sys from MASM
发表于: 2014-6-8 04:19 7218

[原创] AntiShutdown.sys from MASM

2014-6-8 04:19
7218
拦截关机/重启/注销,需要HOOK什么内核函数,我们来看看PowerTool是怎么实现的:


我现在的系统是32位WIN7 旗舰版 [版本 6.1.7600]
打开PowerTool,选择“禁止进程创建等配置”,选中,查看Shadow SSDT钩子,发现NtUserCallNoParam被挂钩,如下图:

我们跟踪下PowerTool 的NtUserCallNoParam 的替代函数

lkd> u 8e97ed10 l50
8e97ed10 8bff mov edi,edi
8e97ed12 55 push ebp
8e97ed13 8bec mov ebp,esp
8e97ed15 83ec08 sub esp,8
8e97ed18 8b4508 mov eax,dword ptr [ebp+8]
8e97ed1b 50 push eax
8e97ed1c ff15d8cd988e call dword ptr ds:[8E98CDD8h]
8e97ed22 8945fc mov dword ptr [ebp-4],eax
8e97ed25 837d0810 cmp dword ptr [ebp+8],10h
8e97ed29 7507 jne 8e97ed32
8e97ed2b c745fc00000000 mov dword ptr [ebp-4],0
8e97ed32 8b45fc mov eax,dword ptr [ebp-4]
8e97ed35 8be5 mov esp,ebp
8e97ed37 5d pop ebp
8e97ed38 c20400 ret 4

关键代码:
8e97ed25 837d0810 cmp dword ptr [ebp+8],10h
8e97ed29 7507 jne 8e97ed32
得出结论:
32位WIN7系统下NtUserCallNoParam参数一是10h时是关机/重启/注销。
那么在WINXP SP3 上是怎么样呢?我们看下,如下图:

与WIN7不同,WINXP是HOOK NtUserCallOneParam
继续跟踪
lkd> u A01A1B80 l50
a01a1b80 8bff mov edi,edi
a01a1b82 55 push ebp
a01a1b83 8bec mov ebp,esp
a01a1b85 83ec08 sub esp,8
a01a1b88 8b450c mov eax,dword ptr [ebp+0Ch]
a01a1b8b 50 push eax
a01a1b8c 8b4d08 mov ecx,dword ptr [ebp+8]
a01a1b8f 51 push ecx
a01a1b90 ff1534fd1aa0 call dword ptr ds:[0A01AFD34h]
a01a1b96 8945fc mov dword ptr [ebp-4],eax
a01a1b99 837d0c34 cmp dword ptr [ebp+0Ch],34h
a01a1b9d 7507 jne a01a1ba6
a01a1b9f c745fc00000000 mov dword ptr [ebp-4],0
a01a1ba6 8b45fc mov eax,dword ptr [ebp-4]
a01a1ba9 8be5 mov esp,ebp
a01a1bab 5d pop ebp
a01a1bac c20800 ret 8
关键代码:
a01a1b99 837d0c34 cmp dword ptr [ebp+0Ch],34h
a01a1b9d 7507 jne a01a1ba6

XP下NtUserCallOneParam下参数二 是 34h时是是关机/重启/注销

核心代码如下:



InitHook proc

;HOOK SSSDT 必须在GUI线程上下文操作才有效,DispatchControl 操作会加载win32k.sys,加载win32k.sys后,系统导出的KeServiceDescriptorTable表会失效

;这时HOOK SSDK 直接用找到的SSSDT基址即可,SSSDT表在第二个数组。

;取SSDT表基地址

invoke GetServiceDescriptorTableShadowAddress

mov SSDT,eax

;取SSSDT表基地址(win32.sys)

add eax,size SYSTEM_SERVICE_TABLE

mov SSSDT,eax

invoke DbgPrint,$CTA0("SSSDT BASE: %8X\n"),eax
;取系统版本

invoke GetWindowsVersion

mov WINDOWS_VERSION,eax


;只确定WINXP和WIN7的SSSDT序号是正确的,其他系统请修改。

.if eax==WINDOWS_VERSION_2K


mov NtUserCallNoParam_callnumber,142h
mov NtUserCallOneParam_callnumber,143h
mov Rcode,38h
ret


.elseif eax==WINDOWS_VERSION_XP || eax==WINDOWS_VERSION_2K3


mov NtUserCallNoParam_callnumber,142h
mov NtUserCallOneParam_callnumber,143h
mov Rcode,34h
ret

.else

mov NtUserCallNoParam_callnumber,14dh
mov NtUserCallOneParam_callnumber,14eh
mov Rcode,10h
ret

.endif


ret
InitHook endp



;***************************************************************************
; 根据给出的服务序号和替代服务地址修改ssdt表,返回值为原服务地址
;***************************************************************************
EditSSDT proc uses ebx ecx lpbase:dword ,dwIndex:dword,lpNowProc:dword

invoke MmIsAddressValid,lpNowProc ;检查地址是否有效
.if al== FALSE

;invoke DbgPrint, $CTA0("无效地址:%8X\n"),lpNowProc
mov eax,FALSE
ret
.endif
mov ecx, dwIndex
mov eax, lpbase ;SYSTEM_SERVICE_TABLE


.if ecx>[eax+8] ;判断服务序号是否超出服务总数

mov eax,FALSE
ret

.endif

mov eax,[eax] ;SSDT的指针

mov ebx,[eax+ecx*4] ;原地址

.if lpNowProc==ebx ;原地址和要修改的地址相同,代表已经修改,直接返回假

mov eax,FALSE
ret

.endif

push ebx ;入栈,保存原来的ServerBase

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



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

.if al== FALSE
pop eax ;恢复堆栈

;invoke DbgPrint, $CTA0("无效地址:%8X\n"),ecx

mov eax,FALSE
ret
.endif


;去掉写保护
push eax
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
pop eax


;修改 SSDT
push lpNowProc
pop dword ptr[ecx]

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

pop eax ;出栈,返回值为原服务地址
ret
EditSSDT endp



new_NtUserCallNoParam proc Routine:dword , Param:dword
;在win7下NtUserCallNoParam的第一个参数Routine = 10h的时候 是关机/重启/注销
mov eax,Rcode
.IF Routine==eax

mov eax ,0
ret

.else

push Param
push Routine

call old_NtUserCallNoParam
ret

.endif

new_NtUserCallNoParam endp

new_NtUserCallOneParam proc Param:dword , Routine:dword
;在win2k下 NtUserCallOneParam的第二个参数Routine = 0x38的时候 是关机/重启/注销
;在winxp/win2k3下NtUserCallOneParam的第二个参数Routine = 0x34的时候 是关机/重启/注销

mov eax,Rcode

.IF Routine==eax

mov eax ,0

ret

.else

push Routine
push Param
call old_NtUserCallOneParam
ret


.endif

new_NtUserCallOneParam endp






代码目录里附带了一个MASM写的驱动加载工具,测试时请注意:

先注册,再运行,然后I/O控制,控制码800是安装HOOK,801是卸载HOOK

注意,驱动停止前先要用控制码801卸载HOOK,不然蓝屏





编译环境:RadASM

blog:http://nohacks.cn

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 292
活跃值: (153)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
Nohack ?  网站还开不开了!
2014-6-8 06:30
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
3
不是我你懂的
2014-6-8 13:20
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
4
重新修正了一下,请有需要的朋友重新下载吧
2014-6-15 04:07
0
雪    币: 8227
活跃值: (2731)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
内核没接触,急需学习啊
2014-6-15 07:17
0
雪    币: 478
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
能否准确判断出是重启还是关机?
2014-6-15 13:04
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
7
在替代函数里,调试输出参数数据,看下有什么区别吧 ,我这里不需要判断准确
2014-6-15 14:25
0
游客
登录 | 注册 方可回帖
返回
//