2023南极动物厂高校决赛之决赛附加题
2023-5-21 18:1:44 Author: 看雪学苑(查看原文) 阅读量:26 收藏


前言

没有参赛,看了下题目,感觉不太难,附加题比较有意思,发个WP。
 
先说结果:通过置位*MmTrackPtes标志位,让内核调用MiInsertPteTracker,把Length存储到*MiDeadPteTrackerSListHead链表,遍历检测这个链表中的Length是不是等于0x2023然后蓝屏。并且同时要置位*MiTrackPtesAborted为1,不然在置位*MmTrackPtes后会蓝屏。
 
备注:带*的(WRK里面叫这个但是pdb里面是去除了这个符号名称的)


过程

题目:
 
题目分析
 
1.ida打开ring3的程序先看看做了啥。
 
 
2.接着打开ring0的程序看看他做了啥。
 
 
非常好基本上全部都被tvm0保护了。
 
3.综上考虑下出题人思路并验证。
 
驱动被全v了,但是导入表并没有被保护。出题人大概是想考察黑盒分析。因为这么短的时间考察去虚拟化,显然是不太符合要求的。
 
先来验证下常规思路,既然在驱动加载后,ring3程序一打开就蓝屏。题目说检测读功能,考虑句柄表。
 
so,验证下...
 
a.在ReadProccesMemory打断点,并不蓝屏,所以在CreateProcessA以后拿到了句柄以后,依然不会蓝屏,排除句柄表。
 
b.根据a很明显问题可以定位在ReadProcessMemory,观察ring3的程序,很明显的地方就是这个0x2023了罗。
 
c.让我们来验证下b,把这个0x2023改掉试试。
 
d.非常好,根本不蓝。
 
e.思路很清晰,大概率检测的Length。目标预期:查找有无全局变量存储了Length,并且大概率这个全局变量是个数组、链表等。
 
f.打开Ntoskrnl.i64 来到NtReadVirtualMemory观察Length的去向。
 
 
走进了MmCopyVirtualMemory,在这个函数的内部发现Length被存到了一个临时的MDL结构里面。
 
 
所以我们继续跟踪MemoryDescriptorList的去向看看是谁获取了结构体中的ByteCount或者是Size
 
g.
 
 
 
只有这几个函数MmProbeAndLockPagesMmMapLockedPagesSpecifyCacheMmUnlockPages。我们一个一个来看看有什么奥秘所在。
 
g.1.MmProbeAndLockPages
先来看看函数内部。
 
 
非常好拿了我们的ByteCount,接着我们来看看MiProbeAndLockPrepare函数内部。
 
 
总的来说这个函数里面并没有直接存储ByteCount这个玩意,而是跟别的加加减减再搞一块。所以先放一边。
 
g.2.MmMapLockedPagesSpecifyCache
 
函数内部发现好几个函数引用了MemoryDescriptorList。
 
思路大概跟g.1一样不细说了,没有直接存储ByteCout或者Size的函数直接先放一边,到时候回过头去看。
 
g.2.1
 
但是在MiInsertPteTracker我们发现了奥秘所在。
 
 
接下来我们观察v8的在哪里来的就完事了。并且根据WRK我们可以知道v8是个什么玩意了。
 
 
 
很明显就是PTE_TRACKED这个结构。
typedef struct _PTE_TRACKER {
LIST_ENTRY ListEntry;
PMDL Mdl;
PFN_NUMBER Count;
PVOID SystemVa;
PVOID StartVa;
ULONG Offset;
ULONG Length;
PFN_NUMBER Page;
struct {
ULONG IoMapping: 1;
ULONG Matched: 1;
ULONG CacheAttribute : 2;
ULONG Spare : 28;
};
PVOID CallingAddress;
PVOID CallersCaller;
} PTE_TRACKER, *PPTE_TRACKER;
`
与预想中的非常符合。ByteCount被直接存储到PTE_TRACKER::Length里面了。
 
g2.2
 
而且非常明显是从全局变量MiDeadPteTrackerSListHead里面拿到的v8。
 
 
g2.3
 
既然上述代码逻辑完全符合我们的目标预期,我们来看看在什么情况下,MmMapLockedPagesSpecifyCache内部会调用MiInsertPteTracker。
 
 
噔噔噔~,发现在dword_140CFB17C(MmTrackPtes)为1的情况下会MiInsertPteTracker。
 
g2.4
 
我们来双机看看这个标志位。
 

 
很不幸,系统默认情况下,这个标志位为0。所以在默认情况下,压根不走这里。
 
那意思就是赛题的驱动把这个标志位改了?我们来验证一波。
 
在这里下个写入断点,然后加载赛题的驱动。
 
ba w1 fffff8020617318c(这是标志位地址,在上图)然后拉起驱动。
 
 
芜湖~,断在NotepadProtect.sys里面。
 
至此分析完毕,其他的还分析个锤子。(其实还有)


1.综合0x02整个分析过程,绕过检测的思路已经非常简单了。给dword_140CFB17C(MmTrackPtes)标志位置0,长度就不会再往全局数组里面插入了。
 
2.模拟他的检测思路就是,给dword_140CFB17C(MmTrackPtes)标志位置1,然后遍历*MiDeadPteTrackerSListHead中的长度是不是等于0x2023。
 
很不幸的是,在我们手动置位dword_140CFB17C(MmTrackPtes)以后立马蓝屏了。
 
 
我们来分析下为什么他不蓝屏,我们会蓝屏,先看看调用栈。
 
 
Ok,在函数里面主动蓝屏的,我们在WRK定位到相应位置看看。
 
 
看来我们还需要给MiTrackPtesAborted置1。
 
3.思路很清晰。
 
结论:通过置位*MmTrackPtes标志位,让内核调用MiInsertPteTracker,把Length存储到*MiDeadPteTrackerSListHead链表,遍历检测这个链表中的Length是不是等于0x2023然后蓝屏。并且同时要置位*MiTrackPtesAborted为1,不然在置位*MmTrackPtes后会蓝屏。
就是大概看了一眼,代码没写。代码没什么技术含量,就是特征定位几个未导出的全局变量,然后遍历自己照着wrk写一遍就行。
总的来说,在加了tvm的情况下,只要思路清晰,就是钻一,还是能比较快速的解完这道题的。而且耗费的时间也并不长。
什么?你跟我说看完上面还是不会做?那把tvm去虚拟化了你总会做了吧?
附件是去虚拟化以后的
NotepadProtect.sys的ida分析文件。
(附件被吞了 看评论区~)

1.https://github1s.com/zhuhuibeishadiao/ntoskrnl (WRK

2.不愿公开姓名的xxx提供的去虚拟化sys。

看雪ID:淡然他徒弟

https://bbs.kanxue.com/user-home-620278.htm

*本文为看雪论坛优秀文章,由 淡然他徒弟 原创,转载请注明来自看雪社区

# 往期推荐

1、在 Windows下搭建LLVM 使用环境

2、深入学习smali语法

3、安卓加固脱壳分享

4、Flutter 逆向初探

5、一个简单实践理解栈空间转移

6、记一次某盾手游加固的脱壳与修复

球分享

球点赞

球在看


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458504809&idx=1&sn=6fd2aa2bbcf40f24244dd56569bdf82b&chksm=b18efee386f977f540bf33ef1a7daab021805eae61709adb391e364886a7a5a5cf78151d5d01#rd
如有侵权请联系:admin#unsafe.sh