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(®s->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