C语言逆向汇编——参数局部变量、函数堆栈、调用约定和内嵌汇编码

发布时间 2023-04-01 09:35:56作者: bonelee
第一节 1.1C语言

1、注意参数局部变量堆栈中的存储方式

2、参数调用函数前就已经存入堆栈,从[EBP+8]、[EBP+C]、……开始。

3、局部变量是在调用函数后,存入缓冲区里,从[EBP-4]、[EBP-8]、……开始

4、函数运算得到的结果,通常存在EAX里


 

 

 

 

 

 

 

 

第一节 1.2逆向汇编

 

 

第一节 1.3练习1

练习1:编写一个函数能够对任意2个整数实现加法,并分析函数的反汇编.

int Plus(int x,int y)

#include <iostream>
#include<Windows.h>

//实现加法功能的函数
int plus(int x,int y)
{
    return x + y;
}

int main()
{
    //调用函数plus();
    plus(1,2);
    system("pause");
}

 

 

第一节 1.4练习2

练习2:编写一个函数,能够对任意3个整数实现加法,并分析函数的反汇编(要求使用上一个函数).

int Plus2(int x,int y,int z)


#include "stdio.h"

int plus(int x,int y)
{
    return x+y;
}

int plus2(int x,int y,int z)
{
    int i = plus(x,y);
    return plus(i,z);
}

void main(int argc,char* argv[])
{
    plus2(1,2,3);
}

 

 

第一节 1.3练习3

3、编写一个函数,能够实现对任意5个整数实现加法(使用Plus1和Plus2).

并分析一个函数的反汇编代码.

int Plus3(int a,int b,int c,int d,int e)


#include "stdio.h"

int plus(int x,int y)
{
    return x+y;
}

int plus2(int x,int y,int z)
{
    int i = plus(x,y);
    return plus(i,z);
}

int plus3(int a,int b,int c,int d,int e)
{
    int i;
    int r;
    i = plus(a,b);
    r = plus2(c,d,e);
    return i+r;
}

void main(int argc,char* argv[])
{
    plus3(5,6,7,8,9);
}
第二节 2.1裸函数与汇编写法

1、裸函数的写法

2、如何在C语言里写汇编代码


 

 

声明一个裸函数后,编译器不会生成任何的代码

 

 


#include <iostream>
#include<Windows.h>

//构造裸函数
int __declspec(naked) plus(int x,int y)
{    
    __asm
    {
        //提升堆栈
        push ebp
        mov ebp,esp
        sub esp,0x40

        //保护现场
        push edi
        push ebx
        push esi

        //填充缓冲区
        lea edi,dword ptr ss:[ebp-0x40]
        mov ecx,0x10
        mov eax,0xcccccccc
        rep stosd

        //加法功能
        mov eax,[ebp+0x8]
        add eax,[ebp+0xc]

        //恢复现场
        pop esi
        pop ebx
        pop edi

        //降低堆栈
        mov esp,ebp
        pop ebp

        ret
    }
}
int main()
{
    plus(1,2);
    system("pause");
}
第二节 2.2调用约定
1、参数是如何传入堆栈?
2、如何平衡堆栈的?

————————————————————————-


调用约定参数压栈平衡堆栈
_cdecl              (C和C++默认的调用约定) 从右至左 调用者清理
_stdcall       API使用的调用约定 从右至左 自身清理
_fastcall ecx/edx传送前两个剩下的从右至左 自身清理(只有2个参数,不需要内平栈)

————————————————————————

_cdecl

cdecl(C declaration,即C声明)是源起C语言的一种调用约定,也是C语言的事实上的标准。

1.函数实参在线程栈上按照从右至左的顺序依次压栈

2.函数结果保存在寄存器EAX/AX/AL中

3.浮点型结果存放在寄存器ST0中

4.编译后的函数名前缀以一个下划线字符    例:sumExample 编译后:_sumExample

5.调用者负责从线程栈中弹出实参(即清栈

6.8比特或者16比特长的整形实参提升为32比特长

7.受到函数调用影响的寄存器(volatile registers):EAX, ECX, EDX, ST0 - ST7, ES, GS

8.不受函数调用影响的寄存器: EBX, EBP, ESP, EDI, ESI, CS, DS

9.RET指令从函数被调用者返回到调用者(实质上是读取寄存器EBP所指的线程栈之处保存的函数返回地址并加载到IP寄存器)

10.堆栈平衡是由调用函数来执行的(在call [地址],之后会有add esp xx表示参数的字节数