C++逆向----基础语法(一)

C++逆向----基础语法(一)

  • C++的源文件扩展名是:cpp(c plus plus的简称)。
  • C++程序的入口是main函数。
  • C++完全兼容C语言的语法。

cin/cout语法

  • C++中常使用cin控制输入,使用cout控制输出。

cout语法

代码

cout << "Hello";  //<<运算符重载
cout << endl;  //相当于换行,此处不加双引号的
cout << "World";

运行结果

image-20210725155506508

另一种实现方法

cout << "Hello" << endl << "World";

运行结果

image-20210725155621798

cin语法

代码

int age;
cin >> age;  //把输入的值赋值给age变量
cout << "age is " << age << endl;

运行结果

image-20210725160105882

补充知识

getchar()函数是等待键盘输入(如果敲回车,就会读取键盘输入,这样就不会退出main函数,只有输入东西才能退出,这样的话我们才能去使用F5执行程序时,才可以有停留,不然会直接一闪而过。)

函数重载(Overload)

什么是函数重载?

  • 函数名一样
  • 参数的顺序,参数的类型,参数的内容,个数不同。
  • 返回值类型与函数重载无关,不能构成重载。
  • C语言不支持函数重载
  • 隐式转换存在二异性。

代码

#include <iostream>
using namespace std;

int sum(int v1,int v2) {
		return v1 + v2;
	}	
int sum(int v1,int v2,int v3) {
	return v1 + v2 + v3;
}
void func(int v1, double v2) {
	cout << "func(int v1, double v2)" << endl;
}
void func(double v1, int v2) {
	cout << "func(double v1, int v2)" << endl;
}
int main() {
	/*
	    C语言是不支持函数的重载的
		C++支持函数重载
	*/
	
	cout << sum(10,20) << endl;
	cout << sum(10, 20, 30) << endl;
	func(10, 1.5);
	func(1.5, 10);
	getchar();
	return 0;
}

运行结果

image-20210725183009410

为什么C++支持函数重载?

  • C++采用了name mangling或者叫name decoration技术
  • 重载的时候生成多个不同函数名的函数,比如deploy(int a)和deploy(double a)这两个函数是重载的,可能分别被编译器编译为deploy_int(int a)和deploy_double(double a)
  • 但是不同的编译器对C++有不同的重载方式。

从汇编的角度去理解函数的重载

  • j进入调试状态,插入断点,这样才能出现反汇编的按钮image-20210725212611003
  • F5运行,然后右键点击反汇编按钮
  • 比较函数func(int v1,double v2)和函数func(double v1,int v2)的不同,显然函数转成的内存地址是不同的,所以函数也是不同的。image-20210725214009254

补充知识

内存地址和机器码
00F428B4 6A 0A   
00F428B6 83 EC 08
  • 两者内存地址是连续的,00F428B4后跟了两个字节,所以后面的是00F428B6。
进制和字节的关系
  • 8个二进制代表2个16进制。
  • 两个16进制代表2个字节。
  • 举例:6A 0A 这个机器码占了2个字节

从IDA的角度去分析函数重载

  • 将C++运行生成的exe文件拖入IDA,这个是在Debug模式下生成的,含有很多的调试信息。image-20210802155315974
  • 将模式调成Release模式,生成exe,拖入IDA,但是release模式下做了优化image-20210802160828924
    • 在release模式下取消优化image-20210802162018936
    • 点击F5运行,重新生成exe文件,拖入IDA,发现函数名是不同的。image-20210802164103478

补充知识

  • Debug 模式:很多的调试信息
  • Release 模式:去除了很多的调试信息,生成的可执行文件比较简洁,高效。编译器会对函数进行优化。

默认参数

C++允许函数设置默认参数,在调用时可以根据情况省略实参

  • 默认参数只能按照从右到左的顺序。
  • 如果函数同时有声明、实现,默认参数只能放在函数声明中
  • 默认参数的值可以是变量、全局符号(全局变量、函数名)。

案例代码

#include <iostream>
using namespace std;

