windows花指令和堆栈溢出原理

1、今天拿到一个exe,用IDA打开后在main的代码如下,想直接F5,报错如下:

     细看代码,有两个比较有意思的地方:

  •    第一个红框,JZ和JNZ跳转到同一个地址:0x4010A1+1=0x4010A2
  •    第二个红框,也就是0x4010A1的开始地址是一个call指令,5字节长度;再下一个指令就从0x4010A6开始了;
  •    0x4010A1处指令call的跳转地址是0x52285E33h,这个明显比用户空间大很多:用户空间一般从0x00400000,很难直接跳转到0x52285E33h;事实上,从IDA看,.text段在0x00413FE0就已经结束了,所以这里的跳转地址肯定有问题(IDA也标红处理)

      综合,0x4010A2就不是指令的入口地址,这里遇到花指令了;

    

 2、选中call指令,右键“D”转成db数据,如下:

    

  既然jz和jnz的目的地都是0x4010A2,那就从0x4010A2开始选中剩余db代码,右键“Analyze selected area”,如下:

     

   终于看到了“庐山真面目”:0x4010A2原来是个lea指令,前面哪个0xe8彻底没用了;

   

 直接把原0xe8打patch,改成0x90,也就是NOP,避免影响其他指令的执行,如下:

  

  随后同样选中0x90,右键analyze seleced area,转成nop指令;最后快捷键P还原成完整的函数;

 

    往上,有个函数执行了system("cmd")代码,这里可以获取shell,先把函数改名cmd_shell;

    

    4、先在重点分析main函数,从第1行代码开始:

(1)这个简单,就是保存原ebp,然后开辟58h的栈空间,最后赋初事值0xcc

.text:00401070                 push    ebp
.text:00401071                 mov     ebp, esp
.text:00401073                 sub     esp, 58h
.text:00401076                 push    ebx
.text:00401077                 push    esi
.text:00401078                 push    edi
.text:00401079                 lea     edi, [ebp-58h]
.text:0040107C                 mov     ecx, 16h
.text:00401081                 mov     eax, 0CCCCCCCCh
.text:00401086                 rep stosd

(2)紧接着从ebp-0x14到ebp-0x4赋值0;

text:00401088                 mov     dword ptr [ebp-14h], 0
.text:0040108F                 xor     eax, eax
.text:00401091                 mov     [ebp-10h], eax
.text:00401094                 mov     [ebp-0Ch], eax
.text:00401097                 mov     [ebp-8], eax
.text:0040109A                 mov     [ebp-4], eax

(3)花指令的这几行代码直接略过,到了最关键的代码之一:scanf   这里直接把用户输入的数字保存在ebp-0x18单元中

.text:004010A2                 lea     ecx, [ebp-18h]  ; 用户通过scanf输入的数字保存在ebp-0x18这里,比如输入6
.text:004010A5                 push    ecx
.text:004010A6                 push    offset aD       ; "%d"
.text:004010AB                 call    _scanf
.text:004010B0                 add     esp, 8

      紧接着把用户输入的数字*4后减去0x14h作为偏移,ebp作为基址,写入cmd_shell函数的入口地址;

.text:004010B3                 mov     edx, [ebp-18h]  ; edx=6
.text:004010B6                 mov     dword ptr [ebp+edx*4-14h], offset cmd_shell

       这个程序中最大的漏洞就在这里了:稍微有点windows32位逆向经验的同学都知道,整个栈都是用ebp加减常数来寻址的,比如ebp+4是函数调用前上个帧的ebp地址;ebp+8是函数调用完的返回地址,ebp+12开始是函数参数;ebp自身开始时函数的局部变量,空间是esp减去常数分配的;具体到这个程序,如果用户输入6,也就是edx=6,那么ebp+edx*4-14h=ebp+8,刚好是main函数的返回地址。如果这里用cmd_shell的地址覆盖,一旦main执行完,就会跳转到cmd_shell执行,这就是传说中的栈溢出(如果这是个网络服务,黑客完全可以精心构造一段字符串发送过来得到反弹shell);完全绕开了原来的跳转流程;前面所有代码执行完后的堆栈示意图如下:

          

       代码执行的效果:输入6以后,马上得到当前目录的shell;通过whoami查询发现是administrator权限,也能查看当前目录的文件;

      

 5、程序完整的C代码如下:

#include "stdafx.h"
#include "stdlib.h"

void shell(){
    system("cmd");
}

int main(int argc, char* argv[])
{
    int a[5]={0};
    int x;
    _asm{
        jz label;
        jnz label;
        _emit 0xE8;
label:
    }
    scanf("%d",&x);
    //a[x] = (int)&shell;
    a[x] = (int)shell;
    printf("Hello World!
");
    return 0;
}

参考:

1、https://www.bilibili.com/video/BV1mK411A75G?from=search&seid=10691647714478259112   花指令patch与原理分析

原文地址:https://www.cnblogs.com/theseventhson/p/13933230.html