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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
|
#include <stddef.h>
#include "frida-gumjs.h"
#include "config.h"
#include "debug.h"
#include "instrument.h"
#if defined(__x86_64__)
static GumAddress current_log_impl = GUM_ADDRESS(0);
#pragma pack(push, 1)
typedef struct {
/*
* pushfq
* push rdx
* mov rdx, [&previouspc] (rip relative addr)
* xor rdx, rdi (current_pc)
* shr rdi. 1
* mov [&previouspc], rdi
* lea rsi, [&_afl_area_ptr] (rip relative)
* add rdx, rsi
* add byte ptr [rdx], 1
* adc byte ptr [rdx], 0
* pop rdx
* popfq
*/
uint8_t push_fq;
uint8_t push_rdx;
uint8_t mov_rdx_rip_off[7];
uint8_t xor_rdx_rdi[3];
uint8_t shr_rdi[3];
uint8_t mov_rip_off_rdi[7];
uint8_t lea_rdi_rip_off[7];
uint8_t add_rdx_rdi[3];
uint8_t add_byte_ptr_rdx[3];
uint8_t adc_byte_ptr_rdx[3];
uint8_t pop_rdx;
uint8_t pop_fq;
uint8_t ret;
} afl_log_code_asm_t;
#pragma pack(pop)
#pragma pack(push, 8)
typedef struct {
afl_log_code_asm_t assembly;
uint64_t current_pc;
} afl_log_code_t;
#pragma pack(pop)
typedef union {
afl_log_code_t data;
uint8_t bytes[0];
} afl_log_code;
static const afl_log_code_asm_t template = {
.push_fq = 0x9c,
.push_rdx = 0x52,
.mov_rdx_rip_off =
{
0x48, 0x8b, 0x15,
/* TBC */
},
.xor_rdx_rdi =
{
0x48,
0x31,
0xfa,
},
.shr_rdi = {0x48, 0xd1, 0xef},
.mov_rip_off_rdi = {0x48, 0x89, 0x3d},
.lea_rdi_rip_off =
{
0x48,
0x8d,
0x3d,
},
.add_rdx_rdi = {0x48, 0x01, 0xfA},
.add_byte_ptr_rdx =
{
0x80,
0x02,
0x01,
},
.adc_byte_ptr_rdx =
{
0x80,
0x12,
0x00,
},
.pop_rdx = 0x5a,
.pop_fq = 0x9d,
.ret = 0xc3};
static guint8 align_pad[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
gboolean instrument_is_coverage_optimize_supported(void) {
return true;
}
static gboolean instrument_coverage_in_range(gssize offset) {
return (offset >= G_MININT32 && offset <= G_MAXINT32);
}
static void instrument_coverate_write_function(GumStalkerOutput *output) {
guint64 misalign = 0;
GumX86Writer *cw = output->writer.x86;
GumAddress code_addr = 0;
afl_log_code code = {0};
/*guint64 instrument_hash_zero = 0;*/
if (current_log_impl == 0 ||
!gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) ||
!gum_x86_writer_can_branch_directly_between(cw->pc + 128,
current_log_impl)) {
gconstpointer after_log_impl = cw->code + 1;
gum_x86_writer_put_jmp_near_label(cw, after_log_impl);
misalign = (cw->pc & 0x7);
if (misalign != 0) {
gum_x86_writer_put_bytes(cw, align_pad, 8 - misalign);
}
current_log_impl = cw->pc;
// gum_x86_writer_put_breakpoint(cw);
code_addr = cw->pc;
code.data.assembly = template;
code.data.current_pc = instrument_get_offset_hash(0);
gssize current_pc_value1 =
GPOINTER_TO_SIZE(&instrument_previous_pc) -
(code_addr + offsetof(afl_log_code, data.assembly.mov_rdx_rip_off) +
sizeof(code.data.assembly.mov_rdx_rip_off));
gssize patch_offset1 =
offsetof(afl_log_code, data.assembly.mov_rdx_rip_off) +
sizeof(code.data.assembly.mov_rdx_rip_off) - sizeof(gint);
if (!instrument_coverage_in_range(current_pc_value1)) {
FATAL("Patch out of range (current_pc_value1): 0x%016lX",
current_pc_value1);
}
gint *dst_pc_value = (gint *)&code.bytes[patch_offset1];
*dst_pc_value = (gint)current_pc_value1;
gssize current_pc_value2 =
GPOINTER_TO_SIZE(&instrument_previous_pc) -
(code_addr + offsetof(afl_log_code, data.assembly.mov_rip_off_rdi) +
sizeof(code.data.assembly.mov_rip_off_rdi));
gssize patch_offset2 =
offsetof(afl_log_code, data.assembly.mov_rip_off_rdi) +
sizeof(code.data.assembly.mov_rip_off_rdi) - sizeof(gint);
if (!instrument_coverage_in_range(current_pc_value2)) {
FATAL("Patch out of range (current_pc_value2): 0x%016lX",
current_pc_value2);
}
dst_pc_value = (gint *)&code.bytes[patch_offset2];
*dst_pc_value = (gint)current_pc_value2;
gsize afl_area_ptr_value =
GPOINTER_TO_SIZE(__afl_area_ptr) -
(code_addr + offsetof(afl_log_code, data.assembly.lea_rdi_rip_off) +
sizeof(code.data.assembly.lea_rdi_rip_off));
gssize afl_area_ptr_offset =
offsetof(afl_log_code, data.assembly.lea_rdi_rip_off) +
sizeof(code.data.assembly.lea_rdi_rip_off) - sizeof(gint);
if (!instrument_coverage_in_range(afl_area_ptr_value)) {
FATAL("Patch out of range (afl_area_ptr_value): 0x%016lX",
afl_area_ptr_value);
}
gint *dst_afl_area_ptr_value = (gint *)&code.bytes[afl_area_ptr_offset];
*dst_afl_area_ptr_value = (gint)afl_area_ptr_value;
gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
gum_x86_writer_put_label(cw, after_log_impl);
}
}
void instrument_coverage_optimize(const cs_insn * instr,
GumStalkerOutput *output) {
GumX86Writer *cw = output->writer.x86;
guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
instrument_coverate_write_function(output);
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
-GUM_RED_ZONE_SIZE);
gum_x86_writer_put_push_reg(cw, GUM_REG_RDI);
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset);
gum_x86_writer_put_call_address(cw, current_log_impl);
gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI);
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
GUM_RED_ZONE_SIZE);
}
void instrument_flush(GumStalkerOutput *output) {
gum_x86_writer_flush(output->writer.x86);
}
gpointer instrument_cur(GumStalkerOutput *output) {
return gum_x86_writer_cur(output->writer.x86);
}
#endif
|