调用源检测逻辑,核心技术之绕过【新萄京娱乐场.2959.com】

kd.exe
-n -v -logo d:\virtual_machine_debugging.txt -y
SRV*C:\Symbols* -k
com:pipe,port=\\.\pipe\com_1,baud=115200,reconnect

———– Rootkit 大旨本领之绕过 IopParseDevice() 调用源检查测量试验逻辑,

————————————————————————————————————————————————————————————————

在上大器晚成篇小说中,我们已经看见 IopParseDevice() 怎么样对传播的 OPEN_PACKET
结构举办求证。假使 ObReferenceObjectByName()
的调用者没有分配并开始化第两个参数 ParseContext,而仅是简轻便单地传颂 “NULL”
,那么当调用链深刻到 IopParseDevice()
内部时,就能够因验证战败重回 C0000024(STATUS_OBJECT_TYPE_MISMATCH)。

咱俩根据源码中的暗指来追踪 OPEN_PACKET
结构究竟在哪分配的,如前所述,调用链
NtCreateFile->IoCreateFile()->IopCreateFile() 的结尾,也正是在
IopCreateFile() 内部,实际负责 OPEN_PACKET
的起头化。上面贴出的代码片段以 NT 5.2 版内核源码为样例:

 

新萄京娱乐场.2959.com 1

也正是说,我们从来复制 IopCreateFile() 中的 OPEN_PACKET
结构开头化部分逻辑就行了?

这里还也可能有八个主题素材,担任分配该组织体内核内部存款和储蓄器的例程 IopAllocateOpenPacket()
是三个宏,Visual C++ 贰零壹肆 中提交它是用 ExAllocatePoolWithTag()
定义的。那就好办了,在大家团结的驱动力源码中,增添相应定义就可以,如下图:

 

新萄京娱乐场.2959.com 2

 

————————————————————————————————————————————————————————————

因为 OPEN_PACKET
结构相像未有公开的文书档案来汇报,所以仍旧在大家的驱动力源码中用 
#include
包罗定义它的头文件,要么直接复制订义的那部分黏贴进来。很料定,前面一个相当的轻易——OPEN_PACKET
在基本源码的 “iomgr.h
中定义,而该头文件又嵌套满含了一群参差不齐的内核头文件,要理清那些嵌套包蕴关系很麻烦,何况最重大的是,其间有的头文件定义的数据类型会与驱动开辟中用的 “ntddk.h”
和“wdm.h”重复,引起编译器的抱怨。
于是一直在 “iomgr.h” 中寻觅字串
“typedef struct _OPEN_PACKET”,把找到的概念块拷贝进来就能够。

然而,OPEN_PACKET 结构中但是一个字段不是 “原生” 定义的——那就是“PDUMMY_FILE_OBJECT” 类型,必要蕴含别的头文件才不变成编写翻译器报错。

自个儿的施工方案是,直接把该字段的扬言所在行注释掉,下图突显了该字段具体的职分(在
iomgr.h” 中的行号),方便各位火速寻找:

 

新萄京娱乐场.2959.com 3

——————————————————————————————————————————————————————————————————

注意,NT 6.1 版内核在编写翻译时刻的 OPEN_PACKET 结构显明是未经 “恶意
改革的,所以编写翻译器为其 “sizeof(OPEN_PACKET)” 表达式总括 0x70
的值,而我们在团结的驱动中拿掉了 OPEN_PACKET
当中贰个字段使得编写翻译器为发挥式 “sizeof(OPEN_PACKET)” 预总结 0x58
的值(前边的调试阶段会申明),那会促成 “Size” 字段不是
IopParseDevice() 内部逻辑预期的 0x70,进而致使再次来到C0000024(STATUS_OBJECT_TYPE_MISMATCH)。

消除办法也十分轻松,大家的驱动中,不要依赖理编辑译时刻的精兵简政,直接把
Size” 字段的值硬编码为 0x70 不就好了?

