吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5331|回复: 10
收起左侧

[转贴] 【转帖】C++逆向学习(三) 移动构造函数

  [复制链接]
默小白 发表于 2019-5-28 10:58

转自:https://xz.aliyun.com/t/5149

最近研究了一下C++类的移动构造函数,同时也进行了一些逆向分析,过程中碰到一个很奇怪的问题,以此记录

相关背景

右值引用

右值引用主要是为了解决C++98/03遇到的两个问题

  1. 临时对象非必要的昂贵的拷贝操作
  2. 模板函数中如何按照参数的实际类型进行转发

本文主要探讨问题1,一些代码尝试和IDA中逆向的分析

学习链接:从4行代码看右值引用,这里就不多说了

move语义

比如在vector.push_back(str)时,str(类)作为实参,会复制一份自身成为形参,进入函数调用

而这个过程中就会产生临时对象,那么也就会调用拷贝构造函数

而如果vector.push_back(std::move(str)),就可以匹配移动构造函数,省去这个拷贝过程以提高效率

链接中已经解释的很详细了,不再赘述,总之就是给将亡值续命,延长它的生命周期(原本很可能是一个临时变量)

代码分析

接下来的部分内容可以作为上一篇文章C++逆向学习(二) vector的补充,在分析移动构造函数时又学到了一些之前没有注意过的vector的细节

Str类源码

#include<iostream>
#include<string.h>
#include<vector>

using namespace std;

class Str {
public:
    char* str;
    Str(char value[]) {
        cout << "Ordinary constructor" << endl;
        int len = strlen(value);
        this->str = (char*)malloc(len + 1);
        memset(str, 0, len + 1);
        strcpy(str, value);
    }
    //拷贝构造函数
    Str(const Str& s) {
        cout << "copy constructor" << endl;
        int len = strlen(s.str);
        str = (char*)malloc(len + 1);
        memset(str, 0, len + 1);
        strcpy(str, s.str);
    }
    //移动构造函数
    Str(Str&& s) {
        cout << "move constructor" << endl;
        str = s.str;
        s.str = NULL;
    }
    ~Str() {
        cout << "destructor" << endl;
        if (str != NULL) {
            free(str);
            str = NULL;
        }
    }
};
//g++ xxx.cpp -std=c++17

代码1

main函数中,不使用move语义,会调用拷贝构造函数

int main(int argc, char** argv) {
    char value[] = "template";
    Str s(value);
    vector<Str> vs;
    vs.push_back(s);
    return 0;
}

IDA打开如下

img

简单的流程,甚至Str的高亮都是对称的

最初调用Str的拷贝构造函数,匹配的是Str(char value[]),接着初始化vector,然后一次push_back(s)

跟进push_back

img

一开始仍然是熟悉的判断vectorsize & capacity的关系,最终调用的是这里的复制构造函数

img

注意第一个参数是this,是C++成员函数调用时的第一个参数,类指针

运行结果:

img

代码2

代码2,只move(s)

int main(int argc, char** argv) {
    char value[] = "template";
    Str s(value);
    vector<Str> vs;
    //vs.push_back(s);

    //cout<<"-----------------"<<endl;
    vs.push_back(move(s));
    return 0;
}

IDA打开如下:

img

注意到其中的std::move,跟进发现其实实现只有一句话

img

也印证了move实际上不移动任何东西,唯一的功能是将一个左值强制转换为一个右值引用

继续跟进

img

仍然是判断大小和容量的代码,接着调用的是移动构造函数

img

运行结果:

img

代码3

这段代码实际上只是在单纯move之前加上了一句push_back(s),但是运行结果差了很多

作为对vector逆向学习的补充

"我全都要"写法,同时用拷贝构造和移动构造

int main(int argc, char** argv) {
    char value[] = "template";
    Str s(value);
    vector<Str> vs;
    vs.push_back(s);

    cout<<"-----------------"<<endl;
    vs.push_back(move(s));
    return 0;
}

按理来说,输出结果也只应该比代码2多一个copy constructordestructor,但实际上多了很多东西

img

IDA打开并没有出乎意料的结果,仍然是清晰的两次push_back,跟进后也没有什么特别的发现,查看交叉引用也没能找到相关信息

为什么在move之后还会有一次copy,对应的之后又多了一个desctructor

首先,vector虽然是值语义,但是move过后,既然已经调用了移动构造函数,肯定不会再无聊的拷贝一次

vs里调试,输出各个时间点的capacity

img

注意第一个destructor容量2的出现时间

跟进源码好久后才发现,多的copy的产生原因,是因为vector内部动态扩容时,在新开辟的空间上调用了复制构造函数

也就是说把原来的一个Str s复制到了新内存空间,这个过程并没有调用移动构造函数

可能这也是写了移动构造函数后,保险起见也要写一个复制构造函数的原因

其他

考虑这个问题

为什么vector内部扩容时,要在新地址调用拷贝构造函数呢?

之前文章已经分析过,vector实际上只存了类型的数据结构

直接memcpy(new_memory,old_memory,size),再把旧内存空间清零,会造成什么问题?

查了一些资料后发现,扩容是allocator的事情,一个可能的实现是原位new

而如果直接memcpy,会不会出问题取决于vector存的类型是否平凡(POD)
POD是Plain old data structure的缩写

资料提到shared_ptr也可能会被影响,取决于引用计数放在哪里

但无论如何,指针的浅拷贝、深拷贝问题值得注意,否则在vector内部扩容时,可能2个指针指向同一块内存,析构时会产生严重的错误

一个月后的SUCTF会有一道C++底层相关的pwn,欢迎来体验

免费评分

参与人数 7吾爱币 +8 热心值 +6 收起 理由
qq31477 + 1 + 1 我很赞同!
zhongjiezhe + 1 + 1 谢谢@Thanks!
JerusalemSky + 1 + 1 我很赞同!
itmaple + 1 我很赞同!
Pear + 2 + 1 用心讨论,共获提升!
陈世界 + 1 + 1 热心回复!
wjshan0808 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

NSYGHIHI 发表于 2019-5-28 11:20
写的不错学习了。不过代码地方有点小瑕疵,当*this==str,直接就返回*this就行了。没必要再进行下面操作了
青松 发表于 2019-5-28 14:40
xjt6294922 发表于 2019-5-28 22:09
Taokaka 发表于 2019-5-28 23:05
学习一下 大佬辛苦了
theStyx 发表于 2019-5-29 00:10
学习学习
学士天下 发表于 2019-5-29 08:51
受教,谢啦!!!
Dolts 发表于 2019-5-29 08:57
围观围观。
zhongjiezhe 发表于 2019-5-29 11:21
还可以更加简单
heang567 发表于 2019-6-11 21:52
谢谢大佬分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-27 05:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表