int sum(int v1, int v2) {
	return v1 + v2;
}
int main() {
	cout << sum(10, 20) << endl;
	getchar();
	return 0;
}
默认参数修改
#include <iostream>
using namespace std;

int sum(int v1=5, int v2=6) {
	return v1 + v2;
}
int main() {
	cout << sum() << endl;
	cout << sum(10) << endl;
	cout << sum(10, 20) << endl;
	getchar();
	return 0;
}
  • cout << sum() << endl; 代表使用默认参数,v1=5,v2=6
  • cout << sum(10) << endl; 代表v1=10,v2使用默认参数6
  • cout << sum(10, 20) << endl; 代表v1=10, v2=20

image-20210809132717535

参数传递规则
  • 参数只能传递从左往右。
  • 必须保证最右面的参数有默认值,或者存在传递的实参。
  • 但是默认参数必须要从最右边开始。

默认函数产生二义性

  • 函数重载、默认参数可能产生冲突,二义性(优先选择使用默认参数)image-20210809140941968

从汇编的角度去理解默认参数的原理

程序代码1:

#include <iostream>
using namespace std;

int sum(int v1, int v2) {
	return v1 + v2;
}
int main() {
	sum(1, 4);
	sum(2, 5);
	getchar();
	return 0;
}

汇编:两个函数的地址一样image-20210809142437042

程序代码2(含有默认参数):

#include <iostream>
using namespace std;

int sum(int v1, int v2=5) {
	return v1 + v2;
}
int main() {
	sum(1);
	sum(1, 5);
	getchar();
	return 0;
}

汇编:两种调用时汇编是一样的image-20210809142706656

extern “C”

  • 被extern "C"修饰的代码会被按照C语言的方式去进行编译。
  • 但是C语言是不支持函数重载的。

extern “C” 案例

程序代码

我们使用extern "C"去执行函数重载的函数

#include <iostream>
using namespace std;

extern "C" void func(){
}
extern "C" void func(int v1) {

}
int main() {

	getchar();
	return 0;
}

运行结果

如图所示函数按照C语言的方式编译,是不支持重载的。

image-20210809144918085

extern “C” 用途

  • 由于C和C++的编译规则不同,多用于C和C++混合开发。
  • 在开发时使用第三方框架\库,这些可能是用C语言写的。

C语言库

int sum(int v1, int v2)
{
	return v1 + v2;
}


int delta(int v1, int v2)
{
	return v1 - v2;
}

C++代码实现1

#include <iostream>
using namespace std;

extern "C" {    //使用extern "C"是告诉编译器使用C语言的编译方式进行编译的
	int sum(int v1, int v2);
	int delta(int v1, int v2);
}
int main() {
	cout << sum(20, 10) << endl;
	cout << delta(20, 10) << endl;
	getchar();
	return 0;
}

C++代码实现2

  • .cpp文件为C++文件
  • .c文件为第三方C语言库
  • .h为头文件,存放函数声明,这样可以使第三方库更便捷的去调用。
#include <iostream>
using namespace std;
 #include"math.h"
int main() {
	cout << sum(20, 10) << endl;
	cout << delta(20, 10) << endl;
	getchar();
	return 0;
}

头文件实现

// header file:存放函数的声明
extern "C"{
int sum(int v1, int v2);
int delta(int v1, int v2);
}

宏定义 #define _cplusplus

  • C++默认存在宏定义 #define _cplusplus
  • 通过对宏定义的判断,我们可以让c语言代码去调用带有extern “C”的头文件。

此时的头文件代码

// header file:存放函数的声明
#ifdef _cplusplus
extern "C"
#endif // _cplusplus

int sum(int v1, int v2);
int delta(int v1, int v2);

#ifdef _cplusplus
   }
#endif // _cplusplus

宏定义 #define _cplusplus

  • C++默认存在宏定义 #define _cplusplus
  • 通过对宏定义的判断,我们可以让c语言代码去调用带有extern “C”的头文件。

此时的头文件代码

// header file:存放函数的声明
#ifdef _cplusplus
extern "C"
#endif // _cplusplus

int sum(int v1, int v2);
int delta(int v1, int v2);

#ifdef _cplusplus
   }
#endif // _cplusplus

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值