DA14531芯片固件逆向系列(4)- L2CAP及ATT层收包再分析
字数 1000 2025-08-24 07:48:09

DA14531芯片固件逆向系列(4)- L2CAP及ATT层收包分析教学文档

1. 前言

本文档详细分析DA14531芯片固件中L2CAP层和ATT层的收包处理流程,重点解析ATT层报文解析过程,并介绍分析过程中发现的漏洞。通过本教程,读者将深入了解蓝牙协议栈中关键层的实现细节和安全问题。

2. L2CAP层收包处理回顾

2.1 主要处理函数

  • hci_acl_data_rx_handler: 处理L2CAP报文的主入口函数
  • 主要处理流程:
    1. 调用l2cc_pdu_unpack检查L2CAP头部字段
    2. 检查Length和Channel ID合法性
    3. 将L2CAP报文拷贝到新分配的内存
    4. 根据数据包类型分发处理

2.2 数据结构

struct l2cc_pdu_recv_ind {
    uint8_t status;      // 表示数据的大小
    uint16_t rem_len;    // 剩余长度
    uint16_t offset;     // 偏移量
    struct l2cc_pdu pdu; // 指向具体的数据
};

struct l2cc_pdu {
    uint16_t payld_len;  // L2Cap Payload长度
    uint16_t chan_id;    // L2Cap Channel ID
    union l2cc_pdu_data {
        uint8_t code;    // L2Cap packet code
        // 各种L2CAP PDU结构体
        struct l2cc_lecb_send_data_req send_lecb_data_req;
        struct l2cc_reject reject;
        struct l2cc_update_param_req update_req;
        // ...其他PDU类型
    } data;
};

3. ATT层报文解析

3.1 ATT PDU基本格式

ATT PDU由以下部分组成:

  • 1字节的opcode
  • 变长的数据部分

3.2 主要处理函数

int sub_7F135F6(int id, l2cc_pdu_recv_ind *l2cc_pdu_recv, unsigned int dest_task) {
    ret = atts_l2cc_pdu_recv_handler(dest_task >> 8, l2cc_pdu_recv);
    if (ret == 255) {
        ret = attc_l2cc_pdu_recv_handler(dest_task >> 8, l2cc_pdu_recv);
    }
    // ...
}

处理流程:

  1. 首先尝试调用atts_l2cc_pdu_recv_handler解析
  2. 如果返回255,则调用attc_l2cc_pdu_recv_handler解析

3.3 ATT处理函数结构

struct att_handler_item {
    unsigned __int8 code;  // ATT PDU的opcode
    unsigned __int8 d[3];  // 填充
    dummy_func func;       // 处理函数指针
};

处理函数查找逻辑:

for (i = 0; i < 0xE; i++) {
    if (atts_handlers_0_0[i].code == code) {
        func = atts_handlers_0_0[i].func;
    }
}
if (func) {
    result = (func)(dest_id, &l2cc_pdu_recv->pdu.data);
}

3.4 典型ATT PDU处理示例:Exchange MTU Response

PDU结构定义

struct l2cc_att_mtu_rsp {
    uint8_t code;     // Exchange MTU Response - 0x03
    uint16_t mtu_size; // Server Rx MTU size
};

处理函数实现

int sub_7F0FC0C(int dest_id, l2cc_att_mtu_rsp *payload) {
    mtu_size = gattm_get_max_mtu();
    if (mtu_size >= payload->mtu_size) {
        mtu_size = payload->mtu_size;
    }
    gattc_set_mtu(dest_id, mtu_size);
    // ...其他处理
    return 0;
}

4. 漏洞分析

4.1 l2cc_att_rd_by_type_rsp整数溢出导致堆溢出

漏洞代码

int __fastcall sub_7F0FDB4(int id, l2cc_att_rd_by_type_rsp *payload) {
    // ...
    if (gattc_get_mtu(id) - 2 > payload->each_len) {
        msg = ke_msg_alloc(dword_7F102F0 + 4, v23, src_id, payload->each_len + 4);
        sub_len = (payload->each_len - 2);
        qmemcpy((msg + 6), &payload->data[2], sub_len); // 整数溢出
    }
    // ...
}

