首页 > 编程语言 >C++逆向分析——引用

C++逆向分析——引用

时间:2023-08-02 18:34:01浏览次数:29  
标签:逆向 00 int C++ 引用 printf 类型 ref

void main() {
    int x = 1;
    int& ref = x;
    ref = 2;
    printf("%d \n", ref);
    return;
}

反汇编代码:

int x = 1;
00724A5F C7 45 F4 01 00 00 00 mov         dword ptr [x],1  
    int& ref = x;
00724A66 8D 45 F4             lea         eax,[x]  
00724A69 89 45 E8             mov         dword ptr [ref],eax  
    ref = 2;
00724A6C 8B 45 E8             mov         eax,dword ptr [ref]  
00724A6F C7 00 02 00 00 00    mov         dword ptr [eax],2  
    printf("%d \n", ref);
00724A75 8B 45 E8             mov         eax,dword ptr [ref]  
00724A78 8B 08                mov         ecx,dword ptr [eax]  
00724A7A 51                   push        ecx  
00724A7B 68 30 7B 72 00       push        offset string "%d \n" (0727B30h)  
00724A80 E8 4D C6 FF FF       call        _printf (07210D2h)  
00724A85 83 C4 08             add         esp,8

 修改为指针,看看反汇编结果:

void main() {
    int x = 1;
    int* ref = &x;
    *ref = 2;
    printf("%d \n", *ref);
    return;
}

 

是不是发现下面的反汇编结果和上面引用的一模一样!

int x = 1;
00B44A5F C7 45 F4 01 00 00 00 mov         dword ptr [x],1  
    int* ref = &x;
00B44A66 8D 45 F4             lea         eax,[x]  
00B44A69 89 45 E8             mov         dword ptr [ref],eax  
    *ref = 2;
00B44A6C 8B 45 E8             mov         eax,dword ptr [ref]  
00B44A6F C7 00 02 00 00 00    mov         dword ptr [eax],2  
    printf("%d \n", *ref);
00B44A75 8B 45 E8             mov         eax,dword ptr [ref]  
00B44A78 8B 08                mov         ecx,dword ptr [eax]  
00B44A7A 51                   push        ecx  
00B44A7B 68 30 7B B4 00       push        offset string "%d \n" (0B47B30h)  
00B44A80 E8 4D C6 FF FF       call        _printf (0B410D2h)  
00B44A85 83 C4 08             add         esp,8

 

引用类型

引用类型就是变量的别名,其在初始化时必须要赋值。

// 基本类型

int x = 1;


int& ref = x;


ref = 2;


printf("%d \n",ref);

 
// 类
Person p;
Person& ref = p;

ref.x = 10;


printf("%d \n",p.x);

 
// 指针类型

int****** x = (int******)1;


int******& ref = x;


ref = (int******)2;


printf("%d \n",x);

 
// 数组类型

int arr[] = {1,2,3};


int (&p)[3] = arr;


p[0] = 4;


printf("%d \n",arr[0]);

如上是引用类型作用在各个类型下的例子,那么引用类型是如何实现的呢?其本质是什么?我们可以看下反汇编代码:

C++逆向分析——引用_赋值

会发现这段反汇编和指针的反汇编一模一样的:

C++逆向分析——引用_反汇编_02

这时候我们暂时的出结论:引用类型就是指针。

 

在我vs2022里实验下:

 

 

但如果引用类型就是指针,为什么C++需要新创建一个引用类型的概念呢?它们之间必然存在着一些区别,我们可以从初始化、运算、赋值来看反汇编代码的区别:

C++逆向分析——引用_引用类型_03

我们可以很清晰的看见区别从运算到赋值都不一样,指针运算到赋值改变的是指针本身,而不是指针指向的那个地址,而引用则不一样其从运算到赋值改变的是所引用的变量,我们得出这几个结论:

  1. 引用必须赋初始值,且只能指向一个变量,从一而终(专一);
  2. 对引用赋值,是对其指向的变量赋值,而不是修改引用本身的值;
  3. 对引用做运算,就是对其指向的变量做运算,而不是对引用本身做运算;
  4. 引用类型就是一个弱化了的指针;个人理解:引用类型就是一个*p

C++逆向分析——引用_反汇编_04

C++设计引用类型是因为指针类型很难驾驭,一旦用不好就回出问题,所以取长补短设计了引用类型。

那么引用类型在实际开发中的作用是什么呢?我们可以用在函数参数传递中:

#include <stdio.h>
 

void Plus(int& i) {

 i++;

return;

}
 

void main() {


int i = 10;

 Plus(i);

 printf("%d \n", i);


return;

}

如上代码中Plus函数的参数是一个引用类型,当我们把变量i传递进去,i就会自增1,而实际上也就修改变量i本身的值;换一种说法就是,我们之前函数参数传递的是值,而这里传递的是变量的地址。

C++逆向分析——引用_反汇编_05

那么在构造类型中又是怎么样的呢?

#include <stdio.h>

class Base {
public:
	int x;
	int y;
	Base(int a, int b) {
		this->x = a;
		this->y = b;
	}
};

