c++逆向分析——this指针

将者,智、信、仁、勇、严也。 将者,智、信、仁、勇、严也。     2023-04-05     615

关键词:

this指针

概述

C++是对C的拓展,C原有的语法C++都支持,并在此基础上拓展了一些语法:封装、继承、多态、模板等等。C++拓展新的语法是为了让使用更加方便、高效,这样就需要编译器多做了很多事情,接下来我们就需要一一学习这些概念。

封装

之前我们学习过结构体这个概念,那么结构体可以做参数传递吗?我们来看一下如下代码:

struct Student
int a;
int b;
int c;
int d;
;
 
int Plus(Student s)
return s.a + s.b + s.c + s.d;
 
void main()
Student s = 1, 2, 3, 4;
int res = Plus(s);
return;

上面这段代码是定义一个结构体,然后将该结构体传入Plus函数(将结构体成员相加返回),那么问题来了,结构体它是否跟数组一样,传递的是指针呢?来看一下反汇编代码:

可以很清晰的看见,结构体作为参数传递时栈顶(ESP)提升了0x10(16个字节,也就是结构体的四个成员【int】的宽度),而后将ESP的值给了EAX,再通过EAX(ESP)将结构体的成员传入函数,结构体成员从左到右依次从栈顶向下复制进入堆栈。

也就是说当我们将结构体作为参数传递时与我们传整数什么的是没有本质区别的,唯一的区别就是传递结构体时不是使用的push来传递的,而是一次性的提升堆栈,然后mov赋值。

虽然我们可以使用结构体进行传参,但是这也存在一个问题,就是当我们使用结构体传参时,假设结构体有40个成员,那么就存在着大量的内存被复制,这样效率很低,是不推荐使用的

那如果非要这样使用该怎么办呢?我们可以使用指针传递的方式来,修改一下代码:

struct Student
int a;
int b;
int c;
int d;
;
 
int Plus(Student* p)
return p->a + p->b + p->c + p->d;
 
void main()
Student s = 1, 2, 3, 4;
int res = Plus(&s);
return;

这样我们就可以使用指针的方式来避免内存的重复使用,效率更高。

可能很多人看到这就很疑惑了,那这跟C++有什么关系呢?我们之前说过C++和C的本质区别,就是编译器替代我们做了很多事情;别着急,慢慢来看。

我们使用指针优化过的代码,实际上还是存在小缺陷的,当结构体成员很多的时候,我们在Plus函数体内就要用指针的调用方式,一堆成员相加...

那么是否可以让我们调用更加简单,更加方便呢?如下代码就可以:

struct Student
int a;
int b;
int c;
int d;
 
int Plus()
return a + b + c + d;
;
 
void main()
Student s = 1, 2, 3, 4;
int res = s.Plus();
return;

将函数放在结构体内,就不需要我们再去写传参、再去使用指针的调用方式了,因为这些工作编译器帮我们完成了,而本质上这与指针调用没有区别:

而这种写法就是C++的概念:封装;也就是说将函数写在结构体内的形式就称之为封装,其带来的好处就是我们可以更加方便的使用结构体的成员。

