看流星社区

 找回密码
 注册账号
查看: 2166|回复: 0

汇编与驱动-采用SSDT Hook NtOpenProcess保护进程

[复制链接]

该用户从未签到

发表于 2017-6-1 17:25:56 | 显示全部楼层 |阅读模式
标 题:汇编与驱动-采用SSDT Hook NtOpenProcess保护进程
作 者: organic
时 间: 2012-07-09,21:05:47
链 接: http://bbs.pediy.com/showthread.php?t=153176

作为一个热爱汇编的人被迫使用C或者C++写驱动是一件很难受的事情,特别是在做一些邪恶的事情的时候,你总会发现汇编就是一只恶魔之手,而C或者C++总是缺乏那么一点魔力,还好,VC支持内联汇编,那么我们用VC的优势给我们写驱动搭一个平台,使用他们丰富的资源,然后用我们的汇编编写核心代码,做我们想做的事情,虽然我的最终目标是全部用汇编解决一切问题,但在目前汇编资源越来越少的情况下我们不得不做一些屈服。
废话说了很多,下面我就奉上一个估计很多同学都学过的一个例子,《郁金香驱动教程》的032课-自写驱动保护XX进程,原理郁金香老师已经讲得很清楚了,C++的代码教程里也有,我就不重复了。我的任务是采用内联汇编改写其中关键的代码,当然,作为一个汇编的热爱者,客户端exe文件我用汇编写的,同时对郁金香的客户端和驱动端代码都进行了完善,同时将客户端编写改为Windows界面,使界面更加友好。
软件运行后界面如下:


下面开始解释一下代码,没什么技术含量,汇编按自己的风格写的,高手直接无视
先说说用户端:
里面有一个DDKDriver.inc的文件,这里面主要是定义了一个汇编常用的宏,还有几个驱动用的宏和一些字符定义(--汇编的资源太缺乏,只能从VC里整点用用),写界面的部分我就不说了,源代码里有。

代码:
invokeCreateFile,addrszDriverLinkName,\
GENERIC_READorGENERIC_WRITE,\
0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
movhDevice,eax
.ifeax==INVALID_HANDLE_VALUE

invokeGetLastError
invokewsprintf,addrszMsgBuffer,CTXT("打开设备失败,错误码=%d"),eax
invokeNt_MsgBox,addrszMsgBuffer
invokeSendMessage,hDlgmain,WM_CLOSE,NULL,NULL
.endif
[/code]

在对话框窗口初始化部分我们用CreateFile打开一个设备,注意第一个参数的命名“addrszDriverLinkName”

代码:
szDriverLinkNamedb"\\.\SSDTHook_NtOpenProcess",0
[/code]

这里不能用郁金香教程你的写法"\\\\.\\SSDTHook_NtOpenProcess",因为汇编是不需要转义符的
打开设备后,我们检查设备的句柄,如果出错,则报一个出错码,发送一个窗口关闭的消息退出,所以一定要先把驱动加载起来,再运行用户端。


代码:
;名称:Nt_SSDTHook
;功能:Hook指定进程PID的程序
;参数:_hDevice=设备句柄
;参数:_HookProcessID=要Hook进程的PID
;返回:eax,eax=1表示成功,eax=0表示失败

Nt_SSDTHookproc_hDeviceWORD,_HookProcessIDWORD
local@InputBufferWORD
local@RetNumWORD

pushesi
pushebx

moveax,_HookProcessID
mov@InputBuffer,eax
leaesi,@InputBuffer
leaebx,@RetNum

invokeDeviceIoControl,_hDevice,SSDTHook_code,esi,4,NULL,0,ebx,NULL
moveax,@RetNum

popebx
popesi
ret
Nt_SSDTHookendp

;名称:Nt_SSDTUnHook
;功能:卸载Hook
;参数:_hDevice=设备句柄
;返回:eax

Nt_SSDTUnHookproc_hDeviceWORD
local@RetNumWORD

pushebx

leaebx,@RetNum

invokeDeviceIoControl,_hDevice,SSDTUnHook_code,NULL,0,NULL,0,ebx,NULL
moveax,@RetNum

popebx

ret
Nt_SSDTUnHookendp
[/code]

其实用户端的Hook和UnHook很简单,就是发送一个IRP给驱动端,同时接受驱动端返回的信息,判断是否Hook或UnHook成功,当然,Nt_SSDTHook发送IRP时还要传递一个要保护进程的PID,SSDTHook_code和SSDTUnHook_code这两个控制码都在DDKDriver.inc定义好了

