专栏首页逆向技术逆向知识十一讲,识别函数的调用约定,函数参数,函数返回值.

逆向知识十一讲,识别函数的调用约定,函数参数,函数返回值.

      逆向知识十一讲,识别函数的调用约定,函数参数,函数返回值.

在反汇编中,我们常常的会看到各种的函数调用,或者通过逆向的手段,单独的使用这个函数,那么此时,我们就需要认识一下怎么识别函数了.

一丶识别__cdecl 函数(俗称C Call),函数参数,函数返回值

首先写一个C Call的函数

1.返回值 int类型, 参数int 类型

高级代码:

int __cdecl MyAdd(int a,int b)
{
    return a + b;
}
int main(int argc, char* argv[])
{
    MyAdd(3,4);
    return 0;
}

main函数调用我们的自己写的

Debug下的汇编代码

在Debug版本下的调用处,我们会看到这种代码,没有流水线优化,没有任何优化

看到了,两个push,紧接着一个Call,然后平栈在外面

识别参数

  有经验的可能会说两个push 就是两个参数,其实不然,我们要进入函数内部,看内部的代码用了几个参数,要通过这个来识别.

  有两处使用,所以是两个参数. 而且直接给eax反回了,此时我们就可以在main函数位置,调用此函数的位置往上数几个push了,这些push才是属于自己这个函数的.

识别参数类型:

  参数类型还是很好识别了,使用参数的地方用的直接是4个字节的寄存器,那么我们可以暂定为int类型

识别调用约定

  如果在函数外面平栈,那么就是C调用约定,从识别参数来看,函数内部的 retn并没有平栈.

 识别返回值

  从上面的识别参数我们看到,eax重新写入了,那么返回值就是int类型

Release版本下的汇编

Release版本和Debug版本差不多一样,优化了少许代码,但是核心代码不变

总结:

1.识别参数,看其函数内部使用了几个参数,然后在函数调用的地方往上数几个push这些是属于自己函数的.

  2.识别参数类型,看其参数是怎么使用.

  3.识别调用约定,看其函数内部是否平栈

  4.识别返回值类型,看其eax是否是被重写,如果被重写,则是返回值是int类型

2.返回值 __int64 C调用约定,参数是浮点和double的情况下

高级代码:

__int64 __cdecl MyAdd(float a,double b)
{
    return a + b;
}
int main(int argc, char* argv[])
{
    MyAdd(3,4);
    return 0;
}

Debug下的汇编代码

1.main 函数调用处

2.函数内部

3.函数内部调用的__ftol

讲解:

  1.识别C约定和上面一样,外面平栈

  2.识别参数,看其我们的的函数调用处,发现有三个push,如果不知道,则会陷入坑,直接认为是三个参数.,但是跟随到函数内部,我们发现只有两个参数,而第二个参数是double,所以在32位下要push 两个四字节,其中高位是0,低位是常量(4)的浮点编码.

  3.识别参数类型,在MyAdd内部,发现了两处使用参数的地方,用的指令分别是 fld 和fadd指令,这些都是浮点相关的.

识别技巧.

  fld指令 将实数压入浮点协处理器,那么此时我们看下汇编指令,(使用IDA的K命令,可以不是符号显示,也就是下方贴出的汇编指令)

FLD 第一个是一个Dword 那么可以确定为是一个32位浮点

Fadd指令,使用Fadd指令的时候,发现是第二个QWORD,难么可以确定是一个double类型的浮点.功能的还原和汇编逆向前10讲一样,里面都是各种流程和指令

  4.识别返回值,在识别返回值的时候,我们发现调用了一个_ftol函数,看到这个函数可以确定返回的是一个__int64,当然我们进入函数内部看到了

下方使用eax 和edx了,而且直接反会了,那么我们知道,在32位系统下,返回一个64位数字,在汇编中的表现形式就是edx.eax的存储方式.

Release版本下的汇编

熟悉总结的四句话,以不变应万变即可,因为类型都不一样.

二丶识别stdcall  函数参数,返回值,参数类型

stdcall比较简单.但是和fastcall还是有区别的.因为fastcall会有寄存器传参,所以把两个的区别搞明白就可以了.

高级代码:

__int64 __stdcall MyAdd(float a,double b,int c)
{
    return a + b + c;
}
int main(int argc, char* argv[])
{
    MyAdd(3.0f,4.0f,6);
    return 0;
}

直接一次性的把各种参数类型,以及返回值设置不一样.观看汇编

Debug下的汇编代码

1.函数调用处

2.MyAdd函数内部

1.识别函数的参数,发现了push 4个进去,但是不要被骗了,在MyAdd内部 分别得出了使用三个参数的位置,所以得出第一个参数为  float 第二个参数类型是 double,第三个参数 是int,又因为其中有一个double参数,所以在调用外面可以看到4个push,因为double是8个字节

2.识别参数个数,stdcall最好的就是它是内部平栈,也就是retn 10h,当然也可以通过这个来判断函数参数的个数

3.识别函数返回值类型

  函数返回值类型,在MyAdd中调用了_ftol函数,其内部则是返回__int64,返回值是 edx.eax

