Skip to content

Commit 5e05ae1

Browse files
authored
feat(android16): support BoringSSL TLS capture on Android 16 (#998)
* feat(android16): support BoringSSL TLS capture on Android 16 - Fix bash numeric comparison bug in boringssl_android_offset.sh - Add boringssl_a_16_kern.c with Android 16 struct offsets - Refactor boringssl_const.h: use SSL_HANDSHAKE_FIELD_STEP to unify TLS 1.3 secret offsets for both InplaceVector (a16) and raw array (≤a15) - Fix TLS 1.3 capture: read version from SSL3_STATE.version (0xd0) since ssl_st.version was removed in Android 16 Signed-off-by: CFC4N <cfc4n.cs@gmail.com> * feat(android16): 重写 BoringSSL offset 工具,支持 Android 16 TLS 密钥捕获 - boringssl-offset.c:用 C++17 type traits + 偏模板特化替换 sed 方案, 自动探测字段变化并输出 feature-flag 宏(含 BSSL__SSL3_STATE_VERSION) - boringssl_android_offset.sh:移除所有版本特定 sed 逻辑 - boringssl_a_16_kern.c:修正 TLS 1.3 版本读取路径,修复密钥捕获缺失问题 - 新增 utils/README.md 及 README-zh_Hans.md Signed-off-by: CFC4N <cfc4n.cs@gmail.com> --------- Signed-off-by: CFC4N <cfc4n.cs@gmail.com>
1 parent 3579a3e commit 5e05ae1

7 files changed

Lines changed: 740 additions & 118 deletions

File tree

kern/boringssl_a_16_kern.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
/* OPENSSL_VERSION_TEXT: OpenSSL 1.1.1 (compatible; BoringSSL) */
55
/* OPENSSL_VERSION_NUMBER: 269488255 */
66

7+
// ssl_st->version removed in this BoringSSL version.
8+
// SSL_SESSION_ST_SSL_VERSION also acts as the Android 16+ feature flag
9+
// for boringssl_const.h (InplaceVector offsets) and boringssl_masterkey.h.
10+
// ssl_session_st->ssl_version
11+
#define SSL_SESSION_ST_SSL_VERSION 0x4
12+
713
// ssl_st->session
814
#define SSL_ST_SESSION 0x58
915

@@ -16,8 +22,9 @@
1622
// ssl_st->s3
1723
#define SSL_ST_S3 0x30
1824

19-
// ssl_session_st->ssl_version
20-
#define SSL_SESSION_ST_SSL_VERSION 0x4
25+
// ssl_session_st->secret_length removed in this BoringSSL version.
26+
// Sentinel 0xFF: boringssl_masterkey.h uses BORINGSSL_SSL_MAX_MASTER_KEY_LENGTH.
27+
#define SSL_SESSION_ST_SECRET_LENGTH 0xFF
2128

2229
// ssl_session_st->secret
2330
#define SSL_SESSION_ST_SECRET 0xa
@@ -49,6 +56,12 @@
4956
// bssl::SSL3_STATE->established_session
5057
#define BSSL__SSL3_STATE_ESTABLISHED_SESSION 0x1d0
5158

59+
// SSL3_STATE->version added in Android 16 (replaces ssl_st->version).
60+
// BSSL__SSL3_STATE_VERSION is the Android 16+ feature flag used by
61+
// boringssl_masterkey.h to read the TLS version before the 1.2/1.3 branch.
62+
// bssl::SSL3_STATE->version
63+
#define BSSL__SSL3_STATE_VERSION 0xd0
64+
5265
// bssl::SSL_HANDSHAKE->new_session
5366
#define BSSL__SSL_HANDSHAKE_NEW_SESSION 0x5f0
5467

@@ -70,8 +83,6 @@
7083
// bssl::SSL_HANDSHAKE->max_version
7184
#define BSSL__SSL_HANDSHAKE_MAX_VERSION 0x1e
7285

73-
#define SSL_SESSION_ST_SECRET_LENGTH 0xFF
74-
7586
#include "boringssl_const.h"
7687
#include "boringssl_masterkey.h"
7788
#include "openssl.h"

kern/boringssl_const.h

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,66 @@
55
// SSL_MAX_MD_SIZE is size of the largest hash function used in TLS, SHA-384.
66
#define SSL_MAX_MD_SIZE 48
77

8+
// memory layout from boringssl repo ssl/internal.h
9+
// struct SSL_HANDSHAKE
10+
//
11+
// ── Android ≤ 15 (TLS 1.3 secrets are private raw arrays) ─────────────────
12+
// uint16_t max_version; // public, 2 bytes @ BSSL__SSL_HANDSHAKE_MAX_VERSION
13+
// // private (aligned to 8):
14+
// size_t hash_len_; // 8 bytes
15+
// uint8_t secret_[48]; // 48 bytes ← SSL_HANDSHAKE_SECRET_
16+
// uint8_t early_traffic_secret_[48]; // step = 48
17+
// ...
18+
//
19+
// ── Android 16+ (TLS 1.3 secrets are public InplaceVector<uint8_t,48>) ────
20+
// uint16_t max_version; // public, 2 bytes
21+
// InplaceVector<uint8_t,48> secret; // ← SSL_HANDSHAKE_SECRET_
22+
// InplaceVector<uint8_t,48> early_traffic_secret; // step = 49
23+
// ...
24+
//
25+
// InplaceVector<uint8_t,N> memory layout (alignof=1, no padding):
26+
// [0 .. N-1] storage_[N] — actual data bytes (same address as struct base)
27+
// [N] size_ — uint8_t (equivalent of hash_len_)
28+
//
29+
// SSL_SESSION_ST_SSL_VERSION is defined only in android16 kern headers and
30+
// serves as the version feature-flag here.
31+
// ────────────────────────────────────────────────────────────────────────────
832

9-
// memory layout from boringssl repo ssl/internal.h line 1720
10-
// struct of struct SSL_HANDSHAKE
11-
/*
12-
// via boringssl source code src/ssl/internal.h : line 1585
13-
14-
// max_version is the maximum accepted protocol version, taking account both
15-
// |SSL_OP_NO_*| and |SSL_CTX_set_max_proto_version| APIs.
16-
uint16_t max_version = 0;
17-
18-
private:
19-
size_t hash_len_ = 0;x
20-
uint8_t secret_[SSL_MAX_MD_SIZE] = {0};
21-
uint8_t early_traffic_secret_[SSL_MAX_MD_SIZE] = {0};
22-
uint8_t client_handshake_secret_[SSL_MAX_MD_SIZE] = {0};
23-
uint8_t server_handshake_secret_[SSL_MAX_MD_SIZE] = {0};
24-
uint8_t client_traffic_secret_0_[SSL_MAX_MD_SIZE] = {0};
25-
uint8_t server_traffic_secret_0_[SSL_MAX_MD_SIZE] = {0};
26-
uint8_t expected_client_finished_[SSL_MAX_MD_SIZE] = {0};
27-
*/
28-
// In BoringSSL, TLS 1.3 keys are private fields, so direct offsetof
29-
// calculation is not possible. Compute the offset by finding the address
30-
// of the field preceding the private section (max_version at offset 30),
31-
// then the first private field (size_t hash_len_) sits at offset 32 after
32-
// alignment. secret_ is at 32 + sizeof(size_t) = 40, and subsequent
33-
// fields are at SSL_MAX_MD_SIZE increments.
34-
35-
36-
// uint16_t max_version = 0;
37-
// sizeof(uint16_t) = 2
38-
#define SSL_HANDSHAKE_HASH_LEN_ roundup(BSSL__SSL_HANDSHAKE_MAX_VERSION+2,8)
39-
40-
// ssl_st->s3->hs
41-
// bssl::SSL_HANDSHAKE->secret_
42-
#define SSL_HANDSHAKE_SECRET_ SSL_HANDSHAKE_HASH_LEN_+8
43-
44-
// bssl::SSL_HANDSHAKE->early_traffic_secret_
45-
#define SSL_HANDSHAKE_EARLY_TRAFFIC_SECRET_ SSL_HANDSHAKE_SECRET_+SSL_MAX_MD_SIZE*1
46-
47-
// bssl::SSL_HANDSHAKE->client_handshake_secret_
48-
#define SSL_HANDSHAKE_CLIENT_HANDSHAKE_SECRET_ SSL_HANDSHAKE_SECRET_+SSL_MAX_MD_SIZE*2
49-
50-
// bssl::SSL_HANDSHAKE->server_handshake_secret_
51-
#define SSL_HANDSHAKE_SERVER_HANDSHAKE_SECRET_ SSL_HANDSHAKE_SECRET_+SSL_MAX_MD_SIZE*3
52-
53-
// bssl::SSL_HANDSHAKE->client_traffic_secret_0_
54-
#define SSL_HANDSHAKE_CLIENT_TRAFFIC_SECRET_0_ SSL_HANDSHAKE_SECRET_+SSL_MAX_MD_SIZE*4
55-
56-
// bssl::SSL_HANDSHAKE->server_traffic_secret_0_
57-
#define SSL_HANDSHAKE_SERVER_TRAFFIC_SECRET_0_ SSL_HANDSHAKE_SECRET_+SSL_MAX_MD_SIZE*5
58-
59-
// bssl::SSL_HANDSHAKE->expected_client_finished_
60-
#define SSL_HANDSHAKE_EXPECTED_CLIENT_FINISHED_ SSL_HANDSHAKE_SECRET_+SSL_MAX_MD_SIZE*6
33+
#ifdef SSL_SESSION_ST_SSL_VERSION
34+
// ── Android 16+: three root values differ from older versions ───────────────
35+
36+
// secret.storage_ starts right after max_version (alignof InplaceVector = 1, no gap)
37+
#define SSL_HANDSHAKE_SECRET_ (BSSL__SSL_HANDSHAKE_MAX_VERSION + 2)
38+
39+
// hash_len is now secret.size_: the uint8_t sitting right after secret.storage_[48]
40+
#define SSL_HANDSHAKE_HASH_LEN_ (SSL_HANDSHAKE_SECRET_ + SSL_MAX_MD_SIZE)
41+
42+
// Each InplaceVector<uint8_t,48> occupies 49 bytes (48 data + 1 size_)
43+
#define SSL_HANDSHAKE_FIELD_STEP (SSL_MAX_MD_SIZE + 1)
44+
45+
#else
46+
// ── Android ≤ 15: original layout ───────────────────────────────────────────
47+
48+
// hash_len_ is a size_t aligned to 8, sitting right after max_version
49+
#define SSL_HANDSHAKE_HASH_LEN_ roundup(BSSL__SSL_HANDSHAKE_MAX_VERSION + 2, 8)
50+
51+
// secret_ follows hash_len_ (size_t = 8 bytes)
52+
#define SSL_HANDSHAKE_SECRET_ (SSL_HANDSHAKE_HASH_LEN_ + 8)
53+
54+
// Each raw uint8_t[48] field occupies exactly 48 bytes, no extra size field
55+
#define SSL_HANDSHAKE_FIELD_STEP SSL_MAX_MD_SIZE
56+
57+
#endif // SSL_SESSION_ST_SSL_VERSION
58+
59+
// ── Downstream offsets: identical formula for all versions ──────────────────
60+
// All fields are laid out consecutively starting from SSL_HANDSHAKE_SECRET_,
61+
// each spaced SSL_HANDSHAKE_FIELD_STEP bytes apart.
62+
63+
#define SSL_HANDSHAKE_EARLY_TRAFFIC_SECRET_ (SSL_HANDSHAKE_SECRET_ + SSL_HANDSHAKE_FIELD_STEP * 1)
64+
#define SSL_HANDSHAKE_CLIENT_HANDSHAKE_SECRET_ (SSL_HANDSHAKE_SECRET_ + SSL_HANDSHAKE_FIELD_STEP * 2)
65+
#define SSL_HANDSHAKE_SERVER_HANDSHAKE_SECRET_ (SSL_HANDSHAKE_SECRET_ + SSL_HANDSHAKE_FIELD_STEP * 3)
66+
#define SSL_HANDSHAKE_CLIENT_TRAFFIC_SECRET_0_ (SSL_HANDSHAKE_SECRET_ + SSL_HANDSHAKE_FIELD_STEP * 4)
67+
#define SSL_HANDSHAKE_SERVER_TRAFFIC_SECRET_0_ (SSL_HANDSHAKE_SECRET_ + SSL_HANDSHAKE_FIELD_STEP * 5)
68+
#define SSL_HANDSHAKE_EXPECTED_CLIENT_FINISHED_ (SSL_HANDSHAKE_SECRET_ + SSL_HANDSHAKE_FIELD_STEP * 6)
6169

6270
/////////////////////////// END ///////////////////////////

kern/boringssl_masterkey.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,18 @@ int probe_ssl_master_key(struct pt_regs *ctx) {
204204
}
205205
s3_address = address;
206206

207+
#ifdef BSSL__SSL3_STATE_VERSION
208+
// Android 16: ssl_st.version was removed; the negotiated protocol version
209+
// now lives in SSL3_STATE.version. Read it here — before the TLS 1.2/1.3
210+
// branch decision — so that TLS 1.3 connections are correctly identified.
211+
u64 *s3_version_ptr = (u64 *)(s3_address + BSSL__SSL3_STATE_VERSION);
212+
ret = bpf_probe_read_user(&ssl_version, sizeof(ssl_version), (void *)s3_version_ptr);
213+
if (ret == 0) {
214+
mastersecret->version = ssl_version & 0xFFFF;
215+
debug_bpf_printk("s3->version: %d\n", mastersecret->version);
216+
}
217+
#endif
218+
207219
struct ssl3_state_st ssl3_stat;
208220
ret = bpf_probe_read_user(&ssl3_stat, sizeof(ssl3_stat), (void *)address);
209221
if (ret) {

0 commit comments

Comments
 (0)