正如图所示,你还只怕会注意到,笔者把 “Type” 字段的常量
“IO_TYPE_OPEN_PACKET” 改成了对应的数值,以保险黄金年代旦。

 

新萄京娱乐场.2959.com 4

 

除此以外,由于 IopAllocateOpenPacket() 等价于
ExAllocatePoolWithTag(),而后人常常重返泛型指针(“ PVOID ,亦即 
void * ”),
所以本人强制把它转型为与 “openPacket” 黄金时代致的档期的顺序。
临门一脚,“东风” 就在于调用 ObReferenceObjectByName()
时,为第八个参数字传送入“openPacket” 就可以,上海体育场面突显的很明亮了。

——————————————————————————————————————————————————————————————————

很不好的是,笔者把编写翻译出来的驱动放到设想机(Windows 7,基于 NT 6.1
版内核)里面动态加载测验,照旧不可能赢获得

“\Device\QQProtect” 相应的设施对象指针,ObReferenceObjectByName() 再次回到C0000024。

为了找寻故障原因,我在分配 OPEN_PACKET
逻辑的日前利用内联汇编加多了三个软中断 “__asm{ int 3; } 
”,宿主机器上运行水源调试器 kd.exe,笔者的开发银行参数疑似那样:

kd.exe -n -v -logo d:\virtual_machine_debugging.txt -y
SRV*C:\Symbols* -k
com:pipe,port=\\.\pipe\com_1,baud=115200,reconnect

 

参数 “logo” 钦定要把任何调节和测量检验进度的出口消息写入日志;

“-y”
内定符号文件的职位(机器指令中从未内核函数与变量的标识,所以调试器需求查找额外的标识以向客户体现人类可读的名号);
“-k” 参数钦定调节和测量检验类型为
命名管道模拟串口1”,Porter率数值越高,响应越快。

把重新编写翻译好的驱动放到虚构机中,在进级权限后的通令提醒符中实行
bcdedit.exe,启用调节和测量试验情势,那样重启虚构机后,就能够进去调节和测量检验格局(无需在运行进程中按下
F8 选择菜单)。

自己把团结的驱动实现存按需加载,相当于行使劳务调控管理器sc.exe)发出指令来动态加载和卸载,达成此功用的呼应批管理文件内容如下图,注意该文件要放在设想机中试行,“start=
demand” 注明通过 sc.exe 按需运维
;“binpath”
就是驱动文件存放的磁盘路线
,借使自身的驱动名称为hideprocess.sys,实行该批管理职分后,就在相关的注册表地点增添了风流浪漫项,以往只需在
cmd.exe 中实行 “sc.exe start/stop hideprocess” 就能够动态加卸载。

新萄京娱乐场.2959.com 5

 

依照上述措施加载时,就能自行触发大家设定好的软件断点,就能够在宿主机中检查设想机的基本空间。
别的还需注意一点:编写翻译驱动时的 “创设” 情形应该选取 Check
Build
,那样会大器晚成并生成同名称的标识文件,后缀为
.pdb”,进而调节和测验器能够展现我们协调驱动中的函数与变量名称,进步调试作用,如下图:

 

新萄京娱乐场.2959.com 6

——————————————————————————————————————————————————————————————————————

接触软件断点后,我们通常会用 “kv
命令查看栈回溯音信,它披表露大家的驱动入口点 DriverEntry() 是由 I/O
处理器的 IopLoadDriver() 调用的:

 

新萄京娱乐场.2959.com 7

栈的顶层函数 “ReferenceDeviceAndHookIRPdispatchRoutine+0x56
是本人增加软中断之处。推行 “r” 命令查看当前的 x86
通用寄放器状态,EIP 指向地址 0x8f4a3196 ,试行 “u
hideprocess!ReferenceDeviceAndHookIRPdispatchRoutine+0x56
L2”,反汇编输出的首先行地址就是 0x8f4a3196,与 EIP
的值适合;第二行是把叁个 16 进制值 “ 704F6F49h” 压栈,实际上它是
ASCII 字符 “pOoI” 的 16
进制编码,换言之,这是在通过内核栈传递 ExAllocatePoolWithTag()
的第三个参数(从右往左传递,请纪念以前的 IopAllocateOpenPacket()
宏定义那张图)。

