push 如何get传参_逆向分析:如何一步步还原C代码

逆向实战

逆向CallingConvention.exe,还原为C代码,记录过程。

程序入口

4aa5810b45e8cf9365175b3d1979cb92.png

如何查找程序入口?

main 函数被调用前要先调用的函数如下:

GetVersion()    
_heap_init()    
GetCommandLineA()   
_crtGetEnvironmentStringsA()    
_setargv()  
_setenvp()  
_cinit()

这些函数调用结束后就会调用main 函数,根据main 函数调用的特征,将3 个参数压入栈内作为函数的参数。

3ac30f4ea47f4504baf75c7cd3056097.png

回到反汇编图,我们可以看到OD给我们注释出来的GetCommandLineA()函数下面紧接着push了三个寄存器,这就是我们判断程序入口最简单的方法了!

main函数

12287ed42db1120212a509d7b72d2d70.png

简要分析:

这里通过push压入了三个参数,通过mov 寄存器,立即数传入了两个参数,符合__fastcall调用约定的传参"手法";因为__fastcall的传参顺序是从右往左,因此函数1的调用如右:func1(1,3,4,6,7)

通过Main函数识别出来程序大致框架如下:

  • 函数3为编译器自动添加的堆栈平衡检查函数,故在此不用考虑。
void __fastcall func1(int a,int b,int c,int d,int e){

}
//函数2我们暂时不知道是什么,先写到这
void  __cdecl func2(int x,int y){

}
void main(int argc,char *argv[])
{
    func1(1,3,4,6,7);
    func2(m,n);
}

func1函数

aebf1ad3f8bbea56798472d1393b33fc.png

简要分析:

mov [local.2],edx实现将mov dword ptr ds:[ebp-8],edx,即给局部变量赋值,不熟悉这部分的朋友可以函数调用与堆栈图分析相关知识点。

这里push了三个参数,并且是在函数内部平衡的堆栈,可以基本判断调用方式为stdcall(这种调用约定在函数内部使用ret n的方式平衡堆栈,待分析func3的时候再论)。

你问我堆栈平衡怎么看,继续往下看吧,紧接着func3向下面分析:

mov [local.3],eax:这句的作用是将调用func3的返回结果eax放到[ebp-0c]中;紧接着又push了两个寄存器,调用func4,并且我们可以看到在call func4之后有条add esp,0x8,这就是堆栈平衡,目的是让堆栈恢复到调用前的状态,由于是在func4外部平衡的堆栈,我们也叫做外平栈,调用约定为C和CPP默认的__cdecl

从以上汇编代码识别出func1的框架如下:

void __fastcall func1(int a,int b,int c,int d,int e){
    int x=1;
    int y=3;
    func3(x,y,c);
    func4();
    func4();
}

func3函数

51e874c2d80743c1b00c42c885629e5e.png

简要分析:

[arg.1]即我们之在main函数看到的传入的第一个参数(最左边的),其它的不再赘述,经过一番加法运算后将返回值放到eax中,看伪代码吧。

func3函数大致框架如下:

int __cdecl func3(int x,int y,it z)
{
    return x+y+z;
}

func1函数补充如下:

void __fastcall func1(int a,int b,int c,int d,int e){
    int x=1;
    int y=3;
    int z=func3(x,y,c);
    func4(x,y);
    func4();
}

这里再提一下,x即[ebp-4],y即[ebp-8],z即[ebp-0c],对应func1函数部分的[local.1],[local.2],[local.3].

func4函数

b032a098d62dfc32b175ff8089973ec4.png

简要分析

同上,不再赘述,直接看伪代码吧!

func4的函数框架如下:

int cdecl func4(int x.int y)
{
    return x+y;
}

func1函数补充如下:

void __fastcall func1(int a,int b,int c,int d,int e){
    int x=1;
    int y=3;
    int z=func3(x,y,c);
    int p=func4(x,y);
    func4(p,z); //运算后eax=0C
}

同理,p代表func1函数部分的[local.4].

到此,func1基本逆向完成,回到main函数,继续func2的逆向,如下:

func2函数

22be73306975f8033c286b263f5e54cc.png

进到func2函数内部,发现其应该是printf函数,那么回到main函数,继续完善,如下:

Main函数

int cdecl func4(int x,int y)
{
    return x+y;
}
void __fastcall func1(int a,int b,int c,int d,int e){
    int x=1;
    int y=3;
    int z=func3(x,y,c);
    int p=func4(x,y);
    func4(p,z); //运算后eax=0C
}
void main(int argc,char *argv[])
{
    printf("%d",func1(1,3,4,6,7));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值