从逆向角度看C++ STL代码之std::vector

本文详细解读了C++中std::vector的内存布局,包括成员变量_Myfirst、_Mylast和_Myend的指针解释,以及通过逆向分析一个测试代码实例,揭示vector构造函数的工作原理和如何根据内存布局进行逆向工程。
摘要由CSDN通过智能技术生成

在C++代码中std::vector是很常见的容器。上篇文章中,我们讨论了std::string的逆向技巧,这篇中我们接着讨论std::vector。

一 内存布局

找到std::vector源码中定义的成员变量,如下:

template<class _Alloc_types>
  class _Vector_alloc
  {  // base class for vector to hold allocator
public:
/* 省略函数相关代码*/
private:
  _Compressed_pair<_Alty, _Vector_val<_Val_types> > _Mypair;
  };

  template<class _Val_types>
  class _Vector_val
    : public _Container_base
  {  // base class for vector to hold data
public:
 /* 省略函数相关代码*/
  pointer _Myfirst;  // pointer to beginning of array
  pointer _Mylast;  // pointer to current end of sequence
  pointer _Myend;  // pointer to end of array
  };

可以看出,vector有三个成员变量:

_Myfirst:指向数组起始位置的指针

_Mylast:指向有效元素结束位置的指针

_Myend:指向数组结束位置的指针

这三个成员变量都是指针类型,共占用4+4+4=12个字节(32位系统下)。vector中没有记录数组大小的成员变量。数组大小是通过_Mylast- _Myfirst计算得出。

二 逆向分析

写个测试代码:

//编译环境:VS2015(v140) + X86 + Release
int main()
{
  vector<int> lst = { 1 ,2, 3 };
  for (auto it = lst.begin(); it != lst.end(); it++)
  {
    printf("%d", *it);
  }
  return 0;
}

还是编译一下,拖进IDA中F5一下。
在这里插入图片描述
上图中,变量Memory就是vector的指针。Memory[0]、Memory[1]和Memory[2]分别是_Myfirst,_Mylast和_Myend。sub_401150是vector的构造函数,函数传入vector首地址指针(Memory),元素数组的首地址(Src)和尾地址(Memoy,这里是最后一个元素的后一个地址,所以是Memory)。进入该函数,如下:
在这里插入图片描述
上图给出了代码的简要分析。这里有一个疑问,第14行代码中的0x3FFFFFFF是怎么来的?其实它是由下面第9行代码中max_size编译得来的。

bool _Buy(size_type _Capacity)
    {  // allocate array with _Capacity elements
    this->_Myfirst() = pointer();
    this->_Mylast() = pointer();
    this->_Myend() = pointer();

    if (_Capacity == 0)
      return (false);
    else if (max_size() < _Capacity)
      _Xlen();  // result too long
    else
      {  // nonempty array, allocate storage
      this->_Myfirst() = this->_Getal().allocate(_Capacity);
      this->_Mylast() = this->_Myfirst();
      this->_Myend() = this->_Myfirst() + _Capacity;
      }
    return (true);
    }

看一下max_size函数的内容:

size_t max_size() const _NOEXCEPT
    {  // estimate maximum array size
    return ((size_t)(-1) / sizeof (_Ty));
    }

显然,0x3FFFFFFF是由 0xFFFFFFFF / sizeof (_Ty)得来的。这里sizeof (_Ty)等于4,因为测试代码中的vector是int数组。

三 总结

我们知道,vector还有其他的重载构造和众多成员函数,虽然他们编译出的代码不尽相同,但是只要我们掌握了vector的内存布局,还是可以在逆向分析中轻松地识别出他们。另外,在vector的元素类型不同的情况下,编译出的代码形式看起来也不太一样,尤其是vector是结构体数组,或者嵌套了其他容器,编译后的代码会看起来比较复杂,但是基本的逻辑是一致的。总的来说,只要把握vector的内存布局,逆向分析还是比较简单的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦子zzy

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值