————————————————————————————————————————————————————————————————

一而再接二连三按下 “t
单步试行,如下图所示,你能够观察,ExAllocatePoolWithTag()
的第贰个参数,分配的基石内部存款和储蓄器大小为 0x70
字节,因为自个儿在宏定义中硬编码了这么些值,实际不是用 sizeof(OPEN_PACKET)
表明式让编写翻译器计算;另一面,图中的 “dt” 命令也验证了它的轻重为
0x70 字节。

第二个传入的参数 “NonPagedPool
为不可换页池,其内的多寡不可能被换出物理内存,该常量对应的数值为 “0”:

新萄京娱乐场.2959.com 8

 

本人不想浪费时间在查看内核内存的抽成细节上,所以笔者按下 “p”,步过
ExAllocatePoolWithTag() 函数调用,接下去的 cmp/jne
汇编类别
对应源码中检查是还是不是成功分配了内部存款和储蓄器并用于 openPacket
指针,实际的施行结果是跳转到地址 0x8f4a31c6 ,对应源码中开端化
OPEN_PACKET 结构前三个字段的逻辑:

新萄京娱乐场.2959.com 9

接下来一直单步施行到调用 ObReferenceObjectByName()
前夕,在这里间我们要 “步入” 它的里边,实行故障排查,所以按下 “t
跟进,这里有三个小技巧,大家早已解析过 ObReferenceObjectByName()
的源码,知道它会调用比很多函数,何况大概知道难点出今后ObpLookupObjectName() 里面,所以指令
tc”能够追踪到每种函数调用处截止,再由客商决定是或不是跟进该函数内部。

那是本身的光明期望,但现实总是狂暴的,在本身跟踪到原子操作类别函数

nt!ExInterlockedPopEntrySList() 调用时,kd.exe
就卡住了,不可能继续追踪从今以后的调用链。从稍早的栈回溯新闻来看,与源码卯月大家预测的调用种类大约切合,只是不精通为什么在
nt!ObpAllocateObjectNameBuffer() 中,为了给传入的驱动对象名称
“\Device\QQProtect”
分配内核内部存款和储蓄器,调用 nt!ExInterlockedPopEntrySList(),而前面一个却爱莫能助追踪。。。。是设想机遭受的开始和结果,照旧原子操作类函数的不可分割性质?

 

新萄京娱乐场.2959.com 10

 ——————————————————————————————————————————————————————————————

讲一些废话,日常我们在栈回溯中看到的顶层表明行,有一个 “Args to Child”
项目,表示调用者传递给它的参数,可是最多也必须要展现前多个。
以下图为例子吗,传递给 nt!ExAllocatePoolWithTag()
的多少个参数(从左到右)就是00000000(NonPagedPool),00000070(作者硬编码的值),704f6f49(ASCII
字符串“pOoI”)
,同理,传递给 hideprocess!DriverEntry() 的第贰个参数
867c3550 是 _DRIVER_OBJECT 结构的地址,由I/O
管理器加载它时为它分配(注意与源码中 DriverEntry() 定义的大器晚成枚
_DRIVER_OBJECT 指针不相同,“Args to Child”

列出的数量一定于施行解引操作符 * 后的结果),第二个参数是
UNICODE_STRubiconING 结构之处,对应源码定义中的后生可畏枚 _UNICODE_STEnclaveING
指针,该组织中存储的是大家驱动在注册表中的完整路线:

 

新萄京娱乐场.2959.com 11
——————————————————————————————————————————————————————————————————

一句话来讲 ,基于上述理由我力无法支继续跟进到 ObpLookupObjectName()
里面查看它是否施行了 IopParseDevice()
回调,进而不可能分明到底怎么后面一个再次回到 C0000024。

