C代码+汇编 C的 函数汇编学习分析 rep stos dword ptr [edi] 落日映苍穹つ 2021-10-18 07:34 383阅读 0赞 如分析有误,请在评论区中,指出 谢谢合作 主要是分析C的函数调用在汇编中的执行流程 本章主要是说一下**函数调用时堆栈的变化**,重点理解部分 C代码 #include"stdafx.h" int plus(int x,int y){ return x+y; } int main() { plus(0,1); return 0; } 汇编代码 VC6.0++ 反编译所得 (如分析有误,请在评论区提出,谢谢) //函数部分 0040100A jmp plus (00401010) //跳转到 00401010内存位置 0040100F int 3 //无视 00401010 push ebp //ebp压栈 00401011 mov ebp,esp // esp的值 赋给 ebp 00401013 sub esp,40h //esp = esp-40H //esp寄存器是栈首位置,相当于提升堆栈,开辟 00401016 push ebx //压栈 00401017 push esi //压栈 00401018 push edi //压栈 00401019 lea edi,[ebp-40h] //将ebp的内存地址 - 40H 后所得的内存地址 赋值给 edi寄存器 0040101C mov ecx,10h 将 10H (16) 赋给 ecx寄存器 00401021 mov eax,0CCCCCCCCh 将 ,0CCCCCCCCh 赋值给eax 00401026 rep stos dword ptr [edi] //循环 ecx的次数 00401028 mov eax,dword ptr [ebp+8] //将ebp+8的内存地址的值 赋给 eax 0040102B add eax,dword ptr [ebp+0Ch] // eax = eax + (ebp+0Ch)的值 0040102E pop edi //弹出栈 0040102F pop esi //弹出栈 00401030 pop ebx //弹出栈 00401031 mov esp,ebp //恢复堆栈 00401033 pop ebp //弹出栈底 00401034 ret //相当于 pop eip //main函数部分 0040B76E push 1 //压栈 因为C函数的调用约定 '__stdcall', plus(0,1); 参数从右向左压入堆栈 0040B770 push 0 //压栈 0040B772 call @ILT+5(plus) (0040100a) 0040B777 add esp,8 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70] # 一步一步来,这里的话 需要画图哈.别急 # ## 前置条件: ## 堆栈的特点是 前大后小(内存地址) 本章是 32位寄存器 所以一次性 4 main函数中, (栈首)esp的寄存器的值为 0019FEF4 , (栈尾)ebp的寄存器的值为 0019FF40 **自绘图** ![在这里插入图片描述][20190811002146805.png] **汇编图** ![在这里插入图片描述][20190811001450930.png] ## 代码逻辑执行开始,主要是堆栈的变 ## **------1** 0040B76E push 1 //压栈 因为C函数的调用约定 '__stdcall', plus(0,1); 参数从右向左压入堆栈 0040B770 push 0 //压栈 0040B772 call @ILT+5(plus) (0040100a)0040B777 0040B777 add esp,8 **push压栈时: 修改的 esp(栈顶的值) -4** 执行前三句:结果如图 前两句应该很好理解 **call指令,在指令执行的时候,会把call的内存地址 下一行的内存地址 压入堆栈中** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 1] **--------2** 0040100A jmp plus (00401010) //跳转到 00401010内存位置 0040100F int 3 //无视 00401010 push ebp //ebp压栈 第一行跳转,不用多说 第二行无视 第三行: push ebp//将堆栈的底,压入到内存地址 ![!\[在这里插入图片描述\](https://img-blog.csdnimg.cn/20190811004105562.png?x-oss-process=image/watermark,type\_ZmFuZ3poZW5naGVpdGk,shadow\_10,text\_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy,size\_16,color\_FFFFFF,t\_70][https_img-blog.csdnimg.cn_20190811004105562.png_x-oss-process_image_watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70] 00401011 mov ebp,esp 00401013 sub esp,40h // 40h = 64(十进制) 第一句 ebp = esp,含义为 执行这个函数开辟内存 ![在这里插入图片描述][20190811005451219.png] 第二局 esp的内存地址 减去40H = 19FEA4 个人见解:提升堆栈 40H=64(十进制) 因为32寄存器 堆栈为4 所以就是提升 64/4= 16 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 2] 00401016 push ebx //压栈 00401017 push esi //压栈 00401018 push edi //压栈 00401019 lea edi,[ebp-40h] //将ebp的内存地址 - 40H 后所得的内存地址 赋值给 edi寄存器 前三句没什么好说的 就是压栈 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 3] lea edi,\[ebp-40h\] //这句话就有点意思了。 ebp-40H就是刚才 esp-40H的地址一样的,将值赋值给EDI ## 高能从这里开始 就比较有意思了 ## 0040101C mov ecx,10h //重复次数 00401021 mov eax,0CCCCCCCCh //eax = 0XCCCCCCCC 00401026 rep stos dword ptr [edi] // 第一句 ecx寄存器一般用来计数, 10H = 16(十进制) 跟我们刚才 ESP-40H 的内存地址也是16个 第二句 将0CCCCCCCCh 赋值给EAX寄存器 第三句 rep stos 【repeat(重复) store(保存) string】 指令解析 **rep** 重复前缀指令,英文缩写 repeat,每执行一次, ecx 减 1,直到 ecx 减至0,重复执行结束 **stos** 串存储指令,英文缩写 store string ,将 eax 中的数据传送到目的地址(目的地址**默认**edi寄存器), 以下两条指令相当于一条 stos 指令 mov [edi], eax add edi, 4 ;或者 sub edi, 4 // 至于到底是加 4 还是减 4 ,是由方向标志 DF 来决定,可以由指令 cld 和 std 指令设置 cld: 从低地址往高地址传送 std: 从高地址往低地址传送 首次执行的汇编图 ![为 es:\[][es] 10H = 16(十进制) 所以rep就是执行16次,所得结果如图 汇编图: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 4]自绘图 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 5] 00401028 mov eax,dword ptr [ebp+8] 0040102B add eax,dword ptr [ebp+0Ch] 自绘图可以明显看到 ebp+8 与 ebp+0ch 也就是函数传参的两个值 也就是C代码 **x+y**; 0040102E pop edi //弹出栈 0040102F pop esi //弹出栈 00401030 pop ebx //弹出栈 这三句都是出栈, 注意出栈后esp的栈顶指针会+4 这三句的自绘图,这时esp的栈顶指针的内存地址为 19FEA4 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 6] # 这三句是本章重点 # 00401031 mov esp,ebp 00401033 pop ebp 00401034 ret 自绘图,这三句执行前的堆栈图 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 7] mov esp,ebp 当执行 的时候,堆栈的 栈顶与栈尾在同一个位置 ![在这里插入图片描述][20190811102152982.png] 00401033 pop ebp 因为执行pop 所以 **esp的栈顶指针**(0019FEE4)+4 = (0019FEE8) 因为 **pop弹出的是堆栈 所以 ebp的值会回到 上一次的位置 也就是 0019FF40**(有疑问请看第一张自绘图,这里比较难理解,多看几遍,建议手画一画图) ret //pop eip ret指令用栈中的数据,修改偏移地址,从而实现近转移 就相当于 pop eip 所以ESP栈顶指针(0019FEE8) +4 = (0019FEEC),这时的堆栈图 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 8] 0040B777 add esp,8 //esp (0019FEEC)+8 = 0019 FEF4 这句就是函数的堆栈平衡,也就是操作数据时,开辟堆栈内存.用完了以后又恢复到 调用函数之前的位置: 最后的自绘图 ![在这里插入图片描述][20190811103738347.png] # 总结: # 1.调用函数的时候,堆栈会为函数执行开辟内存, 00401011 mov ebp,esp 00401013 sub esp,40h 2.调用函数时 用的是Call指令,并且会开辟空间,把函数的参数压栈,并且把后一个eip地址也压栈 特点: 1.会先将**ebp栈底指针**压栈,还有一些寄存器 首要特点**push ebp ,mov ebp,esp** 2.Call函数后面的那一句 一般是堆栈平衡的代码 //mai部分 0040B76E push 1 0040B770 push 0 0040B772 call @ILT+5(plus) (0040100a) //函数部分 00401010 push ebp 00401011 mov ebp,esp 00401013 sub esp,40h 00401016 push ebx 00401017 push esi 00401018 push edi 00401019 lea edi,[ebp-40h] 整理不易,花了好几个小时,有任何问题请在评论区指出,喜欢的话,点个关注或者喜欢哈 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70]: /images/20211018/138e819d3141426aaf1c4a4faa448f8a.png [20190811002146805.png]: /images/20211018/868d160440884ee39c865f5d83c185cb.png [20190811001450930.png]: /images/20211018/0c67cb7dd3b54a4eb3e529290b2b1f0d.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 1]: /images/20211018/20273778ccbb48deb0f32def7ccd3e2d.png [https_img-blog.csdnimg.cn_20190811004105562.png_x-oss-process_image_watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70]: /images/20211018/36a17f41f59e4c4fb7b5ebb46cb674b9.png [20190811005451219.png]: /images/20211018/9307004333c24e418b910af55652d8da.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 2]: /images/20211018/06396ce9134d43548128cd4c3c652dcd.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 3]: /images/20211018/cc48bc2ffecf4d84a9d20c5809f9db55.png [es]: https://img-blog.csdnimg.cn/20190811095508845.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 4]: /images/20211018/4f0019efe5494bef9fa15da487fdef4e.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 5]: /images/20211018/48ac371ef8d94cdd85ba7160d85a9acd.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 6]: /images/20211018/2479cbbe69d9464cbbb4e801a1dc40b3.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 7]: /images/20211018/d385813cde0b419e8535db45de73ea07.png [20190811102152982.png]: /images/20211018/3718a3c6627044a3b4e1f0599ef50c33.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1MzQ5OTgy_size_16_color_FFFFFF_t_70 8]: /images/20211018/2373d188c4374dbca8bb270bfdb23e1d.png [20190811103738347.png]: /images/20211018/3a2f78c5f85549e8b5b559452159e6fa.png
还没有评论,来说两句吧...