漏洞原理

  • each_len为1时,sub_len = each_len - 2会下溢变为0xFFFF
  • 导致qmemcpy拷贝大量数据,造成堆溢出

4.2 ATT PDU处理函数多处越界读

示例1:sub_7F1015C

int __fastcall sub_7F1015C(int a1, l2cc_att_rd_rsp *payload) {
    // ...
    qmemcpy(&v7[5].next + 3, payload->value, 0x10u); // 直接拷贝0x10字节
    // 没有检查payload实际长度,可能导致越界读
}

示例2:sub_7F11E24

void sub_7F11E24(int id, l2cc_att_rd_mult_req *payload) {
    p_payload_length = (int)(payload - 1); // 获取&l2cc_pdu->payld_len
    // 只检查p_payload_length是否为0
    while (payload->nb_handles > v4 && *p_payload_length) {
        data = (int)payload + 2 * v4;
        // 可能访问越界
    }
}

4.3 GATT写请求处理流程分析

关键函数调用链

sub_7F11F42 (处理0x52类型ATT PDU)
  -> caller_gattc_write_req_ind
    -> 发送GATTC_WRITE_REQ_IND(0xC15)消息
      -> gattc_write_req_ind_handler (处理函数)

Write Command PDU结构

struct l2cc_att_wr_cmd {
    uint8_t code;      // Write Command - 0x52
    uint16_t handle;   // 要写入的属性句柄
    uint16_t value_len; // 值长度
    uint8_t value[];   // 要写入的值
};

5. 安全分析建议

  1. 长度校验:所有处理变长数据的函数都应严格校验输入长度
  2. 边界检查:数组/缓冲区访问前必须检查索引/偏移量是否有效
  3. 整数运算:特别注意减法、乘法等可能导致溢出的运算
  4. 消息处理:审计所有自定义的消息处理函数实现
  5. 协议合规:确保实现完全遵循BLE协议规范

6. 参考资源

  1. BLE空口包格式详解
  2. BLE Link layer协议解析
  3. Bluetooth Core Specification官方文档
DA14531芯片固件逆向系列(4)- L2CAP及ATT层收包分析教学文档 1. 前言 本文档详细分析DA14531芯片固件中L2CAP层和ATT层的收包处理流程,重点解析ATT层报文解析过程,并介绍分析过程中发现的漏洞。通过本教程,读者将深入了解蓝牙协议栈中关键层的实现细节和安全问题。 2. L2CAP层收包处理回顾 2.1 主要处理函数 hci_acl_data_rx_handler : 处理L2CAP报文的主入口函数 主要处理流程: 调用 l2cc_pdu_unpack 检查L2CAP头部字段 检查Length和Channel ID合法性 将L2CAP报文拷贝到新分配的内存 根据数据包类型分发处理 2.2 数据结构 3. ATT层报文解析 3.1 ATT PDU基本格式 ATT PDU由以下部分组成: 1字节的opcode 变长的数据部分 3.2 主要处理函数 处理流程: 首先尝试调用 atts_l2cc_pdu_recv_handler 解析 如果返回255,则调用 attc_l2cc_pdu_recv_handler 解析 3.3 ATT处理函数结构 处理函数查找逻辑: 3.4 典型ATT PDU处理示例:Exchange MTU Response PDU结构定义 处理函数实现 4. 漏洞分析 4.1 l2cc_ att_ rd_ by_ type_ rsp整数溢出导致堆溢出 漏洞代码 漏洞原理 当 each_len 为1时, sub_len = each_len - 2 会下溢变为0xFFFF 导致 qmemcpy 拷贝大量数据,造成堆溢出 4.2 ATT PDU处理函数多处越界读 示例1:sub_ 7F1015C 示例2:sub_ 7F11E24 4.3 GATT写请求处理流程分析 关键函数调用链 Write Command PDU结构 5. 安全分析建议 长度校验 :所有处理变长数据的函数都应严格校验输入长度 边界检查 :数组/缓冲区访问前必须检查索引/偏移量是否有效 整数运算 :特别注意减法、乘法等可能导致溢出的运算 消息处理 :审计所有自定义的消息处理函数实现 协议合规 :确保实现完全遵循BLE协议规范 6. 参考资源 BLE空口包格式详解 BLE Link layer协议解析 Bluetooth Core Specification官方文档