C逆向-汇编眼中的函数

本文详细阐述了汇编语言中的裸函数概念,包括其定义方式、函数调用过程、参数传递策略(如寄存器和堆栈传递)、以及局部变量的使用。重点讲解了x86架构下的返回值管理和示例代码演示。
摘要由CSDN通过智能技术生成

汇编眼中的函数

裸函数

裸函数是一种不使用函数预定义的函数框架(prologue)和函数结束的代码(epilogue)的函数,需要自己处理函数入口和出口的任务,还有保持堆栈的平衡等等

  • 定义方式:返回值类型 _declspec(naked) 函数名 (参数列表)

    返回值类型 _declspec(naked) 函数名 (参数列表)
    {
    	__asm
    
    	{
    
    		PUSH EBP							//保存old_EBP,保持堆栈平衡
    
    		MOV EBP,ESP							//抬高栈底
    
    		SUB ESP,0X40						//开辟缓冲区
    
    		PUSH EBX							//保存易变寄存器
    		PUSH ESI
    		PUSH EDI
    
    		LEA EDI,DWORD PTR DS:[EBP - 0X40]	//填充缓冲区
    		MOV EAX,0XCCCCCCCC
    		MOV ECX,0X10
    		REP STOSD
    
    		//函数内语句
    
    		POP EDI								//弹出易变寄存器
    		POP ESI
    		POP EBX
    
    		MOV ESP,EBP							//降低栈顶
    
    		POP EBP								//恢复old_EBP
    
    		RET									//跳出函数
    
    
    	}
    
    
    }
    
函数调用

在汇编语言中,函数调用涉及到将控制权从一个函数转移至另一个函数。通常,函数调用包括以下步骤:

  1. 参数传递: 将参数传递给被调用函数。参数可以通过寄存器、堆栈或其他机制传递。
  2. 调用: 使用call指令将程序的控制权转移到被调用的函数。
  3. 函数体执行: 被调用函数的代码开始执行,处理传递的参数,执行函数体内的指令。
  4. 返回: 使用ret指令将控制权返回到调用函数的下一条指令.
PUSH DWORD PTR DS:[EBP - 0X4]	//传递参数
PUSH 0X1						//传递参数

CALL FUN1						//调用函数

ADD ESP,0X8						//清理栈区的参数

MOV DWORPD PTR DS:[EBP - 0X8]	//获取返回值

XOR EAX							//清零寄存器
局部变量
  • 局部变量反汇编识别: [EBP - XXX] (__fastcall 调用约定的函数,参数通过ECX和EDX传递进函数内之后,也会把参数存储在EBP-XXX)
  • 局部变量是通过占空间保存的
  • 因为局部变量使用栈空间进行存储,所以进入函数后的第一件事就是开辟函数中的局部变量所需的栈空间(缓冲区).这时函数中的局部变量就有了存储的内存空间,在函数结尾处执行释放栈空间的操作.因此局部变量是有生命周期的,他的生命周期在进入函数体的时候开始,在函数执行结束的时候终止.
PUSH EBP							//保存旧的栈底指针

MOV EBP,ESP							//设置新的栈底指针

SUB ESP,0X40						//开辟缓冲区

PUSH EBX							//保存易变寄存器
PUSH ESI
PUSH EDI

LEA EDI,DWORD PTR DS:[EBP - 0X40]	//填充缓冲区
MOV ECX,0X10
MOV EAX,0XCCCCCCCC
REP STOSD

MOV DWORD PTR DS:[EBP - 0X4],0X1	//创建变量
MOV DWORD PTR DS:[EBP - 0X4],0XA


POP EDI								//恢复易变寄存器
POP ESI				
POP EBX

MOV ESP,EBP							//恢复栈顶
POP EBP								//恢复旧的栈底指针
RET									//返回
返回值

在x86架构中,通常使用 eax 寄存器来存储函数的返回值。

//函数调用--------------------------------------------

CALL fun1							//函数调用
MOV DWORD PTR DS:[EBP - 0X4],EAX	//获取返回值
XOR EAX								//清零寄存器

//设置返回值-------------------------------------------

PUSH EBP							//保存旧的栈底指针
MOV EBP,ESP							//设置新的栈底指针
SUB ESP,0X40						//开辟缓冲区

PUSH EBX							//保存易变寄存器
PUSH PSI
PUSH EDI

MOV EAX,0XCCCCCCCC					//填充缓冲区
MOV ECX,0X10
LEA EDI,DWORD PTR DS:[EBP - 0X40]
REP STOSD

MOV DWORD PTR DS:[EBP - 0X4],0X1	//int a = 1;
MOV DWORD PTR DS:[EBP - 0X8],0X2	//int b = 2;

MOV EAX,DWORD PTR DS:[EBP - 0X4]	//b= a + b;
ADD EAX,DWORD PTR DS:[EBP - 0X8]
MOV DWORD PTR DS:[EBP - 0X8],EAX

MOV EAX,DWORD PTR DS:[EBP - 0X8]	//return b;

POP EDI								//恢复易变寄存器
POP ESI
POP EBX

MOV ESP,EBP							//恢复栈顶
POP EBP								//恢复旧的栈底指针
RET									//返回

  • 参数

    在汇编语言中,参数的传递方式取决于所使用的体系结构和编程规范。通常,参数可以通过寄存器、堆栈或者一些其他机制来传递。以下是一些常见的参数传递方式:

    1. 寄存器传递: 一些寄存器用于传递函数的参数。不同的体系结构和编程规范可能会指定不同的寄存器用于参数传递。在x86架构中,eaxebxecxedx 寄存器通常被用于参数传递。
    2. 堆栈传递: 参数可以通过将它们推送(push)到堆栈上来传递。被调用函数可以通过弹出(pop)来获取这些参数。在x86架构中,参数通常从右向左入栈,因此第一个参数会被放在最后入栈的位置。
     int a = Fun2(1,2);
    
    //函数调用
    push 2								//传递第二个参数
    PUSH 1								//传递第一个参数
    
    CALL Fun2							//调用函数
    
    ADD EBP,0X8							//清理栈区参数
    
    MOV DWORD PTR DS:[EBP - 0X4],EAX	//接收返回值
    XOR EAX,EAX							//清零寄存器
    
    
    int Fun2(int a,int b)
    {
    	int c = a + b;
    	return c;
    }
    
    //函数体内部
    
    PUSH EBP							//保存旧的栈底指针
    MOV EBP,ESP							//设置新的栈底指针
    SUB ESP,0X40						//开辟缓冲区
    
    PUSH EBX							//保存易变寄存器
    PUSH ESI
    PUSH EDI
    
    LEA EDI,DWORD PTR DS:[EBP - 0X40]	//填充缓冲区
    MOV EAX,0XCCCCCCCC
    MOV ECX,0X10
    REP STOSD
    
    MOV EAX,DWORD PTR DS:[EBP + 0X8]	//int a = 参数一 + 参数二
    ADD EAX,DWORD PTR DS:[EBP + 0XC]
    MOV DWORD PTR DS:[EBP - 0X4]
    
    MOV EAX,DWORD PTR DS:[EBP - 0X4]	//设置返回值
    
    POP EDI								//恢复易变寄存器
    POP ESI
    POP EBX
    
    MOV ESP,EBP							//降低栈顶
    
    POP EBP								//获取旧的栈底指针
    
    RET									//返回
    
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值