Release下的汇编

和Debug汇编一样,有少许优化.

总结:

  1.识别参数类型: 识别参数类型可以通过函数内部使用参数的时候用的指令,比如第一个 float,使用的是fld指令,fld系列指令就是操作浮点的,而又因为它是一个dword,所以判断是float,第三个参数是一个int,使用的是fixxx指令,fixxx指令就是操作的整数,因为它也是一个dword所以判断是int(当然可以看函数参数使用过程中其指令使用的时候表明这个参数是什么类型的)

  2.识别参数个数, 识别参数个数在stdcall中有两种方式,第一种,直接看内部指令使用参数的地方,第二种,看平栈的时候平了多少.比如上面的例子, retn 10h(16),也就是4个参数的大小,但因为double是8字节,所以判断是三个参数

  3.识别返回值,识别返回值 如果是int指令,那么返回值则放在eax中,如果是__int64指令,返回值则是在 edx.eax中,如果是浮点返回值,返回值则是在浮点协处理器中.

  4.识别调用约定,函数内部平栈,如果没有寄存器传参则是stdcall,如果有寄存器传参,则是fastcall

三丶识别 fastcall 函数,参数个数,参数类型,返回值

高级代码:

double __fastcall MyAdd(float a,double b,int c)
{
    return a + b + c;
}

float __fastcall MySub(__int64 a,int b)
{
    return a - b;
}
int main(int argc, char* argv[])
{
    MyAdd(3.0f,4.0f,6);
    MySub(4,3);
    return 0;
}

Debug下的汇编代码

  1.main函数调用的时候的汇编代码

  2. MyAdd函数内部

  3.MySub函数内部

    1.识别调用约定, 我们看MyAdd内部,还是MySub内部,里面都是用了外面传入的ecx,并且没有保存.那么fastcall就是ecx传参了.平栈和stdcall一样,函数内部平栈

    2.识别函数的个数,识别函数的个数也有两种方法,第一种,看retn的时候,然后加上寄存器, 我们看myadd内部,retn 0ch,平了3个参数,但外面更改了ecx,里面使用了ecx,那么就是4个参数,但因为其中一个参数类型是double,所以还是三个参数.

    3.识别参数类型,看指令来判断是什么类型,fld指令是浮点,fixxx指令则是使用的int,如果看edx.eax并且符号扩展了,则是__int64

    4.上面返回值类型么有更改为doubLe和float,可以看出,在main函数下面是用浮点的出栈指令 fstp指令,从浮点协处理器出栈,浮点协处理器是64位的,所以返回double

总结:

  1.调用约定,如果是c call那么外面平栈,stdcall函数内部平栈,fastcall函数内部平栈,但是会使用外面的寄存器.

  2.识别参数个数,类型,同上

  3.识别返回值,同上.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 网络编程第六讲Select模型

        以前我们讲过一个迭代模型.就是只服务一个客户端连接.但是实际网络编程中.复杂的很多. 比如一个 C/S架构程序 (客户端/服务端) 客户端很多的情况下....

    IBinary
  • C语言第八讲,指针*

                C语言第八讲,指针* 一丶简单理解指针 说到指针,很多人都说是C语言的重点. 也说是C语言的难点. 其实指针并不是难.而是很多人搞不清地...

    IBinary
  • Detours HOOK 库 过滤LoadLibraryExW

    Detours是微软提供的HOOK库.为我们Hook提供了方便.再也不用手撸 HOOK了.当然手撸比较好.可以锻炼.不过工作中要求效率.所以使用这个库. 这个...

    IBinary
  • 微信开发 原

    微信公众平台是运营者通过公众号为微信用户提供资讯和服务的平台,而公众平台开发接口则是提供服务的基础,开发者在公众平台网站中创建公众号、获取接口权限后,可以通过阅...

    wuweixiang
  • 如果希望监听TCP端口9000,应该怎样创建socket?

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

    大黄大黄大黄
  • zip压缩以及tar打包

    叶瑾
  • JAVA代码覆盖率工具JaCoCo-踩坑篇

    JAVA代码覆盖率工具JaCoCo-原理篇和JAVA代码覆盖率工具JaCoCo-实践篇已经给大家介绍过了,本篇为踩坑篇,这里的话题不是说明JaCoCo有什么问题...

    腾讯移动品质中心TMQ
  • 戈登·贝尔奖2017终选名单公布,2/3来自中国,基于神威·太湖之光

    【新智元导读】国际高性能计算应用领域最高奖——戈登贝尔奖今年的终选名单公布,一共三篇论文中有两篇来自中国、基于“神威·太湖之光”。 国际高性能计算应用领域最高奖...

    新智元
  • 更新c++学习笔记 第三章

    定义:就是在声明函数的某个参数的时候为之指定一个默认值,在调用该函数的时候如果采用该默认值,你就无须指定该参数。

    互联网CEO
  • 运维python进行(一) nmap扫描

    最近为了加强服务器安全性和监管,需要每天把公司服务器开放端口扫描记录,一旦出现增加减少能发现。

    py3study

扫码关注云+社区

领取腾讯云代金券