12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 326|回复: 0

【原创】反汇编分析递归和自写汇编实现

[复制链接]

303

主题

303

帖子

616

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
616
发表于 2021-7-26 01:01:44 | 显示全部楼层 |阅读模式
摸鱼玩玩汇编递归,咸鱼使我快乐{:301_978:}
汇编递归

这次通过简单的递归例子来分析递归的对应汇编
递归求前n项和

描述

求序列的前n项和。输入一个正整数n,输出1+2+3+4+5+6+...+n的前n项和
输入输出示例

输入

5
输出

15(1+2+3+4+5)
代码

int sum(int n){        if(n==1)return n;        else{                return n+sum(n-1);        }}int main(int argc, char* argv[]){        int result=sum(5);        printf("%d\n",result);        return 0;}运行结果


反汇编代码

函数外部

19:       int result=sum(5);0040D768   push        50040D76A   call        @ILT+10(fib) (0040100f)0040D76F   add         esp,40040D772   mov         dword ptr [ebp-4],eax20:       printf("%d\n",result);函数内部

8:    int sum(int n){0040D6F0   push        ebp0040D6F1   mov         ebp,esp0040D6F3   sub         esp,40h0040D6F6   push        ebx0040D6F7   push        esi0040D6F8   push        edi0040D6F9   lea         edi,[ebp-40h]0040D6FC   mov         ecx,10h0040D701   mov         eax,0CCCCCCCCh0040D706   rep stos    dword ptr [edi]9:        if(n==1)return n;0040D708   cmp         dword ptr [ebp+8],10040D70C   jne         sum+23h (0040d713)0040D70E   mov         eax,dword ptr [ebp+8]0040D711   jmp         sum+37h (0040d727)10:       else{11:           return n+sum(n-1);0040D713   mov         eax,dword ptr [ebp+8]0040D716   sub         eax,10040D719   push        eax0040D71A   call        @ILT+10(fib) (0040100f)0040D71F   add         esp,40040D722   mov         ecx,dword ptr [ebp+8]0040D725   add         eax,ecx12:       }13:   }0040D727   pop         edi0040D728   pop         esi0040D729   pop         ebx0040D72A   add         esp,40h0040D72D   cmp         ebp,esp0040D72F   call        __chkesp (004010e0)0040D734   mov         esp,ebp0040D736   pop         ebp0040D737   ret反汇编分析

函数外部

19:       int result=sum(5);0040D768   push        50040D76A   call        @ILT+10(fib) (0040100f)0040D76F   add         esp,40040D772   mov         dword ptr [ebp-4],eax1.压入参数5
0040D768   push        52.调用函数
0040D76A   call        @ILT+10(fib) (0040100f)3.堆栈外均衡(默认采用cdecl调用协定)
0040D76F   add         esp,44.将返回值eax赋值给result
0040D772   mov         dword ptr [ebp-4],eax函数内部

截取出关键代码
9:        if(n==1)return n;0040D708   cmp         dword ptr [ebp+8],10040D70C   jne         sum+23h (0040d713)0040D70E   mov         eax,dword ptr [ebp+8]0040D711   jmp         sum+37h (0040d727)10:       else{11:           return n+sum(n-1);0040D713   mov         eax,dword ptr [ebp+8]0040D716   sub         eax,10040D719   push        eax0040D71A   call        @ILT+10(fib) (0040100f)0040D71F   add         esp,40040D722   mov         ecx,dword ptr [ebp+8]0040D725   add         eax,ecx12:       }13:   }0040D727   pop         edi1. cmp比较语句
比较参数和1,这里的[ebp+8]=参数n
0040D708   cmp         dword ptr [ebp+8],12.jcc判断跳转语句
jne:jump not equal,不相等则跳转
0040D70C   jne         sum+23h (0040d713)跳转地址:0040d713
10:       else{11:           return n+sum(n-1);0040D713   mov         eax,dword ptr [ebp+8]即跳转到else
3.将返回值赋值给eax
留意这里是前面的跳转语句没执行才能运行的,也就是前面[ebp+8]=1
这里实在就是mov eax,1
0040D70E   mov         eax,dword ptr [ebp+8]4.绝对跳转语句
0040D711   jmp         sum+37h (0040d727)跳转地址:0040d727
0040D727   pop         edi跳转到要返回前的恢复现场的语句
5.将参数赋值给eax
这里属于else的代码,这里相当于eax=参数n
0040D713   mov         eax,dword ptr [ebp+8]6.将eax减1
相当于eax=eax-1,结合前面的eax=参数n,此时eax=参数n - 1
0040D716   sub         eax,17.将eax作为参数压入堆栈
0040D719   push        eax8.再次调用函数自己,实现递归
0040D71A   call        @ILT+10(fib) (0040100f)9.call执行后进行堆栈外均衡
0040D71F   add         esp,410.将参数n赋值给ecx
相当于ecx=n
0040D722   mov         ecx,dword ptr [ebp+8]11.将前面的ecx加给eax
函数返回值存储在eax中,相当于eax=eax+ecx,结合前面的赋值语句,相当于eax=n+sum(n-1)
0040D725   add         eax,ecx自写汇编实现

仅仅是分析汇编显然不够interesting(>人<;),自己用汇编安排它(ง •_•)ง
代码

#include "stdafx.h"int sum(int n){        int address=(int)sum;        int result;        __asm{_if:                cmp n,1                                //比较参数n和1                jne _else                        //如果参数n不等于1则跳转到_else段_match:                mov eax,1                        //将1赋值给eax                mov result,eax                //将eax赋值给result,结合上面相当于mov result,1                jmp _ret                        //绝对跳转到_ret段_else:        mov eax,n                        //将参数n赋值给eax                dec eax                                //让eax自减1,相当于eax=eax-1,结合上面相当于eax=参数n-1                push eax                        //将eax作为参数压入堆栈                call address                //调用函数自身                add esp,4                        //堆栈外均衡                add eax,n                        //相当于eax=eax+n                mov result,eax                //将eax赋值给result_ret:        }        return result;}int main(int argc, char* argv[]){        int result=sum(5);        printf("%d\n",result);        return 0;}代码分析

这次的自写的函数没有使用裸函数,而是直接在代码中插入汇编代码
裸函数干系可前往:逆向基础笔记九 C语言内联汇编和调用协定
代码流程如下:
1.获取函数的地址
int address=(int)sum;由于在汇编中需要调用函数自己,所以需要函数的地址
2.声明一个变量用于存储返回值
int result;3.声明四个代码段

  • _if段:对应if(n==1)的代码段
  • _match段:对应n==1后执行的代码段
  • _else段:对应else的代码段
  • _ret段:对应返回后的代码段,这里为空,采用了c和asm混编的写法,背面直接就是return result
代码段的详细解释已在上面给出,这里不再赘述
总结

递归函数和普通函数的反汇编实在并没用什么特别大的出入,只不过在函数内部调用的函数是自身
函数调用的优先级较其它运算更高(调用函数也可以看作是一种运算),在汇编语句中可以看到是先调用了函数然后再进行的加法
递归函数如果没有正确返回就会不停向堆栈中压入参数,就会导致所谓的递归栈溢出

来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-4-26 23:30 , Processed in 0.093750 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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