函数反汇编以及栈结构分析

函数反汇编以及栈结构分析

ID:8915592

大小:63.56 KB

页数:7页

时间:2018-04-12

上传者:U-5734
函数反汇编以及栈结构分析_第1页
函数反汇编以及栈结构分析_第2页
函数反汇编以及栈结构分析_第3页
函数反汇编以及栈结构分析_第4页
函数反汇编以及栈结构分析_第5页
资源描述:

《函数反汇编以及栈结构分析》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库

#includeusingnamespacestd;intfunc(inta,intb);voidmain(){intx=1;inty=2;intz=func(x,y);}intfunc(inta,intb){returna+b;}汇编解析:voidmain(){//这个函数头产生的汇编代码是:main:013E13A0pushebp013E13A1movebp,esp013E13A3subesp,0E4h013E13A9pushebx013E13AApushesi013E13ABpushedi013E13ACleaedi,[ebp-0E4h]013E13B2movecx,39h013E13B7moveax,0CCCCCCCCh013E13BCrepstosdwordptres:[edi]*******************************************************intx=1;inty=2;//这个的汇编代码是:013E13BEmovdwordptr[x],1013E13C5movdwordptr[y],2*******************************************************//接下来就是函数的调用了,先是把参数压栈013E13CCmoveax,dwordptr[y]013E13CFpusheax013E13D0movecx,dwordptr[x] 013E13D3pushecx//参数压栈后就是调用函数013E13D4callfunc(13E11D1h)//在这个地方用F11调试步进,可以进入子函数func的汇编代码,如下:013E11D1jmpfunc(13E35B0h)func:013E35B0pushebp013E35B1movebp,esp013E35B3subesp,0C0h013E35B9pushebx013E35BApushesi013E35BBpushedi013E35BCleaedi,[ebp-0C0h]013E35C2movecx,30h013E35C7moveax,0CCCCCCCCh013E35CCrepstosdwordptres:[edi]013E35CEmoveax,dwordptr[a]013E35D1addeax,dwordptr[b]013E35D4popedi013E35D5popesi013E35D6popebx013E35D7movesp,ebp013E35D9popebp013E35DAret//func函数执行完毕后返回主函数中013E13D9addesp,8013E13DCmovdwordptr[z],eax013E13DFxoreax,eax013E13E1popedi013E13E2popesi013E13E3popebx013E13E4addesp,0E4h013E13EAcmpebp,esp013E13ECcall@ILT+315(__RTC_CheckEsp)(13E1140h)013E13F1movesp,ebp013E13F3popebp013E13F4ret接下来再看看各个寄存器都是怎么变的,里面存的什么东西1首先进入main函数最开始: 再看看此时的寄存器的内容:EAX = 00851D88EBX = 7E0BC000ECX = 00854A30EDX = 00000001ESI = 00000000EDI = 00000000EIP = 013E13A0ESP = 009BF76CEBP = 009BF7B8EFL = 000002022再进行单步调试:再观察一下寄存器的内容:EAX = 00851D88EBX = 7E0BC000ECX = 00854A30EDX = 00000001ESI = 00000000EDI = 00000000EIP = 013E13A1ESP = 009BF768EBP = 009BF7B8EFL = 00000202我们发现esp的值少了4,这就说明了函数压栈时是从高字节到低字节递减,越是后压进来的越是字节低。3再把esp的值保存一下再看一下寄存器的内容:EAX = 00851D88EBX = 7E0BC000ECX = 00854A30EDX = 00000001ESI = 00000000EDI = 00000000EIP = 013E13A3ESP = 009BF768EBP = 009BF768EFL = 00000202Ebp就保存了esp的值4再步进到直到main函数调用func函数之前 我们再观察内存的情况连续定义的变量,他们在内存中紧挨着,之间相差4个字节。其实在堆栈中每次内存偏移必须是4个字节的整数倍。这个在参数数目以及类型可变的函数中可以体会到字节对齐的这种思想。我们再观察下此时的寄存器的内容:EAX = 00000002EBX = 7E0BC000ECX = 00000001EDX = 00000001ESI = 00000000EDI = 009BF768EIP = 013E13D3ESP = 009BF674EBP = 009BF768EFL = 00000206我们可以发现实参x,y的值都是先传进寄存器,然后再压栈。当把参数全部压进去后才开始调用函数。同时我们也可以发现EIP寄存器它里面总是放着下一条要执行的指令。5再调试函数到子函数func里面观察此时对应的寄存器EAX = 00000002EBX = 7E0BC000ECX = 00000001EDX = 00000001ESI = 00000000EDI = 009BF768EIP = 013E35B0ESP = 009BF66CEBP = 009BF768EFL = 00000206其中的EBP=009BF768是之前进入main函数时堆栈的栈顶指针。现在我们要把它保存,所以要push以下,放到堆栈的内存中。然后呢,因为进入main函数之后,直到进入func子函数时,我们又要维护这个在main函数中产生的栈顶指针,所以要把栈顶指针的值保存以下,保存在ebp中,所以此时要move以下。通俗的说就是,你这个子函数要在人家main函数的地盘进行栈操作,你就得负责人家main函数之前的栈(栈顶指针),这样在子函数调用结束后,main函数可以直接接着原来的栈干事。同时子函数维护的还有ebx,esi,edi,凡是要在子函数中用到的寄存器,那么子函数就要保存调用它的函数中在这些寄存器中的值。6往后再看看函数的返回值,继续单步调试到: 再看相关的寄存器EAX = 00000003EBX = 7E0BC000ECX = 00000000EDX = 00000001ESI = 00000000EDI = 009BF668EIP = 013E35D4ESP = 009BF59CEBP = 009BF668EFL = 00000206可以看到两个数相加的结果保存在了寄存器EAX中。函数体中的代码执行完毕就要释放栈空间,接下来就是一系列的pop了。7我们再看看pop完后的寄存器:观察对应的寄存器:EAX = 00000003EBX = 7E0BC000ECX = 00000000EDX = 00000001ESI = 00000000EDI = 009BF768EIP = 013E35DAESP = 009BF66CEBP = 009BF768EFL = 00000206我们可以看到EBP变回了之前的 009BF66C(main函数中保存的先前函数的栈顶指针),ESP变回了之前的009BF66C(main函数进入func子函数栈顶指针)。这样就把之前保存在栈内存中的东西重新返回到寄存器中了。再研究下从子函数返回后main函数中的代码013E13D9addesp,8//func函数有两个int参数,所以释放8个字节013E13DCmovdwordptr[z],eax//把函数的返回值赋给变量z013E13DFxoreax,eax//将eax清零,xor表示异或运算,自己跟自己异或肯定是0013E13E1popedi013E13E2popesi013E13E3popebx013E13E4addesp,0E4h013E13EAcmpebp,esp013E13ECcall@ILT+315(__RTC_CheckEsp)(13E1140h)013E13F1movesp,ebp013E13F3popebp013E13F4ret总结:1:函数的返回值通过这些例子我们也可以看出函数可以返回在函数中定义的局部变量的值,因为函数的返回值最后传递给了EAX寄存器,所以即便函数调用结束后,栈中内存释放,但是寄存器却保存了返回值,但是如果返回一个指向栈内存的指针或者地址那就不行了,因为栈被释放了。2:参数的获取有些人或许要问,参数的值都是实参传递给形参的,这还需要什么获取,这话没有错误,但 是如果函数时比较特殊的函数,例如:intfunc(…);intfunc(int,int);intfunc(int,…);这种类型的呢,这些函数要么是可变参数,要么是参数名字没有给。在这种极端比较恶心的条件下,我们依然可以获取传递的实参的值。通过上面我们可以发现栈的结构是:参数n参数n-1…参数1函数的返回地址(call指令后面的那一句)EBP局部变量1局部变量2…局部变量n-1局部变量nEBXESIEDI所以我们可以通过EBP寄存器通过偏移固定的位置就可以找到对应的参数,例如第一个参数只需要EBP的地址加上8得到。3关于这里esp减值的问题通过控制函数的形参个数,以及函数内部定义的局部变量我们可以发现有这样一个规律。(1)函数内部没有定义局部变量是,改变形参的个数不影响esp减去的值,此时esp减去的值都是0C0h。(2)函数内部每多定义一个int类型的局部变量,减去的值就会增加12,就是说多开辟12个字节。(3)函数内部每多定义一个double类型的局部变量,减去的值就会增加16,就是说多开辟16个字节(4)函数内部每多定义一个char类型的局部变量,减去的值就会增加12,就是说多开辟12个字节。(5)函数内部每多定义一个float类型的局部变量,减去的值就会增加12,就是说多开辟12个字节。4寄存器4个数据寄存器(EAX、EBX、ECX和EDX) 2个变址和指针寄存器(ESI和EDI)2个指针寄存器(ESP和EBP) 6个段寄存器(ES、CS、SS、DS、FS和GS)1个指令指针寄存器(EIP)1个标志寄存器(EFlags)EBP:(ExtendedBasePointer)基址指针寄存器,存放栈底指针 ESP:(ExtendedStackPointer)栈指针寄存器,存放栈顶指针EAX:(ExtendedAccumulate)累加寄存器,用做加减乘除运算EBX:(ExtendedBase)基址寄存器,可以用来存储指针ECX:(ExtendedCount)计数寄存器,用在循环中控制循环的次数EDX:(ExtendedData)数据寄存器,在进行乘、除运算时,它可作为默认的操作数参与运算,通常用来保存余数。也 可用于存放I/O的端口地址ESI:(ExtendedSourceIndex)源索引寄存器,可以存放任何数据,但是习惯把它存放指针。EDI:(ExtendedDestinationIndex)目的索引寄存器,但是ESI和EDI虽然他俩经常配合,但是之间的区别还是比较大的。在字符串处理指令中,ESI和DS结合,DS:ESI构成全指针,在穿处理指令方面,ESI负责只读,EDI负责只写。关于为啥只能ESI和DS结合形参全指针,这是硬件构造决定的,没有选择性。ES:EDI,同样构成全指针。EIP:(ExtendedInstructionPointer)指令指针寄存器,要存放下一条执行指令的地址EFL:(ExtendedFlag)标志寄存器,用来运算结果标志(进位,溢出等),状态控制标志(跟踪,中断允许等)。CS——代码段寄存器(CodeSegmentRegister),其值为代码段的段值;DS——数据段寄存器(DataSegmentRegister),其值为数据段的段值;ES——附加段寄存器(ExtraSegmentRegister),其值为附加数据段的段值;SS——堆栈段寄存器(StackSegmentRegister),其值为堆栈段的段值;FS——附加段寄存器(ExtraSegmentRegister),其值为附加数据段的段值;GS——附加段寄存器(ExtraSegmentRegister),其值为附加数据段的段值。5个别语句解释002E13F3subesp,0CCh;(1)002E13F9pushebx:(2)002E13FApushesi;(3)002E13FBpushedi;(4)002E13FCleaedi,[ebp-0CCh];(5)002E1402movecx,33h;(6)002E1407moveax,0CCCCCCCCh;(7)002E140Crepstosdwordptres:[edi];(8)(1)表示栈指针减去occh,就是开辟0cch的栈内存空间来存放临时变量(2)保存ebx到栈内存(3)保存esi到栈内存(4)保存edi到栈内存(5)将临时变量的最低内存地址放到edi中(6)Ecx寄存器设置一个计数次数33h=51(十进制)(7)将eax初始化为0CCCCCCCCh(8)这个语句有点复杂,它涉及到EAX,ECX,ES,EDI,这么多的寄存器。其中rep表示重复执行这个语句,重复的次数由ECX中数字决定;STOS表示字符串保存指令,它把AL或者AX,或者EAX中的数据复制到目标串ES:EDI。每重复一次,ECX中的数字减1,EDI中的值加4,直到EDI中值跟EBP的值相等(这个时候表示给临时变量分配的栈空间已经初始化完毕,都已经初始化为0CCCCCCCC)。从中我们可以看出经常见到的我们自己未初始化的整形变量,编译器都会把它初始化为0CCCCCCCC。

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
关闭