本人想或者是因为基础源码版本的转移,导致相关例程的推断逻辑也不相似了,无法依赖前少年老成版源码的逻辑来编排揣度运转在后生机勃勃版内核上的驱动。
其实建设方案只怕有个别,相比较花时间而已,便是运用 “u” 指令反汇编
ObpLookupObjectName() 伊始处对应的机器指令,再反编写翻译成相同的 C 伪码,与
NT 5.2
版内核源码相比较,寻找里面改换之处,但那是二个费时费劲的劳作,且收入甚微,还比不上直接在互联网络搜释出的
NT 6.1 版内核源码,恐怕附近的本子,再想想绕过的办法。

顺带说一下,根据 A 设备名获得 A 设备对象的指针,然后把
rootkit/本人驱动创立的黑心设备 attach 到 A
设备所在的配备栈,进而阻碍检查通过 A 设备的 IRP
内数据。。。。这种情势已经相比较过时了,因为以往反病毒软件的基本情势组件也会检讨那些设备栈,搜索别的相称特征码的恶心设备,再者,内核调节和测量检验器的
“!devstack”
命令非常轻便遍历揭破出给定设备所在的装置栈内容,被普及用于Computer调查取证中,从
rootkit 的要紧目的——完结隐身——的角度来看, attach
到设备栈就不是叁个好标准。

相反,通过 ObReferenceObjectByName()
总是能够收获驱动对象的指针,进而能够 hook 该驱动的 IRP
分发例程,这种手法掩没性超级高,并且不易于被检查测量检验出来。

继续的博文将研讨怎么着将这种技巧用在 rootkit
中,同有时间适应当下盛行的对称多管理器(SMP)碰到。

————————————————————————————————————————————————————————————————

Rootkit 宗旨技巧之绕过
IopParseDevice() 调用源检查评定逻辑,
—————————————————————————————————…

新萄京娱乐场.2959.com 10

参数
“logo” 钦定要把全部调试进程的输出音信写入日志;

一言以蔽之,基于上述理由笔者力所不如继续跟进到 ObpLookupObjectName()
里面查看它是还是不是进行了 IopParseDevice()
回调,进而不能明确到底怎么前面一个再次来到 C0000024。

 

然而,OPEN_PACKET
结构中仅仅叁个字段不是 “原生” 定义的——那正是 “PDUMMY_FILE_OBJECT”
类型,供给饱含别的头文件才不形成编写翻译器报错。

那是小编的美好期望,但具体总是严酷的,在自己追踪到原子操作类别函数

接触软件断点后,大家日常会用
kv” 命令查看栈回溯音讯,它披表露大家的驱动入口点 DriverEntry() 是由
I/O 管理器的 IopLoadDriver() 调用的:

十分不幸的是,作者把编译出来的驱动放到虚构机(Windows
7,基于 NT 6.1 版内核)里面动态加载测量检验,依然不恐怕获得到

新萄京娱乐场.2959.com 5

——————————————————————————————————————————————————————————————————

