滴水逆向三期笔记与作业——02C语言——06 参数_返回值_局部变量_数组反汇编

OneNote防丢失。

一、函数返回值如何传递

1.1 char类型返回

  1. 代码:
c 复制代码
char fun(){
	//代码
	return 12;
}
int main(int argc, char* argv[]){
	char i = fun();
	return 0;
}
  1. 反汇编:
  • 函数返回值,即return 12代码部分
    在fun函数中,将返回值"12"存放在eax中(教程中32位的vc6++是存放在al位置)。

  • 函数返回值赋值给main中的变量

    将一个字节长度的12赋值给rbp-0x1的位置,在教程中32位的vc6++是将1字节长度存放在ebp-4的位置,即move byte ptr ebp-4,al(ebp-4是main函数的缓冲区),同样是仅存储一个字节的长度,编译器的不同会导致程序在空间的利用程度上存在差异

1.2 short类型返回

  1. 代码:
c 复制代码
short fun(){
	//代码
	return 12;
}
int main(int argc, char* argv[]){
	short i = fun();
	return 0;
}
  1. 反汇编:
  • 函数返回值

    short为2字节长度,所以函数中将返回值12存储在eax中,但32位的vc6++中存储在ax中

  • 函数返回值赋值给main中的变量
    将2字节长度的12存储在rbp-0x2的位置,在教程中32位的vc6++是将2字节长度存放在ebp-4的位置,即move word ptr ebp-4,ax

1.3 int类型返回

  1. 代码:
c 复制代码
int fun(){
	//代码
	return 12;
}
int main(int argc, char* argv[]){
	int i = fun();
	return 0;
}

}
  1. 反汇编:
  • 函数返回值

int为4字节长度,所以函数中将返回值12存储在eax中,32位的vc6++中也存储在eax中

  • 函数返回值赋值给main中的变量

将4字节长度的12存储在rbp-0x4的位置,在教程中32位的vc6++是将4字节长度存放在ebp-4的位置,即move dword ptr ebp-4,ea

1.4 作业-long long类型(64位)返回值

  1. 代码
c 复制代码
__int64 fun(){
	//代码
	return 0x1234567890;
}
int main(int argc, char* argv[]){
	__int64 i = fun();
	return 0;
}
  1. 反汇编:
  • 函数返回值

    在64位的环境中,__int64类型的数据存放在rax寄存器中,在32位的环境中将结果放在eax和edx中
    注:在 64 位代码中,movabs可用于对mov具有 64 位位移或立即数操作数的指令进行编码。
  • 函数返回值赋值给main中的变量

    64位环境中,将rax中的函数返回值存储在rbp-0x8的位置,使用的是qword,在32位环境中将eax(低位)存入ebp-8,将edx(高位)存入ebp-4

1.5 作业-char arr3={1,2,3}与char arr4={1,2,3,4}哪个更省空间,从反汇编角度说明,用char和short分别创建10个元素的数组,观察如何分配

1.5.1 char arr3={1,2,3}与char arr4={1,2,3,4}哪个更省空间,从反汇编角度说明

  1. char arr3={1,2,3}
  • 代码
c 复制代码
void Function(){
	char arr[3] = {1,2,3};
}
int main(int argc, char* argv[]){
	Function();
	return 0;
}
  • 反汇编(64位的VScode)

    以字节大小存储,分配了0x10大小的缓冲区;
  1. char arr4={1,2,3,4}
  • 代码
c 复制代码
void Function(){
	char arr[4] = {1,2,3,4};
}
int main(int argc, char* argv[]){
	 
	Function();
	 
	return 0;
}
  • 反汇编(64位的VScode)
  1. 总结
    同样以字节大小存储,分配了0x10大小的缓冲区;
    VScode在空函数时不分配缓冲区,即nop之后直接ret返回,当arr数组长度为5时,依然分配0x10大小的缓冲区(而不是海哥视频里的0x40+4n大小的缓冲区),可见现在是优化过的,并不会浪费大量内存去提升效率。

1.5.2 用char和short分别创建10个元素的数组,观察如何分配

  • 代码
