STL函数识别

  1. 什么是STL
    1. 案例介绍
  2. STL内存布局

​ C++方向逆向STL

什么是STL

STL是C++标准模板库,内置了很多常用的数据结构和算法,例如动态数组、队列等。故STL在日常编程开发中很常用,故在逆向过程中学习STL是必要的。

逆向中STL的主要问题:

  1. 缺少符号,无法判断STL容器类型
  2. STL内部数据结构相当复杂,难以提取数据
  3. O3优化使用大量STL函数被内联

O3优化是为了提高程序编译运行速度采用的优化方式,函数内联是将函数代码直接嵌入原代码中,减少了函数调用带来的损失。

这使得逆向过程中会很难分清是STL的代码还是用户自己的代码。

常见的STL容器:

  1. std::string 字符串
  2. std::vector 动态数组
  3. std::map 关联数组

案例介绍

无优化有符号:

image-20240623132004934

O3+有符号

image-20240623153746663

对比O0和O3的差距非常大


STL内存布局

在调试程序时观察数据内存布局推断容器类型,以64位gnu C++的stl为例

std::string 结构大致如下:

struct basic_string
{
    char *begin_; //actual string data
    size_t size; //actual size
    union
    {
        size_t capacity; //used if larger than 15 bytes
        char sso_buffer[16];//used if smaller than 16 bytes
    }
}

该结构体固定长度为32字节,4个dq

如果字符串长度小于16,数据就存储在当前结构,否则重新分配内存存放数据

image-20240623212040658

std::vector 内存布局

struct vector_point
{
    Point* start;//指向数据起始长度
    Point* end;//指向数据结束地址
    Point* max;//指向已分配内存的最大长度
}

固定长度24字节,3个dq

调试验证

image-20240623212120677

std::map内存布局,stl内部使用红黑树实现std::map,要获得所有键值对,这里只需要遍历二叉树即可

struct std::map
{
    void* allocator; //ignore
    color color; //ignore
    node  * root;
    node * leftmost;	//ignore
    node * rightmost;	//ignore
    size_t node_count;
}
struct node
{
    color color;
    node * parent;
    node * left;
    node * right;
    
    TypeKey key;	//data_area
    TypeValue value;
}

解析脚本

import idautils 
import idaapi 
import idc 

# parse gnu c++ stlmap 
def parse_gnu_map_header(address): 
    root = idc.read_dbg_qword(address + 0x10) 
    return root 
def parse_gnu_map_node(address): 
    left  = idc.read_dbg_qword(address + 0x10) 
    right = idc.read_dbg_qword(address + 0x18) 
    data  = address + 0x20 
    return left, right, data 
def parse_gnu_map_travel(address): 
    # address <- std::map struct address 
    result = [] 
    worklist = [parse_gnu_map_header(address)] 
    while len(worklist) > 0: 
        addr = worklist.pop() 
        (left, right, data) = parse_gnu_map_node(addr) 
        if left > 0: 
            worklist.append(left) 
        if right > 0: 
            worklist.append(right); 
        result.append(data) 
    return result 
# example 
elements = parse_gnu_map_travel(0x564D240D0EB0) 
for elem in elements: 
    print(hex(elem)) 

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com

×

喜欢就点赞,疼爱就打赏