Skip to content

Commit 810aef6

Browse files
RknMustDie512ValdikSS
authored andcommitted
Add TLS ClientHello fake packet generator
1 parent c0f43a2 commit 810aef6

File tree

4 files changed

+143
-0
lines changed

4 files changed

+143
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ Usage: goodbyedpi.exe [OPTION...]
6767
--fake-from-hex <value> Load fake packets for Fake Request Mode from HEX values (like 1234abcDEF).
6868
This option can be supplied multiple times, in this case each fake packet
6969
would be sent on every request in the command line argument order.
70+
--fake-with-sni <value> Generate fake packets for Fake Request Mode with given SNI domain name.
71+
The packets mimic Mozilla Firefox 130 TLS ClientHello packet
72+
(with random generated fake SessionID, key shares and ECH grease).
73+
Can be supplied multiple times for multiple fake packets.
7074
--fake-gen <value> Generate random-filled fake packets for Fake Request Mode, value of them
7175
(up to 30).
7276
--fake-resend <value> Send each fake packet value number of times.

src/fakepackets.c

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,91 @@ static const unsigned char fake_https_request[] = {
5757
0x00, 0x00, 0x00, 0x00, 0x00
5858
};
5959

60+
// Captured from Firefox 130.0.1
61+
static const unsigned char fake_clienthello_part0[] = { // 116 bytes
62+
// TLS 1.2 ClientHello header (DD for length placeholder)
63+
0x16, 0x03, 0x01, 0xDD, 0xDD, 0x01, 0x00, 0xDD, 0xDD, 0x03, 0x03,
64+
// Random bytes (AA for placeholder)
65+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
66+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
67+
// Random Session ID
68+
0x20,
69+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
70+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
71+
// Cipher Suites
72+
0x00, 0x22, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0xC0, 0x2B, 0xC0, 0x2F, 0xCC, 0xA9, 0xCC, 0xA8,
73+
0xC0, 0x2C, 0xC0, 0x30, 0xC0, 0x0A, 0xC0, 0x09, 0xC0, 0x13, 0xC0, 0x14, 0x00, 0x9C, 0x00, 0x9D,
74+
0x00, 0x2F, 0x00, 0x35,
75+
// Compression Methods
76+
0x01, 0x00,
77+
// Extensions Length
78+
0xDD, 0xDD,
79+
};
80+
// SNI: 00 00 L1 L1 L2 L2 00 L3 L3 (sni)
81+
// L1 = L+5, L2 = L+3, L3 = L // 9 + L bytes
82+
static const unsigned char fake_clienthello_part1[] = { // 523 bytes
83+
// extended_master_secret
84+
0x00, 0x17, 0x00, 0x00,
85+
// renegotiation_info
86+
0xFF, 0x01, 0x00, 0x01, 0x00,
87+
// supported_groups
88+
0x00, 0x0A, 0x00, 0x0E,
89+
0x00, 0x0C, 0x00, 0x1D, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01, 0x00, 0x01, 0x01,
90+
// ex_point_formats
91+
0x00, 0x0B, 0x00, 0x02, 0x01, 0x00,
92+
// session_ticket
93+
0x00, 0x23, 0x00, 0x00,
94+
// ALPN
95+
0x00, 0x10, 0x00, 0x0E,
96+
0x00, 0x0C, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2F, 0x31, 0x2E, 0x31,
97+
// status_request
98+
0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00,
99+
// delegated_credentials
100+
0x00, 0x22, 0x00, 0x0A, 0x00, 0x08, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03,
101+
// key_share
102+
0x00, 0x33, 0x00, 0x6B, 0x00, 0x69, 0x00, 0x1D, 0x00, 0x20,
103+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
104+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
105+
0x00, 0x17, 0x00, 0x41, 0x04,
106+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
107+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
108+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
109+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
110+
// supported_versions
111+
0x00, 0x2B, 0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03,
112+
// signature_algorithms
113+
0x00, 0x0D, 0x00, 0x18, 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05,
114+
0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01,
115+
// psk_key_exchange_modes
116+
0x00, 0x2D, 0x00, 0x02, 0x01, 0x01,
117+
// record_size_limit
118+
0x00, 0x1C, 0x00, 0x02, 0x40, 0x01,
119+
// encrypted_client_hello
120+
0xFE, 0x0D, 0x01, 0x19, 0x00, 0x00, 0x01, 0x00, 0x01, 0xAA, 0x00, 0x20,
121+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
122+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
123+
0x00, 0xEF,
124+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
125+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
126+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
127+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
128+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
129+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
130+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
131+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
132+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
133+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
134+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
135+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
136+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
137+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
138+
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
139+
};
140+
// JA4: t13d1715h2_5b57614c22b0_5c2c66f702b0
141+
// JA4_r: t13d1715h2_002f,0035,009c,009d,1301,1302,1303,c009,c00a,c013,c014,c02b,c02c,c02f,c030,cca8,cca9_0005,000a,000b,000d,0017,001c,0022,0023,002b,002d,0033,fe0d,ff01_0403,0503,0603,0804,0805,0806,0401,0501,0601,0203,0201
142+
// JA3 Fullstring: 771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-34-51-43-13-45-28-65037,29-23-24-25-256-257,0
143+
// JA3: b5001237acdf006056b409cc433726b0
144+
60145
static int send_fake_data(const HANDLE w_filter,
61146
const PWINDIVERT_ADDRESS addr,
62147
const char *pkt,
@@ -311,3 +396,46 @@ int fake_load_random(unsigned int count, unsigned int maxsize) {
311396
}
312397
return 0;
313398
}
399+
400+
void set_uint16be(unsigned char *buffer, int offset, int value) {
401+
buffer[offset] = (value >> 8) & 0xFF;
402+
buffer[offset + 1] = value & 0xFF;
403+
}
404+
405+
int fake_load_from_sni(const char *domain_name) {
406+
if (!domain_name) {
407+
return 1; // just extra safeguard against NPE
408+
}
409+
// calculate sizes
410+
const int name_size = strlen(domain_name);
411+
const int part0_size = sizeof(fake_clienthello_part0);
412+
const int part1_size = sizeof(fake_clienthello_part1);
413+
const int sni_head_size = 9;
414+
const int packet_size = part0_size + part1_size + sni_head_size + name_size;
415+
// allocate memory
416+
unsigned char *packet = malloc(packet_size);
417+
// copy major parts of packet
418+
memcpy(packet, fake_clienthello_part0, part0_size);
419+
memcpy(&packet[part0_size + sni_head_size + name_size], fake_clienthello_part1, part1_size);
420+
// replace placeholders with random generated values
421+
unsigned int random = 0;
422+
for (int i = 0; i < packet_size; i++) {
423+
if (packet[i] == 0xAA) {
424+
rand_s(&random);
425+
packet[i] = random & 0xFF;
426+
}
427+
}
428+
// write size fields into packet
429+
set_uint16be(packet, 0x0003, packet_size - 5);
430+
set_uint16be(packet, 0x0007, packet_size - 9);
431+
set_uint16be(packet, 0x0072, packet_size - 116);
432+
// write SNI extension
433+
set_uint16be(packet, part0_size + 0, 0x0000);
434+
set_uint16be(packet, part0_size + 2, name_size + 5);
435+
set_uint16be(packet, part0_size + 4, name_size + 3);
436+
packet[part0_size + 6] = 0x00;
437+
set_uint16be(packet, part0_size + 7, name_size);
438+
memcpy(&packet[part0_size + sni_head_size], domain_name, name_size);
439+
// add packet to fakes
440+
return fake_add(packet, packet_size);
441+
}