以下图为例子吗,传递给 nt!ExAllocatePoolWithTag()
的四个参数(从左到右)正是00000000(NonPagedPool),00000070(笔者硬编码的值),704f6f49(ASCII
字符串“pOoI”)
,同理,传递给 hideprocess!DriverEntry() 的第贰个参数
867c3550 是 _DRIVER_OBJECT 结构的地点,由I/O
管理器加载它时为它分配(注意与源码中 DriverEntry() 定义的生机勃勃枚
_DRIVER_OBJECT 指针差异,“Args to
Child”

——————————————————————————————————————————————————————————————————

自身想只怕是因为根本源码版本的调换,导致相关例程的决断逻辑也不均等了,无法依据前生龙活虎版源码的逻辑来编排估量运维在后意气风发版内核上的驱动。

第四个传入的参数
NonPagedPool
为不可换页池,其内的数目不可能被换出物理内部存款和储蓄器,该常量对应的数值为
“0”:

新萄京娱乐场.2959.com 2

此处还应该有三个难点,担负分配该组织体内核内部存储器的例程 IopAllocateOpenPacket()
是一个宏,Visual C++ 二〇一六 中提交它是用 ExAllocatePoolWithTag()
定义的。那就好办了,在大家和好的驱动力源码中,增加相应定义就能够,如下图:

在上生机勃勃篇作品中,大家曾经见到IopParseDevice() 怎样对传播的 OPEN_PACKET 结构进行求证。倘诺ObReferenceObjectByName() 的调用者没有分配并开端化第七个参数
ParseContext,而仅是简约地流传 “NULL” ,那么当调用链深刻到
IopParseDevice()
内部时,就能因验证退步重回 C0000024(STATUS_OBJECT_TYPE_MISMATCH)。

顺便说一下,依据 A 设备名获得 A 设备对象的指针,然后把
rootkit/本人驱动创制的黑心设备 attach 到 A
设备所在的设施栈,从而阻碍检查通过 A 设备的 IRP
内数据。。。。这种措施已经比较过时了,因为后天反病毒软件的根本形式组件也会检讨这几个器具栈,找寻其他相称特征码的恶意设备,再者,内核调试器的
“!devstack”
命令相当轻松遍历揭穿出给定设备所在的设施栈内容,被周围用于Computer考查取证中,从
rootkit 的显要目的——落成隐身——的角度来看, attach
到器具栈就不是贰个好标准。

实则应用方案也许有个别,比较花时间而已,便是选择 “u” 指令反汇编
ObpLookupObjectName() 起初处对应的机器指令,再反编写翻译成形似的 C 伪码,与
NT 5.2
版内核源码相比,找寻当中改换的地点,但那是三个费时费劲的干活,且收入甚微,还不及直接在互连网络搜释出的
NT 6.1 版内核源码,或然接近的本子,再思索绕过的议程。

新萄京娱乐场.2959.com 1

“-y”
钦命符号文件的地方(机器指令中绝非内核函数与变量的号子,所以调节和测量检验器要求查找额外的标志以向客商体现人类可读的名目);
“-k”
参数钦命调节和测量检验类型为
取名管道模拟串口1”,Porter率数值越高,响应越快。

 ——————————————————————————————————————————————————————————————

 

————————————————————————————————————————————————————————————————

自己不想浪费时间在查看内核内部存款和储蓄器的分红细节上,所以自个儿按下
p”,步过 ExAllocatePoolWithTag() 函数调用,接下去的 cmp/jne
汇编体系
对应源码中反省是还是不是成功分配了内部存款和储蓄器并用于 openPacket
指针,实际的实施结果是跳转到地址 0x8f4a31c6 ,对应源码中初阶化
OPEN_PACKET 结构前三个字段的逻辑:

 

——————————————————————————————————————————————————————————————————————

列出的数目一定于履行解引操作符 *
后的结果
),首个参数是 UNICODE_ST途锐ING
结构的地址,对应源码定义中的风华正茂枚 _UNICODE_ST福特ExplorerING
指针,该组织中蕴藏的是大家驱动在注册表中的完整路线:

连绵起伏按下
t” 单步试行,如下图所示,你能够看到,ExAllocatePoolWithTag()
的第4个参数,分配的木本内存大小为 0x70
字节,因为自个儿在宏定义中硬编码了那几个值,并不是用 sizeof(OPEN_PACKET)
表明式让编写翻译器计算;其他方面,图中的 “dt” 命令也认证了它的高低为
0x70 字节。

 

新萄京娱乐场.2959.com 9

————————————————————————————————————————————————————————————————

 

依据上述办法加载时,就能够自动触发大家设定好的软件断点,就可以在宿主机中检查虚构机的基石空间。
除此以外还需注意一点:编写翻译驱动时的
“营造” 情形应该选用 Check
Build
,那样会意气风发并生成同名称的号子文件,后缀为
.pdb”,进而调节和测量检验器能够呈现我们协和驱动中的函数与变量名称,提升调节和测量检验作用,如下图:

发表评论

电子邮件地址不会被公开。 必填项已用*标注