OneNote防丢失。
char fun(){
//代码
return 12;
}
int main(int argc, char* argv[]){
char i = fun();
return 0;
}
函数返回值,即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函数的缓冲区),同样是仅存储一个字节的长度,编译器的不同会导致程序在空间的利用程度上存在差异
short fun(){
//代码
return 12;
}
int main(int argc, char* argv[]){
short i = fun();
return 0;
}
函数返回值赋值给main中的变量
将2字节长度的12存储在[rbp-0x2]的位置,在教程中32位的vc6++是将2字节长度存放在[ebp-4]的位置,即move word ptr [ebp-4],ax
int fun(){
//代码
return 12;
}
int main(int argc, char* argv[]){
int i = fun();
return 0;
}
}
int为4字节长度,所以函数中将返回值12存储在eax中,32位的vc6++中也存储在eax中
将4字节长度的12存储在[rbp-0x4]的位置,在教程中32位的vc6++是将4字节长度存放在[ebp-4]的位置,即move dword ptr [ebp-4],ea
__int64 fun(){
//代码
return 0x1234567890;
}
int main(int argc, char* argv[]){
__int64 i = fun();
return 0;
}
void Function(){
char arr[3] = {1,2,3};
}
int main(int argc, char* argv[]){
Function();
return 0;
}
void Function(){
char arr[4] = {1,2,3,4};
}
int main(int argc, char* argv[]){
Function();
return 0;
}
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;
}
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];
}
使用堆栈传递参数,并且使用4字节大小内存存储参数,从右往左入栈,并且外平栈,可见使用的调用约定是__cdecl。
在32位的系统中,参数传递始终按照4字节的大小入栈,所以定义char或者short类型的参数并不会节约空间,反而在char a = 1;Fun(1);传递参数时会产生额外的操作去进行al或者ax的转换。
如果本机是32位的,那么及其对于32位的数据支持度最好,反之32位时,对于32位的支持度最好。所以整数类型的参数,全部使用int传递参数。
参数传递的本质是将上层函数的变量或者表达式的值复制一份再传递给下层函数。
(32位环境中)小于32位的局部变量,空间在分配时,按32位分配;
使用时按实际的宽度使用;
不要定义char/short类型的局部变量;
参数与局部变量没有本质区别,都是局部变量,都在栈中分配(参数是函数调用前分配的值,局部变量是函数执行时分配的值);
完全可以把参数当初局部变量使用。
将某个值存储到变量中的过程就是赋值。
思考题:
int r = x + y;是赋值语句吗?那么 int r = Add(x,y)是赋值语句吗?
是,无本质区别(此处的区别是在于逆向人的眼中)。
1、总结:
1.1 一组相同类型的变量,为了方便读写,采用另外一种表示形式.
1.2 数组在声明的时候,必须用常量来指明长度,不能使用变量.
示例:定义10个变量,观察反汇编:
结尾依然是,海哥牛逼。