分析堆对象与mona.py
引言
大家好,
在为Derbycon的高级漏洞开发课程做准备时,我一直在研究IE中的堆分配原语。在研究过程中,快速识别可能有用的对象是一个令人沮丧(或至少会减慢研究速度)的问题。毕竟,我正在寻找包含任意数据或指向任意数据的指针的对象,但由于噪音的存在,这并不总是容易做到。
我决定为mona.py添加一些新功能,以便更快地找到有趣的对象。这些新功能仅在WinDBG下可用。
要获取最新版本的mona,只需运行!py mona up
。由于我还升级到了最新版本的pykd,您可能还需要更新pykd.pyd才能运行最新版本的mona。(当您尝试使用过时版本的pykd运行mona时,应在WinDBG日志窗口中看到更新说明)
dumpobj (do)
第一个新功能是“dumpobj”。这个mona.py命令将转储对象的内容,并提供(希望)有用的内容信息。该命令接受以下参数:
1
2
3
4
5
6
7
8
9
10
|
Usage of command 'dumpobj' :
-----------------------------
Dump the contents of an object.
Arguments:
-a : Address of object
-s : Size of object (default value: 0x28 or size of chunk)
Optional arguments:
-l : Recursively dump objects
-m : Size for recursive objects (default value: 0x28)
|
如上面的!py mona help dumpobj
输出所示,我们需要至少提供2个参数:
-a
:起始位置(对象的地址,但您可以指定任何位置)
-s
:对象的大小。如果不指定-s
参数,mona将尝试确定对象的大小。如果不可能,mona将转储对象的0x28字节。
此外,您可以告诉mona也转储链接的对象。参数-l
接受一个数字,表示递归转储的级别数。为了限制输出大小(以及性能原因),仅打印链接对象的前0x28字节(除非使用参数-m
来覆盖此行为)。
当然,在WinDBG中转储对象的内容是相当简单的。dds
或dc
命令将打印出对象并显示其内容的一些信息。在某些情况下,dds
/dc
的输出不足,需要额外的工作来进一步分析对象及其内部链接的可选对象。
让我们看一个例子。假设我们在0x023a1bc0有一个0x78字节的对象。当然,我们可以使用本机WinDBG命令转储对象的内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
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 ........
|
很好。我们可以看到各种东西——看起来像指针的值、空值和其他一些“垃圾”。如果不单独查看每个值,很难判断它是什么。
使用mona,我们可以转储相同的对象,mona将尝试收集有关对象中每个dword的更多信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
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 action took 0:00:00.579000
|
显然,对象中的一些值指向字符串(ASCII和Unicode),另一个指针似乎链接到另一个对象(ADVAPI32!g_CodeLevelObjTable+0x4)。这比dds
或dc
有用得多。但我们可以让它更好。我们可以告诉mona自动打印出链接的对象,最多到任何深度级别。让我们重复mona命令,这次要求链接对象最多一级深度:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
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 0x023a1d60 | 0x023a1c88 (Heap) ptr to UNICODE 'Software access rights are determined by the access rights of the user.'
+24 0x023a1d64 | 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 action took 0:00:00.640000
|
如上面的输出所示,mona确定源对象包含对2个链接对象的引用,并决定也转储这些链接对象。重要的是要知道mona不会将字符串(ASCII或Unicode)视为对象,因为mona已经显示了字符串,即使它们是在对象内部引用的。dumpobj命令的输出被写入名为“dumpobj.txt”的文本文件。
供您参考,!mona info -a
的输出包括mona dumpobj的输出(不打印递归对象)。如果您想了解给定地址的确切含义,您将得到类似这样的信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
0:001> !py mona info -a 0x023a1bc0
Hold on...
[+] Generating module info table, hang on...
- Processing modules
- Done. Let's rock 'n roll.
[+] NtGlobalFlag: 0x00000070
0x00000040 : +hpc - Enable Heap Parameter Checking
0x00000020 : +hfc - Enable Heap Free Checking
0x00000010 : +htc - Enable Heap Tail Checking
[+] Information about address 0x023a1bc0
{PAGE_READWRITE}
Address is part of page 0x013c0000 - 0x023a2000
This address resides in the
|