透析挖洞神器mona.py插件新特性
这里不得不用简单的篇幅介绍一下mona.py。这是由corelan team整合的一个可以自动构造Rop Chain而且集成了metasploit计算偏移量功能的强大挖洞辅助插件,详情可以参照他们的官方网站。
当我在准备Derbycon的高级开发课程之前,还一直在玩IE的原始堆分配。其中有些问题给我带来了挫折(至少说,让我的整个研究进度都慢了许多)。反观,这也提高了我快速识别对象的能力,也是一个不错的机遇。毕竟,我是在尝试找一个包含任意数据的对象,或者指针,这做起来并不那么容易!
我决定给mona.py插件增加一些新的特性,以便让大家可以更快的寻找到感兴趣的对象。这些新特性仅仅在WinDBG下有效。
dumpobj (do)
这第一个新特性就是dumpobj。这条mona.py命令会转储对象中的内容,并提供内容中的有用信息。该命令有以下几个参数:
Usage of command 'dumpobj' : ----------------------------- Dump the contents of an object. Arguments: -a <address> : Address of object -s <number> : Size of object (default value: 0x28 or size of chunk) Optional arguments: -l <number> : Recursively dump objects -m<number> : Size forrecursive objects (default value: 0x28)
正如你看到的帮助信息,我们至少需要提供两个参数。
-a <address> : 开始的位置(对象的地址。当然,这个你可以自己随意定义)
-s <number> :对象的大小,如果你指定-s参数,mona会尝试自己定义一个大小。如果定义失败,那么mona会对这个对象转储0×28字节。
此外,你也可以告诉mona转储一些链接对象。-l参数后跟上一个数字,这个数字代表了递归转储的等级。由于性能的原因,会限制输出的大小,链接对象中只有第一个0×28字节的内容会输出给用户。当然,你也可以使用-m参数,看到更多内容。
在WinDBG中转储对象中的内容很繁琐。在某些情况下,dds/dc命令力度还是不够的,还需要做一些额外的工作才能够进一步分析这个对象和可选对象。
让我们来看看下面这个例子,假设我们在0x023a1bc0有一个0×78字节的对象。我们可以使用WinDBG命令转储这个对象中的内容。
0:001> dds 0x023a1bc0 L 0x78/4 023a1bc0 023a1d30 023a1bc4 023a1818 023a1bc8 00000000 023a1bcc 023a1d3c 023a1bd0 023a1824 023a1bd4 baadf00d 023a1bd8 00020000 023a1bdc 00000001 023a1be0 00160014 023a1be4 023a1a38 023a1be8 013a0138 023a1bec 023a1a68 023a1bf0 00000000 023a1bf4 00000001 023a1bf8 023a18a8 023a1bfc 00000000 023a1c00 00000000 023a1c04 00000007 023a1c08 00000007 023a1c0c 023a18d0 023a1c10 00000000 023a1c14 00000000 023a1c18 00000000 023a1c1c 00000000 023a1c20 00000000 023a1c24 00000000 023a1c28 00000000 023a1c2c 00000000 023a1c30 00000000 023a1c34 00000000 0:001> dc 0x023a1bc0 L 0x78/4 023a1bc0 023a1d30 023a1818 00000000 023a1d3c 0.:...:.....<.:. 023a1bd0 023a1824 baadf00d 00020000 00000001 $.:............. 023a1be0 00160014 023a1a38 013a0138 023a1a68 ....8.:.8.:.h.:. 023a1bf0 00000000 00000001 023a18a8 00000000 ..........:..... 023a1c00 00000000 00000007 00000007 023a18d0 ..............:. 023a1c10 00000000 00000000 00000000 00000000 ................ 023a1c20 00000000 00000000 00000000 00000000 ................ 023a1c30 00000000 00000000 ........
Nice!我们可以看到很多东西—似乎是指针的值,nulls,以及一些垃圾数据。
使用mona,我们可以转储相同的对象,mona会尝试在对象中收集更多有关dword的信息。
0:001> !py mona do -a 0x023a1bc0 Hold on... [+] No size specified, checking if address is part of known heap chunk Address found in chunk 0x023a1bb8, heap 0x00240000, (user)size 0x78 ---------------------------------------------------- [+] Dumping object at 0x023a1bc0, 0x78 bytes [+] Preparing output file 'dumpobj.txt' - (Re)setting logfile c:/logs/HeapAlloc2/dumpobj.txt [+] Generating module info table, hang on... - Processing modules - Done. Let's rock 'n roll. >> Object at 0x023a1bc0 (0x78 bytes): Offset Address Contents Info ------ ------- -------- ----- +00 0x023a1bc0 | 0x023a1d30 (Heap) ptr to ASCII '0::' +04 0x023a1bc4 | 0x023a1818 (Heap) ptr to ASCII ':' +08 0x023a1bc8 | 0x00000000 +0c 0x023a1bcc | 0x023a1d3c (Heap) ptr to 0x77e46464 : ADVAPI32!g_CodeLevelObjTable+0x4 +10 0x023a1bd0 | 0x023a1824 (Heap) ptr to ASCII ':' +14 0x023a1bd4 | 0xbaadf00d +18 0x023a1bd8 | 0x00020000 = UNICODE ' ' +1c 0x023a1bdc | 0x00000001 +20 0x023a1be0 | 0x00160014 = UNICODE '' +24 0x023a1be4 | 0x023a1a38 (Heap) ptr to UNICODE 'Basic User' +28 0x023a1be8 | 0x013a0138 (Heap) ptr to ASCII 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...' +2c 0x023a1bec | 0x023a1a68 (Heap) ptr to UNICODE 'Allows programs to execute as a user that does not have Administrator or Power User access rights, but can still access resouces accessible by normal users.' +30 0x023a1bf0 | 0x00000000 +34 0x023a1bf4 | 0x00000001 +38 0x023a1bf8 | 0x023a18a8 +3c 0x023a1bfc | 0x00000000 +40 0x023a1c00 | 0x00000000 +44 0x023a1c04 | 0x00000007 +48 0x023a1c08 | 0x00000007 +4c 0x023a1c0c | 0x023a18d0 (Heap) ptr to ASCII ' :H:p:' +50 0x023a1c10 | 0x00000000 +54 0x023a1c14 | 0x00000000 +58 0x023a1c18 | 0x00000000 +5c 0x023a1c1c | 0x00000000 +60 0x023a1c20 | 0x00000000 +64 0x023a1c24 | 0x00000000 +68 0x023a1c28 | 0x00000000 +6c 0x023a1c2c | 0x00000000 +70 0x023a1c30 | 0x00000000 +74 0x023a1c34 | 0x00000000 [+] This mona.py actiontook 0:00:00.579000
很显然,对象中的某些值指向了字符串(ASCII and Unicode),其他的似乎指向了另外一个对象(ADVAPI32!g_CodeLevelObjTable+0×4)。这个看起来是不是要比使用dds/dc命令更方便呢?其实,我们还可以做得更好,我们还可以通知mona自动打印链接对象。接下来,我们再次使用mona命令并带上-L参数看看效果吧。
0:001> !py mona do -a 0x023a1bc0 -l 1 Hold on... [+] No size specified, checking if address is part of known heap chunk Address found in chunk 0x023a1bb8, heap 0x00240000, (user)size 0x78 ---------------------------------------------------- [+] Dumping object at 0x023a1bc0, 0x78 bytes [+] Also dumping up to 1 levels deep, max size of nested objects: 0x28 bytes [+] Preparing output file 'dumpobj.txt' - (Re)setting logfile c:/logs/HeapAlloc2/dumpobj.txt [+] Generating module info table, hang on... - Processing modules - Done. Let's rock 'n roll. >> Object at 0x023a1bc0 (0x78 bytes): Offset Address Contents Info ------ ------- -------- ----- +00 0x023a1bc0 | 0x023a1d30 (Heap) ptr to ASCII '0::' +04 0x023a1bc4 | 0x023a1818 (Heap) ptr to ASCII ':' +08 0x023a1bc8 | 0x00000000 +0c 0x023a1bcc | 0x023a1d3c (Heap) ptr to 0x77e46464 : ADVAPI32!g_CodeLevelObjTable+0x4 +10 0x023a1bd0 | 0x023a1824 (Heap) ptr to ASCII ':' +14 0x023a1bd4 | 0xbaadf00d +18 0x023a1bd8 | 0x00020000 = UNICODE ' ' +1c 0x023a1bdc | 0x00000001 +20 0x023a1be0 | 0x00160014 = UNICODE '' +24 0x023a1be4 | 0x023a1a38 (Heap) ptr to UNICODE 'Basic User' +28 0x023a1be8 | 0x013a0138 (Heap) ptr to ASCII 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...' +2c 0x023a1bec | 0x023a1a68 (Heap) ptr to UNICODE 'Allows programs to execute as a user that does not have Administrator or Power User access rights, but can still access resouces accessible by normal users.' +30 0x023a1bf0 | 0x00000000 +34 0x023a1bf4 | 0x00000001 +38 0x023a1bf8 | 0x023a18a8 (Heap) ptr to 0x00000101 : +3c 0x023a1bfc | 0x00000000 +40 0x023a1c00 | 0x00000000 +44 0x023a1c04 | 0x00000007 +48 0x023a1c08 | 0x00000007 +4c 0x023a1c0c | 0x023a18d0 (Heap) ptr to ASCII ' :H:p:' +50 0x023a1c10 | 0x00000000 +54 0x023a1c14 | 0x00000000 +58 0x023a1c18 | 0x00000000 +5c 0x023a1c1c | 0x00000000 +60 0x023a1c20 | 0x00000000 +64 0x023a1c24 | 0x00000000 +68 0x023a1c28 | 0x00000000 +6c 0x023a1c2c | 0x00000000 +70 0x023a1c30 | 0x00000000 +74 0x023a1c34 | 0x00000000 >> Object at 0x023a1d3c (0x28 bytes): Offset Address Contents Info ------ ------- -------- ----- +00 0x023a1d3c | 0x77e46464 ADVAPI32!g_CodeLevelObjTable+0x4 +04 0x023a1d40 | 0x023a1bcc (Heap) ptr to ASCII '<:$:' +08 0x023a1d44 | 0xbaadf00d +0c 0x023a1d48 | 0x00040000 = UNICODE ' ' +10 0x023a1d4c | 0x00000101 +14 0x023a1d50 | 0x001a0018 = UNICODE '' +18 0x023a1d54 | 0x023a1c50 (Heap) ptr to UNICODE 'Unrestricted' +1c 0x023a1d58 | 0x0090008e (Heap) ptr to ASCII 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...' +20 0x023a1d5c | 0x023a1c88 (Heap) ptr to UNICODE 'Software access rights are determined by the access rights of the user.' +24 0x023a1d60 | 0x00000000 >> Object at 0x023a18a8 (0x28 bytes): Offset Address Contents Info ------ ------- -------- ----- +00 0x023a18a8 | 0x00000101 +04 0x023a18ac | 0x05000000 +08 0x023a18b0 | 0x0000000a +0c 0x023a18b4 | 0xabababab +10 0x023a18b8 | 0xabababab +14 0x023a18bc | 0xfeeefeee +18 0x023a18c0 | 0x00000000 +1c 0x023a18c4 | 0x00000000 +20 0x023a18c8 | 0x0005000a = UNICODE '' +24 0x023a18cc | 0x051807c2 [+] This mona.py actiontook 0:00:00.640000
在上面的输出我们可以看到,mona确定源对象中包含了对2个链接对象的引用,并且转储了链接对象。最重要的是要知道mona不会把字符串 (ASCII or Unicode) 当作对象处理,因为mona已经显示了字符串,dumpobj命令的输出,最终会写入一个名为“dumpobj.txt”的文本文件中。
dumplog (dl)
显然,dumpobj命令能够十分轻松的获得一个对象的重要信息。如果你已经知道起始对象,这对你来说就更加方便了。
为了让世界清净下来,我决定使用dumplog去解析日志文件(基于某一语法),并在已经分配好的对象中执行dumpobj命令。在当前这个版本,dumplog并不能够转储链接对象,但是我准备给他加上这一特性。
Dumplog在使用前,需要进行一些设置。我们需要告诉WinDBG创建一个遵循特定协议的日志文件,当然了,我们需要在同一个调试会话中运行mona。
Dumplog的帮助信息如下:
Usage of command 'dl' : ------------------------ Dump all objects recorded in an alloc/free log Note: dumplog will only dump objects that have not been freed in the samelogfile. Expected syntax for log entries: Alloc : 'alloc(size in hex) =address' Free : 'free(address)' Additional text after the alloc & free info is fine. Just make sure the syntax matches exactly with the examples above. Arguments: -f <path/to/logfile>: Full path to the logfile
这个想法是为了记录所有的堆分配以及*操作。在WinDBG中可以通过以下步骤实现:
.logclose .logopen c://allocs.txt
接下来,记录2个断点
bp !ntdll + 0002e12c ".printf /"alloc(0x%x) = 0x%p/",poi(esp+c), eax; .echo; g" bp ntdll!RtlFreeHeap "j (poi(esp+c)!=0)'.printf /"free(0x%p)/", poi(esp+c); .echo; g'; 'g';"
(基于kernel32.dll最新版本, Windows7 SP1).
当RtlAllocateHeap 和RtlFreeHeap被调用时,这两个断点就会向WinDBG发送一个消息。
当你准备分析漏洞时,不要关闭WinDBG,关闭日志文件时使用.logclose命令。我们现在就可以使用mona解析日志文件了。
!py mona dl -fc:/allocs.txt
输出将被写入dump_alloc_free.txt文件
最后,希望你能够喜欢这两个新特性。