----------- Rootkit 主旨工夫之绕过 IopParseDevice() 调用源检查实验逻辑 ---------------

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

在上一篇小说中,大家曾经见到IopParseDevice() 怎么着对传播的 OPEN_PACKET 结构进行求证。如若ObReferenceObjectByName() 的调用者未有分配并开始化第二个参数 ParseContext,而仅是粗略地扩散 “NULL” ,那么当调用链深远到 IopParseDevice() 内部时,就能够因验证失利重临 C0000024(STATUS_OBJECT_TYPE_MISMATCH)。

顺手说一下,遵照 A 设备名获得 A 设备对象的指针,然后把 rootkit/本身驱动成立的恶心设备 attach 到 A 设备所在的配备栈,进而阻碍检查通过 A 设备的 IRP 内数据。。。。这种艺术已经相比过时了,因为未来反病毒软件的基础格局组件也会检查这么些设施栈,寻觅别的相称特征码的黑心设备,再者,内核调试器的 “!devstack” 命令很轻便遍历揭发出给定设备所在的器材栈内容,被布满用于Computer考察取证中,从 rootkit 的重大目的——达成隐身——的角度来看, attach 到设备栈就不是二个好规范。

以下图为例子吗,传递给 nt!ExAllocatePoolWithTag() 的八个参数(从左到右)就是00000000(NonPagedPool),00000070(作者硬编码的值),704f6f49(ASCII 字符串“pOoI”),同理,传递给 hideprocess!DriverEntry() 的率先个参数 867c3550 是 _DRIVER_OBJECT 结构的地址,由I/O 管理器加载它时为它分配(注意与源码中 DriverEntry() 定义的一枚 _DRIVER_OBJECT 指针区别,“Args to Child”

nt!ExInterlockedPopEntrySList() 调用时,kd.exe 就卡住了,不能够持续跟踪此后的调用链。从稍早的栈回溯音讯来看,与源码阳节我们估计的调用连串大约切合,只是不知底为什么在 nt!ObpAllocateObjectNameBuffer() 中,为了给传入的驱动对象名称 “DeviceQQProtect” 分配内核内部存款和储蓄器,调用 nt!ExInterlockedPopEntrySList(),而后人却敬敏不谢追踪。。。。是虚构机情状的来由,如故原子操作类函数的不可分割性质?

很倒霉的是,笔者把编写翻译出来的驱动放到虚构机(Windows 7,基于 NT 6.1 版内核)里面动态加载测验,如故无法取获得

为了寻觅故障原因,作者在分配 OPEN_PACKET 逻辑的前面利用内联系汇率编增多了二个软中断 “__asm{ int 3; }  ”,宿主机器上运营水源调节和测量检验器 kd.exe,小编的运营参数疑似那样:

遵照上述措施加载时,就能够活动触发大家设定好的软件断点,就能够在宿主机中反省虚构机的基业空间。
除此以外还需注意一点:编写翻译驱动时的 “创设” 蒙受应该选用 Check Build,那样会一并生成同名称的记号文件,后缀为 “.pdb”,进而调节和测验器能够显得大家温馨驱动中的函数与变量名称,进步调节和测验作用,如下图:

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

然而,OPEN_PACKET 结构中单唯三个字段不是 “原生” 定义的——这正是 “PDUMMY_FILE_OBJECT” 类型,需求包涵其余头文件才不产生编写翻译器报错。

“-y” 钦定符号文件的岗位(机器指令中向来不内核函数与变量的标志,所以调节和测量检验器须要查找额外的标志以向客商展现人类可读的名号);
“-k” 参数钦赐调节和测量试验类型为 “取名管道模拟串口1”,Porter率数值越高,响应越快。

图片 1

 

图片 2

 

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

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

那是本身的光明期望,但实际总是残暴的,在自家追踪到原子操作类别函数

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

如下图所示,你还有恐怕会注意到,小编把 “Type” 字段的常量 “IO_TYPE_OPEN_PACKET” 改成了相应的数值,以确认保证一旦。

列出的多寡一定于试行解引操作符 * 后的结果),第贰个参数是 UNICODE_ST奥迪Q3ING 结构的地点,对应源码定义中的一枚 _UNICODE_STKoleosING 指针,该协会中蕴藏的是我们驱动在注册表中的完整路线:

本身的应用方案是,直接把该字段的扬言所在行注释掉,下图呈现了该字段具体的地方(在 “iomgr.h” 中的行号),方便各位连忙寻找:

解决办法也极粗略,我们的驱动中,不要依据理编辑译时刻的计算,直接把 “Size” 字段的值硬编码为 0x70 不就好了?

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

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

讲一些废话,日常大家在栈回溯中来看的顶层表达行,有一个 “Args to Child” 项目,表示调用者传递给它的参数,可是最多也不得不展现前五个。

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

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

把重新编写翻译好的驱动放到设想机中,在提高权限后的下令提醒符中实施 bcdedit.exe,启用调试格局,那样重启设想机后,就可以进去调节和测验格局(没有供给在运维进程中按下 F8 接纳菜单)。

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

 

 

别的,由于 IopAllocateOpenPacket() 等价于 ExAllocatePoolWithTag(),而后人经常再次回到泛型指针(“ PVOID ,亦即 void * ”),
于是小编强制把它转型为与 “openPacket” 一致的项目。
齐全,“东风” 就在于调用 ObReferenceObjectByName() 时,为第三个参数字传送入“openPacket” 就能够,上海教室突显的很通晓了。

 

图片 3