void PrintByRef(Base& refb, Base* pb) {

	printf("%d %d \n", pb->x, pb->y);

	printf("%d %d \n", refb.x, refb.y);

}

void main() {
	Base b(1, 2);

	PrintByRef(b, &b);
	return;
}

 

 

C++逆向分析——引用_赋值_06

 

我们可以看见除了读取的表现形式不一样,实际上汇编代码是一模一样的;但是指针类型是可以重新赋值并运算的,而引用类型不可以。

当一个变量是int类型的,而我们引用类型却是一个其他类型的,会怎么样呢?

int x = 10;

Person& ref = (Person&)x;

这是可以编译的,但是没有实际意义,所以在使用引用的时候原来是什么类型就应该使用什么类型。

大家都知道,我们使用指针的时候是可以修改指针本身的,这会存在一定的风险,而C++中提供了引用类型,不可以修改引用本身,我们可以修改被引用的值,当我们不想其他人修改引用类型对应引用的值,可以使用const这个关键词,这种方式我们称之为常引用:

C++逆向分析——引用_反汇编_07

标签:逆向,00,int,C++,引用,printf,类型,ref
From: https://blog.51cto.com/u_11908275/6941572

相关文章

  • C++逆向分析——类成员的访问控制
    类成员的访问控制课外→好的编程习惯:定义与实现分开写,提升代码可读性。如下代码,Student这个类的所有成员我们都可以调用,但是我们不想让被人调用Print1这个方法该怎么?structStudent{intage;intsex;voidPrint1(){printf("FuncPrint1");}voidPrint(){......
  • C++逆向分析——new和delete new[]和delete[]
    在堆中创建对象我们可以在什么地方创建对象?全局变量区,在函数外面在栈中创建对象,也就是函数内在堆中创建对象注意:之前一直提到的堆栈实际上是两个概念->堆、栈,我们之前所讲的就是栈,从本章开始要严格区分。在C语言中,我们可以通过一个函数去申请一块内存,就是malloc(N);申请的这一块内存......
  • C++逆向分析——继承
    继承structPerson{intage;intsex;};structTeacher{intage;intsex;intlevel;intclassId;};如上代码中可以看见,Teacher类与Person类都存在着相同的2个成员age和sex,那么这就相当于重复编写了,我们可以通过继承的方式避免这样重复的编写(当前类名称:要......
  • C++逆向分析——this指针
    this指针概述C++是对C的拓展,C原有的语法C++都支持,并在此基础上拓展了一些语法:封装、继承、多态、模板等等。C++拓展新的语法是为了让使用更加方便、高效,这样就需要编译器多做了很多事情,接下来我们就需要一一学习这些概念。封装之前我们学习过结构体这个概念,那么结构体可以做参数传......
  • C语言逆向——预处理之宏定义、条件编译与文件包含
    预处理之宏定义、条件编译与文件包含预处理一般是指在程序源代码被转换为二进制代码之前,由预处理器对程序源代码文本进行处理,处理后的结果再由编译器进一步编译。预处理功能主要包括宏定义、文件包含、条件编译三部分。宏定义简单的宏:#define标识符字符序列#defineFALSE0#d......
  • C语言逆向分析——Switch语句,为何大多数情况较if语句更高效?就是因为查找表
    Switch语句Switch语句也是分支语句的一种,其语法如下:switch(表达式){case常量表达式1:语句;break;case常量表达式:语句;break;case常量表达式:语句;break;......default:语句;break;}需要注意如下几点:表达式结束不能是浮点数case后的常量......
  • C语言逆向——数组和结构体,数组多维只是一个编译构造的假象,本质会转成一维数组,结构体
    数组数组是C语言中非常重要的一个概念,学习C语言主要就是两个知识点:数组、指针,学好这两个,那么你的C语言一定也会很好。什么是数组?或者说什么情况下我们需要使用数组,比如说我们需要定义一个人的年龄,我们可以定义一个变量来表示,但是如果我们需要定义三个人的年龄呢?那就需要三个变量来......
  • 逆向——字符与字符串,中文字符GB2312编码由来
    字符与字符串在之前的课程中我们了解到变量的定义决定两个事情,第一是决定存储的数据宽度,第二是决定了存储的数据格式,那么我们来看下下面的代码:inta=123;//变量x,数据宽度为4个字节,里面存储的是补码(在计算机系统中,数值一律用补码来存储)intfloatb=123.4F;//IEEE编码(浮点)......
  • 【C++数据结构】启航,打开新世界的大门!
    @TOC一、学习数据结构的原因学习数据结构对于计算机科学和软件开发非常重要,它提供了处理和组织数据的有效方法和技术。以下是几个学习数据结构的重要原因:提高问题解决能力:数据结构教会了我们如何选择和使用适当的数据结构来解决问题。了解各种数据结构的特性和性能可以帮助我们分......
  • v_jstools js逆向分析工具
    1.工具地址:https://github.com/cilame/v_jstools2.下载文件文件下载下来以后,复制到桌面,然后解压到当前文件夹,会看到一个  v_jstools-main 的文件夹。3.插件安装谷歌浏览器地址栏输入如下url,打开扩展程序页面,并打开开发者模式:chrome://extensions/打开后,点击......