c 复制代码
int main(int argc, char* argv[]){
 
	char arr0[10] = {1,2,3,4,5,6,7,8,9,10};
	short arr1[10] = {1,2,3,4,5,6,7,8,9,10};
	 
	return 0;
}
  • 反汇编

    char使用字节大小存储,short使用字大小存储(可见新版本还是优化了的,该是多大就是多大)。

1.6 作业-找出下面赋值过程的反汇编代码

1.6.1 作业部分

  • 代码:
c 复制代码
void Function(){
	int x = 1;
	int y = 2;
	int r;
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	r = arr[1];
	r = arr[x];
	r = arr[x+y];
	r = arr[x*2+y];
}
  • 反汇编


    数组寻址:值=取值(rbp/ebp + rax/eax * 数值宽度 - 数组首地址),其中rax/eax中存的是arrn中的n。

1.7 作业-选做桶排序

之前还在卷开发的时候都直接跳过的玩意,略过略过。

二、参数传递的本质

2.1 8位参数传递

  • 代码:
  • 汇编:

使用堆栈传递参数,并且使用4字节大小内存存储参数,从右往左入栈,并且外平栈,可见使用的调用约定是__cdecl。

2.2 16位参数传递

  • 代码:
  • 汇编:

2.3 32位参数传递

  • 代码:

  • 汇编:

2.4 总结:

  1. 在32位的系统中,参数传递始终按照4字节的大小入栈,所以定义char或者short类型的参数并不会节约空间,反而在char a = 1;Fun(1);传递参数时会产生额外的操作去进行al或者ax的转换。

  2. 如果本机是32位的,那么及其对于32位的数据支持度最好,反之32位时,对于32位的支持度最好。所以整数类型的参数,全部使用int传递参数。

  3. 参数传递的本质是将上层函数的变量或者表达式的值复制一份再传递给下层函数。

三、局部变量的内存分配

  1. (32位环境中)小于32位的局部变量,空间在分配时,按32位分配;

  2. 使用时按实际的宽度使用;

  3. 不要定义char/short类型的局部变量;

  4. 参数与局部变量没有本质区别,都是局部变量,都在栈中分配(参数是函数调用前分配的值,局部变量是函数执行时分配的值);

  5. 完全可以把参数当初局部变量使用。

四、赋值语句的本质

将某个值存储到变量中的过程就是赋值。

思考题:

int r = x + y;是赋值语句吗?那么 int r = Add(x,y)是赋值语句吗?

是,无本质区别(此处的区别是在于逆向人的眼中)。

五、数组的本质

1、总结:

1.1 一组相同类型的变量,为了方便读写,采用另外一种表示形式.

1.2 数组在声明的时候,必须用常量来指明长度,不能使用变量.

示例:定义10个变量,观察反汇编:

  • 分别赋值

在缓冲区将数组中的数据一一填入

  • 数组赋值


    可见在底层是一样的。

六、数组的使用

偏向开发的知识点

结尾依然是,海哥牛逼。

相关推荐
智者知已应修善业15 小时前
【51单片机使用IO组赋值方法实现无源蜂鸣器响时LED12亮不响时34亮】2024-3-7
c++·经验分享·笔记·算法·51单片机
.千余15 小时前
【C++】深挖STL list底层:解迭代器与节点存储逻辑
开发语言·c++·笔记·学习·其他
kgduu16 小时前
msi文件右键以管理员身份运行
笔记
zhangrelay16 小时前
2000-2025 年适龄升学智能大模型整理数据
大数据·笔记·学习
栈溢出了16 小时前
PyTorch 中 unfold 的理解笔记
人工智能·pytorch·笔记
智者知已应修善业16 小时前
【51单片机0.1秒计时到21.0时点亮LED】2024-1-5
c++·经验分享·笔记·算法·51单片机
AeeeSs16 小时前
web shell
笔记
虎符饼干16 小时前
从选词到布局优化,实现搜索引擎自然排名上涨
笔记
是上好佳佳佳呀16 小时前
【数据分析|DAY01】Series 和 DataFrame 笔记
笔记·数据分析
XS03010617 小时前
计算机系统层次结构笔记
笔记·硬件工程