在源码里这样写的
_Alloc_hider _M_dataplus;
size_type _M_string_length;
enum { _S_local_capacity = 15 / sizeof(_CharT) };
union
{
_CharT _M_local_buf[_S_local_capacity + 1];
size_type _M_allocated_capacity;
};
在内存中_M_dataplus指向字符串内存的开头,_M_string_length记录字符串长度
而下面是一个Union结构体
当字符串长度≤0xf的时候,_M_local_buf保存字符串
而字符串长度>0xf的时候,则向堆管理器申请内存,此时_M_allocated_capacity记录堆块大小
ida内可导入这个结构体
struct string {
uint8_t *data_ptr;
size_t length;
union {
char localbuf[15];
size_t capacity;
};
}
构建入口点长这样
std::string::basic_string<std::allocator<char>>(&a1, "Hello")
__int64 __fastcall std::string::basic_string<std::allocator<char>>(string *a1, char *a2)
{
__int64 v2; // rax
char *v4; // [rsp+20h] [rbp-30h]
v2 = std::string::_M_local_data(a1);
std::string::_Alloc_hider::_Alloc_hider(a1, v2);// string->data_ptr = string->localbuf
if ( !a2 )
std::__throw_logic_error("basic_string: construction from null is not valid");
v4 = &a2[std::char_traits<char>::length(a2)]; // dataend
return std::string::_M_construct<char const*>(a1, a2, v4);
}
构建时先把string→data_ptr指向localbuf,然后再调用_M_construct
unsigned __int64 __fastcall std::string::_M_construct<char const*>(string *a1, uint8_t *a2, uint8_t *a3)
{
__int64 v3; // rax
uint8_t *dataptr; // rax
string *v7; // [rsp+70h] [rbp-20h] BYREF
unsigned __int64 length; // [rsp+78h] [rbp-18h] BYREF
uint8_t *v9; // [rsp+80h] [rbp-10h]
unsigned __int64 canary; // [rsp+88h] [rbp-8h]
canary = __readfsqword(0x28u);
v9 = a2;
length = a3 - a2;
if ( (unsigned __int64)(a3 - a2) > 0xF ) // if data length < 0xf, copy to localbuf
{
v3 = std::string::_M_create(a1, &length, 0LL);// alloc memory
std::string::_M_data(a1, v3);
std::string::_M_capacity(a1, length);
}
std::string::_M_construct<char const*>(char const*,char const*,std::forward_iterator_tag)::_Guard::_Guard(&v7, a1);
dataptr = std::string::_M_data(a1);
std::string::_S_copy_chars<char const*>(dataptr, a2, a3);// if length == 1, use std::assign else use std::copy
v7 = 0LL;
std::string::_M_set_length(a1, length);
std::string::_M_construct<char const*>(char const*,char const*,std::forward_iterator_tag)::_Guard::~_Guard(&v7);
return __readfsqword(0x28u);
}
这里首先判断data长度是否大于0xf,如果大于,需要调用_M_create进一步申请内存空间,然后进一步设置dataptr以及capacity
__int64 __fastcall std::string::_M_create(string *a1, unsigned __int64 *a2, unsigned __int64 a3)
{
__int64 allocator; // rdi
unsigned __int64 v5; // [rsp+0h] [rbp-30h]
unsigned __int64 v6; // [rsp+10h] [rbp-20h]
v6 = *a2;
if ( v6 > std::string::max_size(a1) ) // length could not larger than 0x7fffffffffffffff-1
std::__throw_length_error("basic_string::_M_create");
if ( *a2 > a3 && *a2 < 2 * a3 )
{
*a2 = 2 * a3; // x 2
v5 = *a2;
if ( v5 > std::string::max_size(a1) )
*a2 = std::string::max_size(a1);
}
allocator = std::string::_M_get_allocator(a1);
return std::string::_S_allocate(allocator, *a2 + 1);// using new(arg2)
}
后面通过std::string::_S_copy_chars<char const*>
将数据复制到string中