CVE-2012-1535 Flash漏洞调试笔记
前言:
好久没来看雪,看了古河的分析之前,自己也调了一下这个洞。感觉现在漏洞分析贴,一般自己分析完之后,会按照正向的思路写下整个触发成因。这种公告式的制式写法确实清晰明了,却删减了大量原创作者在分析过程中的思路和数据追踪、回溯的轨迹。造成分析爱好者无法学习,只能膜拜。也许这是一种门槛吧。
本文反其道而行之。着力点在于从现象挖掘本质,注重描述作者个人的思路和分析方法。希望对大家有所帮助,供大家共同学习。
环境:
Windows XP en +windbg
Adobe Flash Player ActiveX 11.1.102.63
样本:
见同版块古河的帖子。
1, 打开windbg,进行如下设置:
gflags.exe /i iexplore.exe +hpa
0:000> g
(c4.4cc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=1e0d0000 ebx=1e0cfff0 ecx=000004f4 edx=00000000 esi=0535df70 edi=053697f0
eip=103d7a0e esp=0013dd48 ebp=0013dd80 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00050202
Flash11g!DllUnregisterServer+0x23bfb5:
103d7a0e ff5008 call dword ptr [eax+8] ds:0023:1e0d0008=????????
发现异常,简单的数据回溯追踪后,设置如下断点:
sxe ld:Flash11g.ocx
bp 103d7bd0
bp 103d7d6b ".echo *****************************************; r esi; kp L20;.echo **************************************; gc;"
2, 进入sub_103D7BD0函数(此时设置虚拟机快照,以后每次恢复,保证上下文每次分析都相同):我们发现离esi比较近的赋值语句
.text:103D7D57 mov esi, eax
bp 103D7D57 ".echo Signal####################; r eax; .echo the virtual call:; dd poi(eax)+8 L1; .echo $$$$$$$$$$$$$$$$$$$$End; gc;"
0:000> g
Signal####################
eax=0535df70
the virtual call:
0535c1b8 100336df
####################
......
Signal####################
eax=0535df70
the virtual call:
0535c1b8 100336df
####################
Signal####################
eax=0535df70
the virtual call:
0535c1b8 00000000
####################
......
Signal####################
eax=0535df70
the virtual call:
0535c1b8 00000000
####################
Signal####################
eax=0535df70
the virtual call:
1e0d0008 ????????
####################
Signal####################
eax=0535df70
the virtual call:
1e0d0008 ????????
####################
*****************************************
esi=0535df70
1e0d0008 ????????
**************************************
eax=00000000 ebx=1e0cfff0 ecx=000004f4 edx=00000000 esi=0535df70 edi=053697f0
eip=103d7d6b esp=0013dd58 ebp=0013dd80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040246
Flash11g!DllUnregisterServer+0x23c312:
103d7d6b e88ffcffff call Flash11g!DllUnregisterServer+0x23bfa6 (103d79ff)
3, 我们发现eax所指向的dword经过几次重要的变化,正是最后的变化,导致访问虚表函数失败。对其下内存写入断点。重新开始
ba w1 0535df70 ".echo mem changed--------------; r ebx; dd poi(0535df70)+8 L1; "
...
Signal####################
eax=0535df70
the virtual call:
0535c1b8 00000000
$$$$$$$$$$$$$$$$$$$$End
Signal####################
eax=0535df70
the virtual call:
0535c1b8 00000000
$$$$$$$$$$$$$$$$$$$$End
mem changed--------------
1e0d0000 ????????
eax=1e0cfff8 ebx=1e0cfff0 ecx=00e40206 edx=00000000 esi=0535df68 edi=053697f0
eip=103d7cfa esp=0013dd5c ebp=0013dd80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040246
Flash11g!DllUnregisterServer+0x23c2a1:
103d7cfa 7512 jne Flash11g!DllUnregisterServer+0x23c2b5 (103d7d0e) [br=0]
4, 指令mov [esi+8], eax是关键,直接导致后面的执行异常。我们必须在此处追踪eax的来源。发现跟ebx有关,我们在循环中读取一下ebx的值。
发现在第一次循环后,ebx已经是这个值了。继续追踪ebx的来源
.text:103D7C05 push 8
.text:103D7C07 jmp short loc_103D7C1D
.text:103D7C09 ; ---------------------------------------------------------------------------
.text:103D7C09
.text:103D7C09 loc_103D7C09: ; CODE XREF: sub_103D7BD0+21j
.text:103D7C09 cmp eax, 0FFFFh
.text:103D7C0E ja loc_103D7D76
.text:103D7C14 mov [ebp+var_14], 1
.text:103D7C1B push 4
.text:103D7C1D
.text:103D7C1D loc_103D7C1D: ; CODE XREF: sub_103D7BD0+37j
.text:103D7C1D pop ebx //执行完这个之后,ebx=8
.text:103D7D54 add ebx, [ebp+var_18] //加上后,是不是ebx就确定了?
.text:103D7D57 mov esi, eax
5, 我们猜测以上两个地方决定了ebx的值。
bp 103D7D54 ".echo trace ebx from where:; r ebx;.echo : +++++++++++++++++++++++; "重新开始下
0:000> g
trace ebx from where:
ebx=00000008
+++++++++++++++++++++++
eax=0535df70 ebx=00000008 ecx=00000001 edx=00000000 esi=05359048 edi=053697f0
eip=103d7d54 esp=0013dd5c ebp=0013dd80 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040202
Flash11g!DllUnregisterServer+0x23c2fb:
103d7d54 035de8 add ebx,dword ptr [ebp-18h] ss:0023:0013dd68=1e0cffe8
可以看出1e0cffe8+8 =1E0CFFF0。证实了我们的猜测。接下来追踪ebp-18h指向的内存数据的变化来源。
6, 设置内存写入断点,初步假设ebp-18h始终为0013dd68。栈针一般不会有变化的。
ba w1 0013dd68 ".echo poi(0013dd68) has changed:; dd 0013dd68 L1; .echo ------------------------------;"
0:000> bp 103D7D57 ".echo Signal####################; r eax; .echo the virtual call:; dd poi(eax)+8 L1; .echo $$$$$$$$$$$$$$$$$$$$End; gc;"
0:000> bp 103D7D54 ".echo trace ebx from where:; r ebx;.echo +++++++++++++++++++++++; "
0:000> ba w1 0013dd68 ".echo poi(0013dd68) has changed:; dd 0013dd68 L1; .echo ------------------------------;"
0:000> g
poi(0013dd68) has changed:
0013dd68 1e0cffe8
------------------------------
eax=1e0cffe8 ebx=00000008 ecx=000000ff edx=00000000 esi=05359048 edi=053697f0
eip=103d7ce0 esp=0013dd50 ebp=0013dd80 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040206
Flash11g!DllUnregisterServer+0x23c287:
103d7ce0 8b4510 mov eax,dword ptr [ebp+10h] ss:0023:0013dd90=00003000
对应的IDA查看如下:
.text:103D7CD5 loc_103D7CD5: ; CODE XREF: sub_103D7BD0+D8j
.text:103D7CD5 push ebx
.text:103D7CD6 push [ebp+arg_4]
.text:103D7CD9 push edi
.text:103D7CDA call dword ptr [edi+18h] //关键函数啦
.text:103D7CDD mov [ebp+var_18], eax ; poi(0013dd68) has changed
7, 在103D7CDA处下断点。查看函数执行的过程
0:000> bp 103d7cda
0:000> ba w1 0013dd68 ".echo poi(0013dd68) has changed:; dd 0013dd68 L1; .echo ------------------------------;"
0:000> g
Breakpoint 2 hit
eax=00003000 ebx=00000008 ecx=05413000 edx=00000000 esi=05359048 edi=053697f0
eip=103d7cda esp=0013dd50 ebp=0013dd80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040246
Flash11g!DllUnregisterServer+0x23c281:
103d7cda ff5718 call dword ptr [edi+18h] ds:0023:05369808=103d85bb
0:000> dds esp esp+20
0013dd50 053697f0
0013dd54 0013ddf8
0013dd58 00000008
0013dd5c 0013ddf8
0013dd60 05848020
0013dd64 0535c1b0
0013dd68 103cb90c Flash11g!DllUnregisterServer+0x22feb3
0013dd6c 00000000
0013dd70 00000000
8, 在函数103d85bb中,比较关键的代码如下:
.text:103D85F8 mov ecx, [esi+40h] //ecx = 0541788d
.text:103D85FB add eax, ecx //eax = 8 +ecx = 05417895
.text:103D85FD movzx ebx, byte ptr [eax]
.text:103D8600 movzx ecx, byte ptr [eax+1]
.text:103D8611 shl ebx, 8
.text:103D8614 or ebx, ecx
.text:103D8616 shl ebx, 8
.text:103D8619 or ebx, eax
0:000> db 05417895(ecx+eax)
05417895 1e 0c ff e8 30 00 00 0b-0d da 00 03 00 22 ff a2 ....0........"..
054178a5 00 03 00 2b ff 81 00 03-00 35 00 1a 00 03 00 79 ...+.....5.....y
054178b5 ff a2 00 03 00 7b ff a2-00 03 00 7c ff a2 00 03 .....{.....|....
很明显的可以看出,这段代码的意思,就是把ebx赋值成0x1e0cffe8
9,我们需要追踪内存地址处05417895的来源,由指令可见,主要是来源于esi+40h。而esi则是函数压入的第一个参数值(初步猜测为某个类型的基址假定为baseAddr)
这样我们推断,这个地址来源于poi(baseAddr+40)+8 =05417895。而且此处地址指向的内存一直没有发生变化。
0:000> bp 103d7bd0
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\Macromed\Flash\Flash11g.ocx -
0:000> bp 103d7d6b ".echo *****************************************; r esi; dd poi(esi)+8 L1; .echo **************************************;"
0:000> g
Breakpoint 0 hit
eax=053697f0 ebx=0535c1b0 ecx=0000003d edx=0000009c esi=05848020 edi=0013ddf8
eip=103d7bd0 esp=0013dd84 ebp=0013dda8 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040206
Flash11g!DllUnregisterServer+0x23c177:
103d7bd0 55 push ebp
0:000> db 05417895
05417895 1e 0c ff e8 30 00 00 0b-0d da 00 03 00 22 ff a2 ....0........"..
054178a5 00 03 00 2b ff 81 00 03-00 35 00 1a 00 03 00 79 ...+.....5.....y
054178b5 ff a2 00 03 00 7b ff a2-00 03 00 7c ff a2 00 03 .....{.....|....
10, 我们搜索这些数据是否在swf中,果然一下子找到了。我们把swf中的这个改成0c0c0c0c,那么最后call的地方应该是0c0c0c2c。重新加载:
This exception may be expected and handled.
eax=0c0c0c24 ebx=0c0c0c14 ecx=000004f5 edx=00000000 esi=0345df80 edi=034697f0
eip=103d7a0e esp=0013dd48 ebp=0013dd80 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00050202
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\Macromed\Flash\Flash11g.ocx -
Flash11g!DllUnregisterServer+0x23bfb5:
103d7a0e ff5008 call dword ptr [eax+8] ds:0023:0c0c0c2c=????????
验证了我们的猜想,EIP完全可控。
接下来的问题是,为何程序在call这个地址时,简单来说前面的分析可知,call的函数地址其实是poi(addressBase)+8。这个addressBase所指向的本来应该是个正常
的值。后期被覆盖成一个非法的了,而且这个非法的值来源于swf文件内部。
11, addressBase在本实例中为0535df70。单步跟一下sub_103D7BD0。我们发现执行这个函数过后,返回的正是此值。
.text:103D7C27 mov eax, [ebp+arg_0]
.text:103D7C2A push 10h
.text:103D7C2C push eax
.text:103D7C2D call dword ptr [eax] ; AllocMem Return 0535df70
初步猜测这是个内存的提取函数。而大函数sub_103D7BD0的第一个参数是内存池的提取索引(应该是个类基址一样的东西)我们定义这个函数为GetPoolMem。
记住,函数执行返回的内存池地址为0535df70。
后期内存池类基址(姑且叫这个名吧)首先被放在这个地方
.text:103D7C44 mov eax, [ebp+arg_8] //0x10000000(这个数值的来源一会再说)
.text:103D7C47 mov ecx, [ebp+arg_0] //内存池类基址
.text:103D7C4A mov [esi+8], eax //存储在addressBase+8的地方
.text:103D7C4D shl eax, 4 // eax= 0x10000000 *0x10
.text:103D7C50 push eax
.text:103D7C51 push ecx
.text:103D7C52 mov [esi], ecx //内存池类基址(参数一)存储在addressBase的地方
.text:103D7C54 mov [esi+4], edi
.text:103D7C57 call dword ptr [ecx] //调用GetPoolMem
我们发现第二次调用了GetPoolMem函数。记下返回值为05359048 < 0535df70 (我们把第二次返回的记录为addressBase2)
0:000> db eax
05359048 44 90 35 05 54 90 35 05-00 00 00 00 50 90 35 05 D.5.T.5.....P.5.
05359058 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
该返回值被保存在AddressBase+0c的位置
.text:103D7C5D mov [esi+0Ch], eax
接下来进行一系列对刚分配的缓冲区的操作。
12,主要是一个大循环,从addressBase2开始,每次都是0x10个操作单元。
.text:103D7C8A Circle_Handler: ; CODE XREF: sub_103D7BD0+18Cj
.text:103D7C8A mov esi, [esi+0Ch] ; esi = AddressBase2
.text:103D7C8D add esi, [ebp+var_4] ; var_4每次都加10,进而AddressBase2每次都加10
.text:103D7C90 lea eax, [ebx+4]
.text:103D7C93 push eax
.text:103D7C94 push [ebp+arg_4]
.text:103D7C97 push edi
.text:103D7C98 call dword ptr [edi+0Ch] ; 第一次返回0x300,一会再看
.text:103D7C9B add esp, 0Ch
.text:103D7C9E cmp [ebp+var_14], 0 ; 这地方没看明白,估计会回来
.text:103D7CA2 mov [ebp+arg_8], eax
.text:103D7CA5 mov [esi+4], ebx ; addressBase2+4修改
.text:103D7CA8 jz short loc_103D7CD5
.text:103D7CAA lea eax, [ebx+2]
.text:103D7CAD push eax
.text:103D7CAE push [ebp+arg_4]
.text:103D7CB1 push edi
.text:103D7CB2 call dword ptr [edi+0Ch]
.text:103D7CB5 mov [ebp+var_18], eax
.text:103D7CB8 mov eax, [ebp+arg_8]
.text:103D7CBB sar eax, 8
.text:103D7CBE mov [esi], eax
.text:103D7CC0 add esp, 0Ch
.text:103D7CC3 test byte ptr [ebp+arg_8], 1
.text:103D7CC7 lea eax, [ebx+6]
.text:103D7CCA mov [esi+8], eax
.text:103D7CCD jz short loc_103D7D0E
.text:103D7CCF test byte ptr [ebp+arg_8], 6
.text:103D7CD3 jmp short loc_103D7D0C
.text:103D7CD5 ; ---------------------------------------------------------------------------
.text:103D7CD5
.text:103D7CD5 loc_103D7CD5: ; CODE XREF: sub_103D7BD0+D8j
.text:103D7CD5 push ebx
.text:103D7CD6 push [ebp+arg_4]
.text:103D7CD9 push edi
.text:103D7CDA call dword ptr [edi+18h] ; 第三次调用,读取1e0cffe8
.text:103D7CDD mov [ebp+var_18], eax ; poi(0013dd68) has changed
.text:103D7CE0 mov eax, [ebp+arg_8] ; 刚函数的返回值0x300
.text:103D7CE3 and eax, 0FFh ; eax=0
.text:103D7CE8 mov [esi], eax ; counter的比较值被修改成0,导致第二次循环退出。
.text:103D7CEA add esp, 0Ch
.text:103D7CED test [ebp+arg_8], 0C000h ; 0x300比较
.text:103D7CF4 lea eax, [ebx+8]
.text:103D7CF7 mov [esi+8], eax ; poi(0535df70) changed 2ed
.text:103D7CFA jnz short loc_103D7D0E
.text:103D7CFC lea eax, [ebx+6]
.text:103D7CFF push eax
.text:103D7D00 push [ebp+arg_4]
.text:103D7D03 push edi
.text:103D7D04 call dword ptr [edi+0Ch] ; 又调用这个,不知道干啥,应该是couter之类的。。。返回0x0b
.text:103D7D07 add esp, 0Ch
.text:103D7D0A test eax, eax
.text:103D7D0C
.text:103D7D0C loc_103D7D0C: ; CODE XREF: sub_103D7BD0+103j
.text:103D7D0C jz short loc_103D7D12
.text:103D7D0E
.text:103D7D0E loc_103D7D0E: ; CODE XREF: sub_103D7BD0+FDj
.text:103D7D0E ; sub_103D7BD0+12Aj
.text:103D7D0E and dword ptr [esi+8], 0 ; addressBase2+8 修改
.text:103D7D12
.text:103D7D12 loc_103D7D12: ; CODE XREF: sub_103D7BD0:loc_103D7D0Cj
.text:103D7D12 mov eax, [esi]
.text:103D7D14 test eax, eax
.text:103D7D16 jnz short loc_103D7D2F
.text:103D7D18 push dword ptr [esi+8]
.text:103D7D1B push [ebp+arg_4]
.text:103D7D1E push edi
.text:103D7D1F call dword ptr [edi+0Ch] ; 返回1
.text:103D7D22 add esp, 0Ch
.text:103D7D25 dec eax
.text:103D7D26 add dword ptr [esi+8], 8 ; AddressBase2+8修改
.text:103D7D2A mov [esi+0Ch], eax ; AddressBase2+0c修改
.text:103D7D2D jmp short loc_103D7D3E
.text:103D7D2F ; ---------------------------------------------------------------------------
.text:103D7D2F
.text:103D7D2F loc_103D7D2F: ; CODE XREF: sub_103D7BD0+146j
.text:103D7D2F cmp eax, 2
.text:103D7D32 jnz short loc_103D7D3A
.text:103D7D34 or dword ptr [esi+0Ch], 0FFFFFFFFh
.text:103D7D38 jmp short loc_103D7D3E
.text:103D7D3A ; ---------------------------------------------------------------------------
.text:103D7D3A
.text:103D7D3A loc_103D7D3A: ; CODE XREF: sub_103D7BD0+162j
.text:103D7D3A and dword ptr [esi+8], 0
.text:103D7D3E
.text:103D7D3E loc_103D7D3E: ; CODE XREF: sub_103D7BD0+15Dj
.text:103D7D3E ; sub_103D7BD0+168j
.text:103D7D3E cmp dword ptr [esi+8], 0
.text:103D7D42 jnz short loc_103D7D47
.text:103D7D44 inc [ebp+var_10]
.text:103D7D47
.text:103D7D47 loc_103D7D47: ; CODE XREF: sub_103D7BD0+172j
.text:103D7D47 inc [ebp+var_8] ; 注意了,couter自加了
.text:103D7D4A mov eax, [ebp+var_C]
.text:103D7D4D mov ecx, [ebp+var_8]
.text:103D7D50 add [ebp+var_4], 10h
.text:103D7D54 add ebx, [ebp+var_18] ; ebx此时被赋值0x1e0cfff0
.text:103D7D57 mov esi, eax
.text:103D7D59 cmp ecx, [eax+8] ; 循环0x10000000次
.text:103D7D5C jb Circle_Handler
根据前面的调试,最终在.text:103D7CF7处,AddressBase1的内容被覆盖为1e0cfff8 。这个应该是循环次数为0x10000000,但是前面AddressBase2分配时整形乘法
溢出造成实际分配的内存为0,覆盖了AddressBase1。我们接下来看下这个循环是如何退出的。继续单步跟踪下(其实没几行代码的,耐心。。。)
在这里我们对103D7D59处设置断点,查下ecx的counter值多少时退出的。(其实前面的调试2步中可以看出是0x4f4)
bp 103D7D59 ".echo counter num:; r ecx; .echo AddressBase1 Mem Status:; dd eax L10; .echo ++++++++++++; gc;"
ba w1 0535df70 ".echo mem changed--------------; "
0:000> bp 103D7D59 ".echo counter num:; r ecx; .echo AddressBase1 Mem Status:; dd eax L10; .echo ++++++++++++; gc;"
0:000> ba w1 0535df70 ".echo mem changed--------------; "
0:000> g
mem changed--------------
eax=00000000 ebx=00000008 ecx=0535c1b0 edx=00000000 esi=0535df70 edi=053697f0
eip=103d7c54 esp=0013dd54 ebp=0013dd80 iopl=0 nv up ei pl zr na pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040247
Flash11g!DllUnregisterServer+0x23c1fb:
103d7c54 897e04 mov dword ptr [esi+4],edi ds:0023:0535df74=00000000
0:000> g
counter num:
ecx=00000001
AddressBase1 Mem Status:
0535df70 0535c1b0 053697f0 10000000 05359048
0535df80 00000000 00000000 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
counter num:
ecx=00000002
AddressBase1 Mem Status:
0535df70 0535c1b0 053697f0 10000000 05359048
0535df80 00000000 00000000 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
counter num:
ecx=00000003
AddressBase1 Mem Status:
0535df70 0535c1b0 053697f0 10000000 05359048
0535df80 00000000 00000000 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
......
......
counter num:
ecx=000004f2
AddressBase1 Mem Status:
0535df70 0535c1b0 053697f0 10000000 05359048
0535df80 00000000 00000000 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
mem changed--------------
eax=1e0cfff8 ebx=1e0cfff0 ecx=00e40206 edx=00000000 esi=0535df68 edi=053697f0
eip=103d7cfa esp=0013dd5c ebp=0013dd80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040246
Flash11g!DllUnregisterServer+0x23c2a1:
103d7cfa 7512 jne Flash11g!DllUnregisterServer+0x23c2b5 (103d7d0e) [br=0]
这时我们修改下其中一个断点:
bp 103D7D59 ".echo counter num:; r ecx; .echo AddressBase1 Mem Status:; dd eax L10; .echo ++++++++++++;"
0:000> bp 103D7D59 ".echo counter num:; r ecx; .echo AddressBase1 Mem Status:; dd eax L10; .echo ++++++++++++;"
breakpoint 2 redefined
0:000> g
mem changed--------------
eax=ffffffff ebx=1e0cfff0 ecx=00900206 edx=00000000 esi=0535df68 edi=053697f0
eip=103d7d2a esp=0013dd5c ebp=0013dd80 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040216
Flash11g!DllUnregisterServer+0x23c2d1:
103d7d2a 89460c mov dword ptr [esi+0Ch],eax ds:0023:0535df74=053697f0
0:000> g
counter num:
ecx=000004f3
AddressBase1 Mem Status:
0535df70 1e0d0000 ffffffff 10000000 05359048
0535df80 00000000 00000000 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
eax=0535df70 ebx=1e0cfff0 ecx=000004f3 edx=00000000 esi=0535df70 edi=053697f0
eip=103d7d59 esp=0013dd5c ebp=0013dd80 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040206
Flash11g!DllUnregisterServer+0x23c300:
103d7d59 3b4808 cmp ecx,dword ptr [eax+8] ds:0023:0535df78={Flash11g (10000000)}
0:000> g
counter num:
ecx=000004f4
AddressBase1 Mem Status:
0535df70 1e0d0000 ffffffff 00000000 1e0cfff0
0535df80 1e0d0000 ffffffff 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
eax=0535df70 ebx=1e0cfff0 ecx=000004f4 edx=00000000 esi=0535df70 edi=053697f0
eip=103d7d59 esp=0013dd5c ebp=0013dd80 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040206
Flash11g!DllUnregisterServer+0x23c300:
103d7d59 3b4808 cmp ecx,dword ptr [eax+8] ds:0023:0535df78=00000000
13, counter走到0x4f4,我们发现ecx比较的一直是poi(AddressBase1+8),已经在上一轮循环中被修改成0了。直接导致比较失败。我们看下这个值是何时被改成0
的。
bp 103D7D59 ".echo counter num:; r ecx; .echo AddressBase1 Mem Status:; dd eax L10; .echo ++++++++++++; gc;"
ba w1 0535df70 ".echo mem changed--------------; "
ba w1 0535df78 ".echo counter compared num changed*******************;"
0:000> g
counter compared num changed*******************
eax=10000000 ebx=00000008 ecx=0535c1b0 edx=00000000 esi=0535df70 edi=053697f0
eip=103d7c4d esp=0013dd5c ebp=0013dd80 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040202
Flash11g!DllUnregisterServer+0x23c1f4:
103d7c4d c1e004 shl eax,4 //这个是最开始保存函数返回的0x10000000,竟然就保存在AddressBase1+8的位置。后面一直用它索引。
0:000> g
mem changed--------------
eax=00000000 ebx=00000008 ecx=0535c1b0 edx=00000000 esi=0535df70 edi=053697f0
eip=103d7c54 esp=0013dd54 ebp=0013dd80 iopl=0 nv up ei pl zr na pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040247
Flash11g!DllUnregisterServer+0x23c1fb:
103d7c54 897e04 mov dword ptr [esi+4],edi ds:0023:0535df74=00000000
0:000> g
counter num:
ecx=00000001
AddressBase1 Mem Status:
0535df70 0535c1b0 053697f0 10000000 05359048
0535df80 00000000 00000000 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
counter num:
ecx=00000002
AddressBase1 Mem Status:
0535df70 0535c1b0 053697f0 10000000 05359048
0535df80 00000000 00000000 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
......
......
......
counter num:
ecx=000004f2
AddressBase1 Mem Status:
0535df70 0535c1b0 053697f0 10000000 05359048
0535df80 00000000 00000000 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
mem changed--------------
eax=1e0cfff8 ebx=1e0cfff0 ecx=00e40206 edx=00000000 esi=0535df68 edi=053697f0
eip=103d7cfa esp=0013dd5c ebp=0013dd80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040246
Flash11g!DllUnregisterServer+0x23c2a1:
103d7cfa 7512 jne Flash11g!DllUnregisterServer+0x23c2b5 (103d7d0e) [br=0]
0:000> g
mem changed--------------
eax=ffffffff ebx=1e0cfff0 ecx=00900206 edx=00000000 esi=0535df68 edi=053697f0
eip=103d7d2a esp=0013dd5c ebp=0013dd80 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040216
Flash11g!DllUnregisterServer+0x23c2d1:
103d7d2a 89460c mov dword ptr [esi+0Ch],eax ds:0023:0535df74=053697f0
0:000> g
counter num:
ecx=000004f3
AddressBase1 Mem Status:
0535df70 1e0d0000 ffffffff 10000000 05359048
0535df80 00000000 00000000 00000000 00000000
0535df90 00000000 00000000 00000000 00000000
0535dfa0 00000000 00000000 00000000 00000000
++++++++++++
counter compared num changed*******************
eax=00000000 ebx=1e0cfff0 ecx=00e40206 edx=00000000 esi=0535df78 edi=053697f0
eip=103d7cea esp=0013dd50 ebp=0013dd80 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00040246
Flash11g!DllUnregisterServer+0x23c291:
103d7cea 83c40c add esp,0Ch
这里就找到counter比较值修改的地方了。现在大致搞清楚了。整形溢出导致分配的AddressBase2内存池长度为0,而后进行的操作以它的基址开始,仍然进行
原始的赋值操作循环,影响开始分配的内存池AddressBase1。在赋值过程中计数器的比较值也被修改,导致循环退出。而后在进一步的操作中,本来一开始
AddressBase1索引着内存池一系列的操作函数(0535c1b0)。结果这么一搞尼玛被修改成无效的地址1e0d0000了。直接导致call异常。所有的这些地址都可控。
14, 整个分析完成后,再去看古河的帖子,估计也不用我在这里重复描述一下他正向分析的过程吧。另外,结构体、数据解析之类的见他的文章。
另附古河的帖子链接:
http://bbs.pediy.com/showthread.php?t=154860
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。