0%

TLS 混淆(四)解 Server Hello

引言

【上一篇文章】 介绍了服务端混淆插件将响应数据打包成 TLS 的过程。当数据包传递给客户端时,客户端混淆插件需要解析出响应数据。那么本篇文章将继续介绍客户端是如何解析的。

解析真实数据

  1. 开始依然是判断混淆的启用情况,以及辅助工具的内存分配
    1
    2
    3
    4
    5
    6
    7
    if (obfs == NULL || obfs->deobfs_stage < 0) return 0;

    if (obfs->extra == NULL)
    {
    obfs->extra = ss_malloc(sizeof(frame_t));
    memset(obfs->extra, 0, sizeof(frame_t));
    }
  2. 由于是第一次进行解析,所以当前的解析阶段为 0,我们直接进入解析流程
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    // 计算 server hello 结构大小
    size_t hello_len = sizeof(struct tls_server_hello);

    // 取出报文数据
    char *data = buf->data;

    // 混淆报文的总长度
    int len = buf->len;
    // 如果去掉 server hello 之后大小为 0 了,那说明数据包有问题
    len -= hello_len;
    if (len <= 0) return OBFS_NEED_MORE;

    // 定位 server hello 头指针
    struct tls_server_hello *hello = (struct tls_server_hello *) data;
    // 类型判断,不符合约定的类型,说明包有问题
    if (hello->content_type != tls_server_hello_template.content_type)
    return OBFS_ERROR;

    // 依次判断去掉密钥交换、加密的握手信息之后的大小是否符合预期
    size_t change_cipher_spec_len = sizeof(struct tls_change_cipher_spec);
    size_t encrypted_handshake_len = sizeof(struct tls_encrypted_handshake);

    len -= change_cipher_spec_len + encrypted_handshake_len;
    if (len <= 0) return OBFS_NEED_MORE;

    // 计算 tls 包的大小,包括 server hello 头、交换密钥头、加密的握手协议头,以便于定位到实际数据,注意此 tls_len 是不包括实际数据的
    size_t tls_len = hello_len + change_cipher_spec_len + encrypted_handshake_len;
    // buf->data 加上 server hello、交换密钥头大小就是加密握手信息的起始地址
    struct tls_encrypted_handshake *encrypted_handshake =
    (struct tls_encrypted_handshake *) (buf->data + hello_len + change_cipher_spec_len);
    // msg_len 就是实际数据的大小
    size_t msg_len = CT_NTOHS(encrypted_handshake->len);

    /*
    * buf->data + tls_len 就是实际数据的起始地址偏移量,至于复制多长呢?这里我们
    * 看到,直接用数据包的总长度 - 固定 tls 头的长度,而不是直接取 msg_len
    * memmove(buf->data, buf->data + tls_len, buf->len - tls_len)
    */
    // 实际的数据大小重新记录到 buf->len 中
    buf->len = buf->len - tls_len;
    // 递增解析阶段
    obfs->deobfs_stage++;

    // 与解析请求类似,这两个值会出现不一样的情况吗?
    if (buf->len > msg_len)
    {
    return deobfs_app_data(buf, msg_len, obfs);
    } else
    {
    ((frame_t *) obfs->extra)->idx = buf->len - msg_len;
    }

总结

至此,TLS 的握手已经完成,客服端发送 Client Hello,而服务端响应 Server Hello。虽然这是“握手”阶段,但是已经开始传递真实数据了。握手之后,就是混淆实际的数据传输报文了,相比握手阶段,数据的传输混淆更复杂一些,这部分内容我就放到下篇文章进行介绍吧。