src/fakepackets.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ int send_fake_https_request(const HANDLE w_filter,
1919
const BYTE set_seq
2020
);
2121
int fake_load_from_hex(const char *data);
22+
int fake_load_from_sni(const char *domain_name);
2223
int fake_load_random(unsigned int count, unsigned int maxsize);

src/goodbyedpi.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ static struct option long_options[] = {
189189
{"reverse-frag",no_argument, 0, '(' },
190190
{"max-payload", optional_argument, 0, '|' },
191191
{"fake-from-hex", required_argument, 0, 'u' },
192+
{"fake-with-sni", required_argument, 0, '}' },
192193
{"fake-gen", required_argument, 0, 'j' },
193194
{"fake-resend", required_argument, 0, 't' },
194195
{"debug-exit", optional_argument, 0, 'x' },
@@ -948,6 +949,11 @@ int main(int argc, char *argv[]) {
948949
printf("WARNING: bad fake HEX value %s\n", optarg);
949950
}
950951
break;
952+
case '}': // --fake-with-sni
953+
if (fake_load_from_sni(optarg)) {
954+
printf("WARNING: bad domain name for SNI: %s\n", optarg);
955+
}
956+
break;
951957
case 'j': // --fake-gen
952958
if (fake_load_random(atoub(optarg, "Fake generator parameter error!"), 200)) {
953959
puts("WARNING: fake generator has failed!");
@@ -1013,6 +1019,10 @@ int main(int argc, char *argv[]) {
10131019
" --fake-from-hex <value> Load fake packets for Fake Request Mode from HEX values (like 1234abcDEF).\n"
10141020
" This option can be supplied multiple times, in this case each fake packet\n"
10151021
" would be sent on every request in the command line argument order.\n"
1022+
" --fake-with-sni <value> Generate fake packets for Fake Request Mode with given SNI domain name.\n"
1023+
" The packets mimic Mozilla Firefox 130 TLS ClientHello packet\n"
1024+
" (with random generated fake SessionID, key shares and ECH grease).\n"
1025+
" Can be supplied multiple times for multiple fake packets.\n"
10161026
" --fake-gen <value> Generate random-filled fake packets for Fake Request Mode, value of them\n"
10171027
" (up to 30).\n"
10181028
" --fake-resend <value> Send each fake packet value number of times.\n"

0 commit comments

Comments
 (0)