参数 “logo” 钦命要把任何调节和测量试验进程的出口新闻写入日志;

留意,NT 6.1 版内核在编写翻译时刻的 OPEN_PACKET 结构明显是未经 “恶意” 修改的,所以编写翻译器为其 “sizeof(OPEN_PACKET)” 表明式计算 0x70 的值,而大家在友好的驱动中拿掉了 OPEN_PACKET 当中七个字段使得编写翻译器为表达式 “sizeof(OPEN_PACKET)” 预总计 0x58 的值(前面包车型客车调节和测验阶段会证明),那会变成 “Size” 字段不是 IopParseDevice() 内部逻辑预期的 0x70,从而导致重返C0000024(STATUS_OBJECT_TYPE_MISMATCH)。

图片 4

那边还恐怕有一个标题,担任分配该组织体内核内存的例程 IopAllocateOpenPacket() 是三个宏,Visual C++ 2016 中付出它是用 ExAllocatePoolWithTag() 定义的。那就好办了,在我们和好的驱动力源码中,加多相应定义就可以,如下图:

 

相反,通过 ObReferenceObjectByName() 总是能够得到驱动对象的指针,进而能够 hook 该驱动的 IRP 分发例程,这种手段掩瞒性极高,并且不轻松被检查实验出来。

图片 5

 

持续的博文将探讨怎么着将这种本事用在 rootkit 中,同一时间适应当前风靡的扬长避短多处理器(SMP)意况。

图片 6

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

也正是说,我们直接复制 IopCreateFile() 中的 OPEN_PACKET 结构伊始化部分逻辑就行了?

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

自个儿想或许是因为基础源码版本的更换,导致相关例程的剖断逻辑也区别了,无法依赖前一版源码的逻辑来编排猜测运转在后一版内核上的驱动。

图片 7

图片 8

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

 

 

 

因为 OPEN_PACKET 结构同样未有当面包车型地铁文书档案来描述,所以如故在大家的驱动力源码中用  “#include” 包括定义它的头文件,要么直接复制订义的那有些黏贴进来。很显明,前面一个比较轻便——OPEN_PACKET 在基础源码的 “iomgr.h” 中定义,而该头文件又嵌套富含了一批杂七杂八的内核头文件,要理清这一个嵌套富含关系很麻烦,何况最关键的是,里面有的头文件定义的数据类型会与驱动开荒中用的 “ntddk.h” 和“wdm.h”重复,引起编译器的埋怨。故而平昔在 “iomgr.h” 中寻找字串 “typedef struct _OPEN_PACKET”,把找到的概念块拷贝进来就可以。

 

图片 9

骨子里应用方案大概某些,相比较花时间而已,正是使用 “u” 指令反汇编 ObpLookupObjectName() 初阶处对应的机器指令,再反编写翻译成类似的 C 伪码,与 NT 5.2 版内核源码相比,搜索个中改造的地点,但那是一个费时费劲的干活,且收入甚微,还比不上直接在网络络搜释出的 NT 6.1 版内核源码,或许临近的本子,再想想绕过的办法。

简单来讲,基于上述理由笔者一点战略也施展不出继续跟进到 ObpLookupObjectName() 里面查看它是或不是推行了 IopParseDevice() 回调,进而不可能鲜明到底为什么前面一个再次来到 C0000024。

图片 10

 

持续按下 “t” 单步实施,如下图所示,你能够看出,ExAllocatePoolWithTag() 的第二个参数,分配的基行业内部部存款和储蓄器大小为 0x70 字节,因为本身在宏定义中硬编码了那么些值,而不是用 sizeof(OPEN_PACKET) 表达式让编写翻译器总计;另一方面,图中的 “dt” 命令也表明了它的高低为 0x70 字节。

我们依照源码中的暗示来追踪OPEN_PACKET 结构毕竟在哪分配的,如前所述,调用链 NtCreateFile->IoCreateFile()->IopCreateFile() 的最后,也正是在 IopCreateFile() 内部,实际担负 OPEN_PACKET 的初叶化。上边贴出的代码片段以 NT 5.2 版内核源码为样例:

图片 11
——————————————————————————————————————————————————————————————————

 

小编把本人的驱动实现存按需加载,也便是使用服务调整管理器sc.exe)发出指令来动态加载和卸载,达成此功用的料理批管理公事内容如下图,注意该公文要放在虚构机中实行,“start= demand” 评释通过 sc.exe 按需运转;“binpath” 就是驱动文件贮存的磁盘路线,假诺自身的驱动名称为hideprocess.sys,试行该批管理义务后,就在连锁的注册表地方增添了一项,未来只需在 cmd.exe 中推行 “sc.exe start/stop hideprocess” 就可以看到动态加卸载。

“DeviceQQProtect” 相应的配备对象指针,ObReferenceObjectByName() 重返 C0000024。

接下来直白单步实践到调用 ObReferenceObjectByName() 前夕,在这里地大家要 “步入” 它的个中,进行故障逐个审查,所以按下 “t” 跟进,这里有三个小本事,大家曾经解析过 ObReferenceObjectByName() 的源码,知道它会调用很多函数,并且差相当的少理解难题应时而生在 ObpLookupObjectName() 里面,所以指令 “tc”能够跟踪到种种函数调用处停止,再由顾客决定是不是跟进该函数内部。

本文由2020欧洲杯官方投注-2020欧洲杯官方投注网址发布于win7,转载请注明出处:----------- Rootkit 主旨工夫之绕过 IopParseDevice() 调用源检查实验逻辑 ---------------

相关阅读