引言
【上一篇文章】 介绍了服务端混淆插件将响应数据打包成 TLS 的过程。当数据包传递给客户端时,客户端混淆插件需要解析出响应数据。那么本篇文章将继续介绍客户端是如何解析的。
解析真实数据
- 开始依然是判断混淆的启用情况,以及辅助工具的内存分配
1
2
3
4
5
6
7if (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));
} - 由于是第一次进行解析,所以当前的解析阶段为 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。虽然这是“握手”阶段,但是已经开始传递真实数据了。握手之后,就是混淆实际的数据传输报文了,相比握手阶段,数据的传输混淆更复杂一些,这部分内容我就放到下篇文章进行介绍吧。