接下来讲一讲驱动端的代码,其他公共的部分就不解释了,基本驱动的框架就是那样,我们直接拿来用就是了,当然我编译的时候用的是VS2005和DDK,还有一个DDKWizard,网上有教程,这里我们就不讲了,编译不成功的同学很有可能是编译环境搭建有问题。


代码:
NTSTATUSMyNtOpenProcess(OUTPHANDLEProcessHandle,INACCESS_MASKAccessMask,INPOBJECT_ATTRIBUTESObjectAttributes,INPCLIENT_IDClientId)
{
NTSTATUSReturn_NtOpenProcess;
DbgPrint("进入MyNtOpenProcess\n");
//调用原NtOpenProcess
_asm
{
pushClientId
pushObjectAttributes
pushAccessMask
pushProcessHandle
callSSDT_NtOpenProcess

movReturn_NtOpenProcess,eax
}
if(HookProcessID==ClientId->UniqueProcess)
{
ProcessHandle=NULL;
Return_NtOpenProcess=STATUS_ACCESS_DENIED;
DbgPrint("NtOpenProcess被保护\n");
}
returnReturn_NtOpenProcess;
}
[/code]

这里我们先写一个MyNtOpenProcess以替代原NtOpenProcess,郁金香教程中用的是C++的写法,这里我们用内联汇编来代替。

代码:
pushClientId
pushObjectAttributes
pushAccessMask
pushProcessHandle
callSSDT_NtOpenProcess

movReturn_NtOpenProcess,eax
[/code]

其实代替的方法很简单,就是把NtOpenProcess的4个参数直接入栈即可,当然注意顺序要相反,然后call我们Hook前得到NtOpenProcess的原地址,注意call后不要再去平衡堆栈,因为Window内核函数和API一样,是自己恢复堆栈的
调用原NtOpenProcess后,我们就判断ClientId和我们从用户端程序得到的要保护的进程的PID是否相等,相等就将ProcessHandle=NULL,不相等则直接返回


代码:
NTSTATUSSSDTHook_NtOpenProcess()
{
if(HookFlag_NtOpenProcess==0)
{
DbgPrint("开始HookNtOpenProcess\n");
_asm
{
pushad
movebx,KeServiceDescriptorTable
moveax,122
movebx,[ebx]//取SSDT表基址
shleax,2//函数索引号*4
addebx,eax
movSSDT_NtOpenProcess_Addr,ebx//得到SSDT表中指向NtOpenProcess的地址的地址
moveax,[ebx]
movSSDT_NtOpenProcess,eax//得到原NtOpenProcess的地址

cli//去除写保护
moveax,cr0
andeax,0FFFEFFFFh
movcr0,eax

moveax,MyNtOpenProcess//写入我们自己的NtOpenProcess地址
mov[ebx],eax

moveax,cr0//恢复写保护
oreax,10000h
movcr0,eax
sti
popad
}
HookFlag_NtOpenProcess=1;
DbgPrint("NtOpenProcess原地址:%x\n",(int)SSDT_NtOpenProcess);
DbgPrint("HookNtOpenProcess后的地址:%x\n",(int)MyNtOpenProcess);
}
else
{
DbgPrint("NtOpenProcess已被Hook\n");
}

returnSTATUS_SUCCESS;
}
[/code]

下面是UnHook的部分,主要是将SSDT表中NtOpenProcess的原地址重新写入

代码:
NTSTATUSSSDTUnHook_NtOpenProcess()
{
if(HookFlag_NtOpenProcess==1)
{
_asm
{
pushad
cli
moveax,cr0
andeax,0FFFEFFFFh
movcr0,eax

movebx,SSDT_NtOpenProcess_Addr//得到SSDT表中指向NtOpenProcess的地址的地址
moveax,SSDT_NtOpenProcess
mov[ebx],eax//恢复SSDT表中NtOpenProcess的地址

moveax,cr0
oreax,10000h
movcr0,eax
sti
popad
}
DbgPrint("UnHook还原NtOpenProcess完毕\n");
HookFlag_NtOpenProcess=0;
}
else
{
DbgPrint("NtOpenProcess已被还原\n");
}
returnSTATUS_SUCCESS;
}
[/code]

这里我们看到驱动关键的部分用汇编写后程序要精简很多,对于操作内存汇编是相当容易的,实际上郁金香教程的去除写保护和恢复写保护也是用汇编写的,当然我的代码和他的稍微有点不同,内联汇编给我们一个有力的工具,让汇编继续在驱动中发挥它强大的能力,在RING0级别下更加能畅行无阻。
当然这个保护是简单的,破解的方法也很容易,把要保护的进程关闭,然后再重新打开,一般他的PID就改变了,我们就Hook不到了。
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 16:56

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表