吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 12024|回复: 20
收起左侧

[调试逆向] 逆向分析:如何一步步还原C代码

  [复制链接]
shavchen 发表于 2019-10-22 15:38
本帖最后由 shavchen 于 2019-10-23 10:38 编辑

逆向实战

应各位的建议,加了注释,喜欢的看官点个赞支持一下,哈哈!

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

程序入口

image.png

如何查找程序入口?

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

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

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

image.png

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

main函数

image.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函数

image.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函数

image.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函数

image.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函数

image.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));
}



免费评分

参与人数 6威望 +1 吾爱币 +12 热心值 +6 收起 理由
moyunrz + 1 + 1 谢谢@Thanks!
Hmily + 1 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Aksa + 1 + 1 谢谢@Thanks!
quandu + 1 + 1 建议楼主把哪一部分怎么得到的原理简单提一下,对我们小白来说理解或者去百.
椎名牧 + 1 + 1 用心讨论,共获提升!
dechong + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| shavchen 发表于 2019-10-23 10:02
yaoyao7 发表于 2019-10-23 09:11
我感觉你可以再加一点说明的东西,类似于注释的那种,就比如关键寄存器里放的是什么之类的,新手看起来就会 ...

嗯嗯可以,下次写文章的时候注意
yaoyao7 发表于 2019-10-23 09:11
我感觉你可以再加一点说明的东西,类似于注释的那种,就比如关键寄存器里放的是什么之类的,新手看起来就会很轻松了。个人建议~
syc_song 发表于 2019-10-22 16:57
 楼主| shavchen 发表于 2019-10-22 18:00
本帖最后由 shavchen 于 2019-10-22 18:02 编辑

对啊,挺简单的一个程序
相关知识点:
调用约定:cdecl ,fastcall ,stdcall
堆栈平衡
yer 发表于 2019-10-22 20:38
摩拜!感谢分享!
飞爱甜 发表于 2019-10-22 20:40
很实用!
yb98 发表于 2019-10-23 05:35


感谢分享~感谢分享
whatdos 发表于 2019-10-23 08:45
感谢分享......
头像被屏蔽
seed 发表于 2019-10-23 09:44
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-1 07:16

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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