讲到了封装,我们就要知道另外两个概念:

  1. :带有函数的结构体,称为类;

  2. 成员函数:结构体里的函数,称为成员函数

    1. 函数本身不占用结构体的空间(函数不属于结构体

    2. 调用成员函数的方法与调用结构体成员的语法是一样的 → 结构体名称.函数名()

this指针

之前我们学过了封装,如下代码:

struct Student
int a;
int b;
int c;
int d;
 
int Plus()
return a + b + c + d;
;
 
void main()
Student s = 1, 2, 3, 4;
int res = s.Plus();
return;

其对应的反汇编代码如下:

可以看见我们使用s.Plus()的时候,传递的参数是一个指针,这个指针就是当前结构体的地址,这个指针就是this指针。(通常情况下编译器会使用ecx来传递当前结构体的指针)

那么当我们将Plus函数修改成无返回值,不调用结构体成员后,这个指针还会传递过来么?

struct Student
int a;
int b;
int c;
int d;
 
void Plus()
 
;
 
void main()
Student s = 1, 2, 3, 4;
s.Plus();
return;

我们看下反汇编代码,发现指针依然会传递过来:

那也就是说this指针是编译器默认传入的,通常会通过ecx进行参数的传递,不管你用还是不用,它都存在着

既然this指针会作为参数传递,我们是否也可以直接使用这个指针呢?答案是可以的:

struct Student
int a;
int b;
 
void Init(int a, int b)
this->a = a;
this->b = b;
 
;

我们在结构体的成员函数内使用this这个关键词就可以调用了,如上代码所示。

那么this指针有什么作用呢?我们可以看下如下代码:

struct Student
int a;
int b;
 
void Init(int a, int b)
a = a;
b = b;
 
;
 
void main()
Student s;
s.Init(1,2);
return;

这段代码我们要实现的就是,使用成员函数初始化成员的值,但是实际运行却不符合我们的预期:

跟进反汇编代码发现,这里就是将传入的参数赋值给了参数本身,并没有改变成员的值,这是因为编译器根本不知道你这里的a到底是谁,所以我们就需要借助this指针来实现:

#include <stdio.h>
 
struct Student
int a;
int b;
 
void Init(int a, int b)
this->a = a;
this->b = b;
 
void Print()
printf("%d %d", this->a, this->b);
 
;
 
void main()
Student s;
s.Init(1,2);
s.Print();
return;

为了方便,添加一个成员函数,用于打印输出成员的值:

可以看见,这里成功进行初始化了。

总结:

  1. this指针是编译器默认传入的,通常会使用ecx进行参数的传递

  2. 成员函数都有this指针,无论是否使用

  3. this指针不能做++ --等运算,也不可以被重新赋值

  4. this指针不占用结构体的宽度

 

this指针和函数都不占用struct的空间,我们验证下:

#include <cstdio>

struct A 
    char* hello() 
        return "hi";
    
;

int main() 
    A a;
    printf("empty struct size=%d\\n", sizeof(a));

 

输出为1。

所以可以知道,没有任何成员变量的struct大小为1.

c++反汇编与逆向分析技术揭秘的目录

参考技术A前言第一部分 准备工作第1章 熟悉工作环境和相关工具/21.1 调试工具MicrosoftVisualC++6.0和OllyDBG/21.2 反汇编静态分析工具IDA/51.3 反汇编引擎的工作原理/111.4 本章小结/16第二部分 C++反汇编揭秘第2章 基本数... 查看详情

c++逆向总结(代码片段)

本篇文章适用于有一定C语言基础,但是对C++零基础的同学看,讲解了C++里的一些概念C在定义一个结构体的时候,就是定义一个新的数据类型而C++在定义一个结构体,会有一个this指针,指向... 查看详情

c++逆向总结(代码片段)

本篇文章适用于有一定C语言基础,但是对C++零基础的同学看,讲解了C++里的一些概念C在定义一个结构体的时候,就是定义一个新的数据类型而C++在定义一个结构体,会有一个this指针,指向... 查看详情

逆向分析技术(代码片段)

1.启动函数功能:检索新进程命令指针,环境指针,全局变量初始化,内存堆栈初始化比如:GetCommandLineA命令指针GetStartupInfoA启动信息GetModuleHandleA执行文件基地址编译器自动加入的代码:00401020>/$55pushebp00401021|.8BECmovebp,esp0040102... 查看详情

c++反汇编与逆向分析-读书笔记(代码片段)

目录C++逆向需求某C++逆向课程的目录知识点1:intmain(intargc,char*argv[])的参数知识点2:构造函数和析构函数知识点3:局部变量和参数的位置:知识点4:加减乘除,异或等操作对应的汇编源码:知... 查看详情

c++反汇编与逆向分析-读书笔记(代码片段)

目录C++逆向需求某C++逆向课程的目录知识点1:intmain(intargc,char*argv[])的参数知识点2:构造函数和析构函数知识点3:局部变量和参数的位置:知识点4:加减乘除,异或等操作对应的汇编源码:知... 查看详情

c++类设计总结回顾------this指针

当类中的成员函数涉及到两个对象时,就需要用到this指针;  每个成员函数(包括构造和析构函数)都有一个this指针。this指针指向调用对象,如果需要引用整个调用对象,则可以使用表达式*this(解引用);  在函数括号... 查看详情

c++和c#中'this'指针的概念和数据类型

】c++和c#中\\\'this\\\'指针的概念和数据类型【英文标题】:conceptanddatatypeof\'this\'pointerinc++andc#c++和c#中\'this\'指针的概念和数据类型【发布时间】:2014-12-1813:13:22【问题描述】:我对这个指针的概念有点不清楚。我知道c++中的this... 查看详情

c++之类和对象——类的定义,存储方式,this指针!(五千字长文详解!)(代码片段)

...式,this指针!面向过程和面向对象初步认识面向过程:分析出求解问题的步骤,通过函数调用逐步解决问题面向对象:关注的是对象!讲一件事分成不同的对象,靠对象的交互之间的完成的!(至于怎么实现就不用管)类的引... 查看详情

关于c++中的this指针

记忆中,初识c++中的this指针的时候,根本不知道它是什么,有什么作用。再识,就知道了它的作用,也掌握了它背后的东西。this指针,就是一个指向当前对象的指针。我们知道,定义出一个类,它在内存中是不占空间的... 查看详情

c++逆向vector

最近弄Androidc/c++方面的逆向,发现c++的类,stl模板,在逆向的时候相比c语言都带来了不小的困难。今天自己写了个小程序,然后逆向分析了一下vector<int>array_int;array_int.push_back(1);array_int.push_back(2);array_int.push_back(5); 定义... 查看详情

c++程序正向编译逆向反编译(代码片段)

1.需求    逆向工程师必须先是一个正向开发工程师,如果没有C++/MFC的开发经验,就不会懂得如何逆向分析C++/MFC的程序,本文完成一个helloworld的C++正逆向过程。2.C++程序源码  编译环境࿱... 查看详情

C++ this 指针始终为 const

】C++this指针始终为const【英文标题】:C++thethispointerisalwaysconst【发布时间】:2013-04-1910:05:48【问题描述】:对于类X的非const成员函数,此指针的类型为X*const。那么,成员函数的这个指针总是常量。那么,我们是否总是需要像这... 查看详情

c++中this指针的用法及介绍

this指针只能在一个类的成员函数中调用,它表示当前对象的地址。下面是一个例子:voidDate::setMonth(intmn)month=mn;//这三句是等价的this->month=mn;(*this).month=mn;this只能在成员函数中使用。全局函数,静态函数都... 查看详情

c++类体系中this指针不能改变指向吗?

this指针可以作强制类型转换,那么this指针可以改变指向否?多谢解答!有点意思,举个例子:inti;如上,随便定义一个变量,现在,你能改变变量i的地址么?原则上,从高级语言的角度来说,改变i的地址是不可能的,因为i的... 查看详情

如何将“this”指针传递给 C++ WinAPI 线程?

】如何将“this”指针传递给C++WinAPI线程?【英文标题】:Howtopassinthe\'this\'pointertoaC++WinAPIthread?【发布时间】:2020-06-0916:15:39【问题描述】:我正在尝试运行C++线程,但也将实例传递给类本身。我似乎无法弄清楚。我有一个线程... 查看详情

详谈c++中的this指针,一个合格的c++程序员必须具备的知识(代码片段)

引出this指针没有见过this指针的同学们看到这个地方,会忽然疑惑,this指针是什么个鬼东西,下面让我们来看一段类的定义与实例化的代码。classDatepublic: voidDisplay() cout<<_year<<"/"<<_month<<"/&#... 查看详情

this指针

...。那么成员函数 是如何被翻译的呢?答案是引入this指针。    this指针:       实际上非静态 查看详情