C语言逆向汇编——参数局部变量、函数堆栈、调用约定和内嵌汇编码
第一节 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
#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
#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 x
,x表示参数的字节数
)
第二节 2.7内联汇编实现功能
#include <iostream>
#include<Windows.h>
#include<stdio.h>
/*
-----------------------
-----------------------
编写内联汇编,实现功能
-----------------------
-----------------------
int plus(int x, int y, int z)
{
int a = 2;
int b = 3;
int c = 4;
return x + y + z + a + b + c;
}
*/
int __declspec(naked) function(int x, int y, int z)
{
__asm
{
//提升堆栈
push ebp
mov ebp,esp
sub esp,0x40
//保护现场
push edi
push ebx
push esi
//填充缓冲区
lea edi,dword ptr ss:[ebp-0x40]
mov eax,0xcccccccc
mov ecx,0x10
rep stosd
//功能实现
// return x + y + z + a + b + c;
//3个参数:(1, 2, 3)
//3个局部变量:int a = 2 ; int b = 3 ; int c = 4
// [ebp-0x4] ; [ebp-0x8] ; [ebp-0xc]
mov dword ptr ds : [ebp-0x4],2
mov dword ptr ds : [ebp - 0x8],3
mov dword ptr ds : [ebp - 0xc],4
mov eax, dword ptr ds : [ebp + 0x8]
add eax, dword ptr ds : [ebp + 0xc]
add eax, dword ptr ds : [ebp + 0x10]
add eax, dword ptr ds : [ebp - 0x4]
add eax, dword ptr ds : [ebp - 0x8]
add eax, dword ptr ds : [ebp - 0xc]
//还原现场
pop esi
pop ebx
pop edi
//降低堆栈
mov esp,ebp
pop ebp
//返回
ret
}
}
int main()
{
function(1, 2, 3);
system("pause");
return 0;
}
运行验证下: