引言
【上一篇文章】 介绍了客户端发送请求到服务端进行 Hello Client 握手,本篇继续讲解服务端收到请求之后如何反解析具体的数据。
庐山真面目
Hello Client 握手包其实就只是一个用来欺骗防火墙的外壳,真正的数据也藏在其中。到达服务端之后,我们首先要做的就是去掉外壳,拿到真实的数据。
先判断当前是否启用混淆
1
| if (obfs == NULL || obfs->deobfs_stage < 0) return 0;
|
如果当前混淆上下文中不存在 extra,实例化它,它的作用我们往后在介绍。
1 2 3 4 5
| if (obfs->extra == NULL) { obfs->extra = ss_malloc(sizeof(frame_t)); memset(obfs->extra, 0, sizeof(frame_t)); }
|
为当前混淆上下文初始化缓存,这里分配了 32 个字节。具体的作用,我们稍后介绍。
1 2 3 4 5 6
| if (obfs->buf == NULL) { obfs->buf = (buffer_t *) ss_malloc(sizeof(buffer_t)); balloc(obfs->buf, 32); obfs->buf->len = 32; }
|
由于当前的混淆阶段为 0(Hello Client 握手包,混淆阶段肯定为 0),所以开始解析 tls_client_hello。
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
|
int len = buf->len;
len -= sizeof(struct tls_client_hello);
if (len <= 0) return OBFS_NEED_MORE;
struct tls_client_hello *hello = (struct tls_client_hello *) buf->data;
if (hello->content_type != tls_client_hello_template.content_type) return OBFS_ERROR;
size_t hello_len = CT_NTOHS(hello->len) + 5;
memcpy(obfs->buf->data, hello->session_id, 32);
|
- 获取真实数据
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
len -= sizeof(struct tls_ext_session_ticket);
if (len <= 0) return OBFS_NEED_MORE;
struct tls_ext_session_ticket *ticket = (struct tls_ext_session_ticket *) (buf->data + sizeof(struct tls_client_hello));
if (ticket->session_ticket_type != tls_ext_session_ticket_template.session_ticket_type) return OBFS_ERROR;
size_t ticket_len = CT_NTOHS(ticket->session_ticket_ext_len);
if (len < ticket_len) return OBFS_NEED_MORE;
memmove(buf->data, (char *) ticket + sizeof(struct tls_ext_session_ticket), ticket_len);
if (buf->len > hello_len) {
memmove(buf->data + ticket_len, buf->data + hello_len, buf->len - hello_len); }
buf->len = ticket_len + buf->len - hello_len;
obfs->deobfs_stage++;
if (buf->len > ticket_len) {
return deobfs_app_data(buf, ticket_len, obfs); } else {
((frame_t *) obfs->extra)->idx = buf->len - ticket_len; }
|
以上就是对 Hello Client 解混淆的介绍,其中有几个令人疑惑的点,deobfs_app_data
、Session Id
的作用?什么情况会有额外的数据?buf->len
有可能比 ticket_len
小吗?不要着急,后续的文章会对这些内容逐一解释。
此外,我们还要记住的一点是,obfs 上下文对象是针对于当前连接存在的。只要当前连接没有被销毁,obfs 就是同一个对象。