0%

C语言1-空函数、裸函数、调用预定、数据宽度、全局变量&局部变量

C语言1-空函数、裸函数、调用预定、数据宽度、全局变量&局部变量

杂项放到最后了

空函数

空函数

1
2
3
void function(){
;
}

注:hook,跳过原函数的东西,运行我们自己的函数。比如说把call指令前面的东西换成jmp,跳转到我们自己写的函数。

空函数是有初始化的,有call有ret

裸函数

1
2
3
void _declspec(naked) function(){

}

加上了裸函数关键字之后,就相当于告诉编译器,不用管我们的堆栈,不用初始化,全部都由我们自己弄。这个就没有初始化了,没有call没有ret

所以我们需要自己编写汇编语句,需要用到一个关键字,_asm

1
2
3
4
5
void _declspec(naked) function(){
_asm{

}
}

调用约定

_cdecl 从右往左入栈 调用者清理堆栈 外平线(默认)他会自己去平衡堆栈,他是在函数外面平衡堆栈,所以函数内部就不用平衡堆栈了,也就是降低栈。

image-20231231222606782

_stdcall 从右往左入栈 自身清理堆栈 内平线

而这个是在函数内部进行堆栈平衡,

image-20231231224037381

_fastcall将前两个参数用ecx edx传入,剩下的参数从右往左入栈 自身清理堆栈 内平线

这个只有前两个参数是存在寄存器(从左往右数),后面的参数是存在内存的。

数据宽度

主要分为整数类型和浮点数类型

整数类型:

char 8bit 1字节 对应byte
short 16bit 2字节 对应word
int 32bit 4字节 对应dword

有符号数和无符号数

有符号数:会把第一位当作符号,所以范围是-128127
无符号数:8个位全可以用,所以范围是0
255

1
2
3
4
5
6
7
char c =128; //这个就是越界了
unsigned char u = 128; //这就就是不越界
//但是在汇编语句中,有符号数和无符号数的表现形式是一样的
//只有在运算的时候是不一样的
//运算的时候有什么不一样呢?
//他们运算的时候都jcc语句的比较是不一样的
//有符号数的jcc语句是jle,无符号数是jbe

而在c语言中如何分别有符号数和无符号数呢?
unsigned关键字就是无符号数(之前我的blog有写)

全局变量/局部变量

全局变量是整个程序可访问的变量,生存期从程序开始到程序结束;局部变量存在于模块中(比如某个函数),只有在模块中可以访问,生存期从模块开始到结束。

全局变量分配在全局数据段,在程序开始运行的时候被加载,局部变量则分配在程序的堆栈中。因此,操作系统和编译器可以通过内存的分配位置来知道区分全局变和局部变量。

全局变量和局部变量的区别是在存储器中的位置不同,具体说,全局变量存储在数据段中,局部变量一般存在堆栈段 。

全局变量
1.全局变量的地址在程序编译时就已经确定,如果没有赋初始值则为0
2.全局变量可以被所有函数修改,存储的是最后一个函数所赋的值。
3.全局变量占用的内存会一直存在,知道进程结束。
4.反汇编:mov 寄存器,dword ptr ds:[0x1234567]
5.初始化可以不赋初值

局部变量
1.局部变量没有固定地址,需要在调用的时候才会在堆栈里面分配内存
2.局部变量执行完毕之后数据仍然保存在堆栈,但已经没有作用
3.只在函数内部使用,不能跨函数调用
4.反汇编:mov eax,[esp-4]
5.初始化必须赋初值

杂项

1.如果写东西出现0xc0005出来,那么很有可能是地址不正确

2.一般函数的过程

1
2
3
4
5
1.提栈
2.保存现场
3.填充缓冲区
4.函数的核心功能
5.恢复现场