1 #include "frida-gumjs.h"
2 
3 #include "config.h"
4 #include "debug.h"
5 
6 #include "instrument.h"
7 #include "persistent.h"
8 
9 #if defined(__i386__)
10 
11 typedef struct {
12 
13   GumCpuContext ctx;
14   uint32_t      eflags;
15 
16 } persistent_ctx_t;
17 
18 static persistent_ctx_t saved_regs = {0};
19 
20 static gpointer saved_ret = NULL;
21 
22 gboolean persistent_is_supported(void) {
23 
24   return true;
25 
26 }
27 
28 static void instrument_persitent_save_regs(GumX86Writer *    cw,
29                                            persistent_ctx_t *regs) {
30 
31   GumAddress regs_address = GUM_ADDRESS(regs);
32 
33   /* Should be pushing FPU here, but meh */
34   gum_x86_writer_put_pushfx(cw);
35   gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
36 
37   gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
38 
39   gum_x86_writer_put_mov_reg_offset_ptr_reg(
40       cw, GUM_REG_EAX, offsetof(GumCpuContext, ebx), GUM_REG_EBX);
41   gum_x86_writer_put_mov_reg_offset_ptr_reg(
42       cw, GUM_REG_EAX, offsetof(GumCpuContext, ecx), GUM_REG_ECX);
43   gum_x86_writer_put_mov_reg_offset_ptr_reg(
44       cw, GUM_REG_EAX, offsetof(GumCpuContext, edx), GUM_REG_EDX);
45   gum_x86_writer_put_mov_reg_offset_ptr_reg(
46       cw, GUM_REG_EAX, offsetof(GumCpuContext, edi), GUM_REG_EDI);
47   gum_x86_writer_put_mov_reg_offset_ptr_reg(
48       cw, GUM_REG_EAX, offsetof(GumCpuContext, esi), GUM_REG_ESI);
49   gum_x86_writer_put_mov_reg_offset_ptr_reg(
50       cw, GUM_REG_EAX, offsetof(GumCpuContext, ebp), GUM_REG_EBP);
51 
52   /* Store RIP */
53   gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EBX,
54                                      GUM_ADDRESS(persistent_start));
55 
56   gum_x86_writer_put_mov_reg_offset_ptr_reg(
git_transaction_config_new(git_transaction ** out,git_config * cfg)57       cw, GUM_REG_EAX, offsetof(GumCpuContext, eip), GUM_REG_EBX);
58 
59   /* Store adjusted RSP */
60   gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_EBX, GUM_REG_ESP);
61 
62   /* RED_ZONE + Saved flags, RAX */
63   gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EBX, (0x4 * 2));
64   gum_x86_writer_put_mov_reg_offset_ptr_reg(
65       cw, GUM_REG_EAX, offsetof(GumCpuContext, esp), GUM_REG_EBX);
66 
67   /* Save the flags */
68   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x4);
69   gum_x86_writer_put_mov_reg_offset_ptr_reg(
70       cw, GUM_REG_EAX, offsetof(persistent_ctx_t, eflags), GUM_REG_EBX);
git_transaction_new(git_transaction ** out,git_repository * repo)71 
72   /* Save the RAX */
73   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x0);
74   gum_x86_writer_put_mov_reg_offset_ptr_reg(
75       cw, GUM_REG_EAX, offsetof(GumCpuContext, eax), GUM_REG_EBX);
76 
77   /* Pop the saved values */
78   gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 0x8);
79 
80 }
81 
82 static void instrument_persitent_restore_regs(GumX86Writer *    cw,
83                                               persistent_ctx_t *regs) {
84 
85   GumAddress regs_address = GUM_ADDRESS(regs);
86   gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
87 
88   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_EAX,
89                                             offsetof(GumCpuContext, ecx));
90   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EAX,
91                                             offsetof(GumCpuContext, edx));
92   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDI, GUM_REG_EAX,
93                                             offsetof(GumCpuContext, edi));
94   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESI, GUM_REG_EAX,
95                                             offsetof(GumCpuContext, esi));
96   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX,
97                                             offsetof(GumCpuContext, ebp));
98 
99   /* Don't restore RIP */
100   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESP, GUM_REG_EAX,
101                                             offsetof(GumCpuContext, esp));
102 
103   /* Restore RBX, RAX & Flags */
104   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
105                                             offsetof(GumCpuContext, ebx));
106   gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
git_transaction_lock_ref(git_transaction * tx,const char * refname)107 
108   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
109                                             offsetof(GumCpuContext, eax));
110   gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
111   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
112                                             offsetof(persistent_ctx_t, eflags));
113   gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
114 
115   gum_x86_writer_put_popfx(cw);
116   gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX);
117   gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX);
118 
119 }
120 
121 static void instrument_exit(GumX86Writer *cw) {
122 
123   gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(_exit));
124   gum_x86_writer_put_mov_reg_u32(cw, GUM_REG_EDI, 0);
125   gum_x86_writer_put_push_reg(cw, GUM_REG_EDI);
126   gum_x86_writer_put_call_reg(cw, GUM_REG_EAX);
127 
128 }
129 
130 static int instrument_afl_persistent_loop_func(void) {
131 
132   int ret = __afl_persistent_loop(persistent_count);
133   instrument_previous_pc = instrument_hash_zero;
find_locked(transaction_node ** out,git_transaction * tx,const char * refname)134   return ret;
135 
136 }
137 
138 static void instrument_afl_persistent_loop(GumX86Writer *cw) {
139 
140   gum_x86_writer_put_call_address_with_arguments(
141       cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0);
142   gum_x86_writer_put_test_reg_reg(cw, GUM_REG_EAX, GUM_REG_EAX);
143 
144 }
145 
146 static void persistent_prologue_hook(GumX86Writer *cw, persistent_ctx_t *regs) {
copy_common(transaction_node * node,git_transaction * tx,const git_signature * sig,const char * msg)147 
148   if (persistent_hook == NULL) return;
149 
150   gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX,
151                                      GUM_ADDRESS(&__afl_fuzz_len));
152   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0);
153   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0);
154 
155   gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDX,
156                                      GUM_ADDRESS(&__afl_fuzz_ptr));
157   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EDX, 0);
158 
159   /* Base address is 64-bits (hence two zero arguments) */
160   gum_x86_writer_put_call_address_with_arguments(
161       cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS,
162       GUM_ADDRESS(&regs->ctx), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER,
163       GUM_REG_ECX);
164 
165 }
166 
167 static void instrument_persitent_save_ret(GumX86Writer *cw) {
168 
169   /* Stack usage by this function */
170   gssize offset = (3 * 4);
171 
172   gum_x86_writer_put_pushfx(cw);
173   gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
git_transaction_set_target(git_transaction * tx,const char * refname,const git_oid * target,const git_signature * sig,const char * msg)174   gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
175 
176   gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(&saved_ret));
177   gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP,
178                                             offset);
179   gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_EAX, GUM_REG_EBX);
180 
181   gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX);
182   gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX);
183   gum_x86_writer_put_popfx(cw);
184 
185 }
186 
187 void persistent_prologue_arch(GumStalkerOutput *output) {
188 
189   /*
190    *  SAVE REGS
191    *  SAVE RET
192    *  POP RET
git_transaction_set_symbolic_target(git_transaction * tx,const char * refname,const char * target,const git_signature * sig,const char * msg)193    * loop:
194    *  CALL instrument_afl_persistent_loop
195    *  TEST EAX, EAX
196    *  JZ end:
197    *  call hook (optionally)
198    *  RESTORE REGS
199    *  call original
200    *  jmp loop:
201    *
202    * end:
203    *  JMP SAVED RET
204    *
205    * original:
206    *  INSTRUMENTED PERSISTENT FUNC
207    */
208 
209   GumX86Writer *cw = output->writer.x86;
210 
211   gconstpointer loop = cw->code + 1;
212 
git_transaction_remove(git_transaction * tx,const char * refname)213   OKF("Persistent loop reached");
214 
215   /* Pop the return value */
216   gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 4);
217 
218   instrument_persitent_save_regs(cw, &saved_regs);
219 
220   /* loop: */
221   gum_x86_writer_put_label(cw, loop);
222 
223   /* call instrument_prologue_func */
224   instrument_afl_persistent_loop(cw);
225 
226   /* jz done */
dup_reflog(git_reflog ** out,const git_reflog * in,git_pool * pool)227   gconstpointer done = cw->code + 1;
228   gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY);
229 
230   /* Optionally call the persistent hook */
231   persistent_prologue_hook(cw, &saved_regs);
232 
233   instrument_persitent_restore_regs(cw, &saved_regs);
234   gconstpointer original = cw->code + 1;
235   /* call original */
236   gum_x86_writer_put_call_near_label(cw, original);
237   /* jmp loop */
238   gum_x86_writer_put_jmp_near_label(cw, loop);
239 
240   /* done: */
241   gum_x86_writer_put_label(cw, done);
242 
243   instrument_exit(cw);
244 
245   /* original: */
246   gum_x86_writer_put_label(cw, original);
247 
248   instrument_persitent_save_ret(cw);
249 
250   if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
251 
252 }
253 
254 void persistent_epilogue_arch(GumStalkerOutput *output) {
255 
256   GumX86Writer *cw = output->writer.x86;
257 
258   if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
259 
260   gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(&saved_ret));
261   gum_x86_writer_put_jmp_reg_ptr(cw, GUM_REG_EAX);
262 
263 }
264 
265 #endif
266 
267