void Shade::detour(void *address, void *target, void *&trampoline) { const size_t instr_max = 17; auto list = instrlist_create(dr); byte instr_data[instr_max]; byte *current = (byte *)address; byte *min_pos = (byte *)address + 5; size_t size = 0; while(current < min_pos) { read(current, instr_data, instr_max); auto instr = instr_create(dr); byte *decoded = decode_from_copy(dr, instr_data, current, instr); if(!decoded) error("Unknown instruction"); instrlist_append(list, instr); instr_make_persistent(dr, instr); current += (size_t)(decoded - instr_data); size += instr_length(dr, instr); } auto instr = INSTR_CREATE_jmp(dr, opnd_create_pc(current)); size += instr_length(dr, instr); instrlist_append(list, instr); auto local_trampoline = alloca(size); if(!local_trampoline) error("Out of memory"); void *remote = code_section.allocate(size, 4); if(!instrlist_encode_to_copy(dr, list, (byte *)local_trampoline, (byte *)remote, 0, true)) error("Unable to encode instructions"); instrlist_clear_and_destroy(dr, list); write(remote, local_trampoline, size); trampoline = remote; char code[5]; DWORD offset = (size_t)target - (size_t)address - 5; code[0] = 0xE9; *(DWORD *)(code + 1) = offset; access(address, 5, [&] { write(address, code, 5); }); }
byte * instrlist_encode(dcontext_t *dcontext, instrlist_t *ilist, byte *pc, bool has_instr_jmp_targets) { return instrlist_encode_to_copy(dcontext, ilist, pc, pc, NULL, has_instr_jmp_targets); }