diff --git a/gum/backend-arm/gumstalker-arm.c b/gum/backend-arm/gumstalker-arm.c index c83e636c53..f2a92de4f9 100644 --- a/gum/backend-arm/gumstalker-arm.c +++ b/gum/backend-arm/gumstalker-arm.c @@ -2451,15 +2451,17 @@ gum_stalker_iterator_arm_next (GumStalkerIterator * self, { gc->continuation_real_address = instruction->end; return FALSE; - } - - if (gum_arm_relocator_eob (rl)) + } + else if (!skip_implicitly_requested && gum_arm_relocator_eob (rl)) + { return FALSE; + } } instruction = &self->instruction; n_read = gum_arm_relocator_read_one (rl, &instruction->ci); + if (n_read == 0) return FALSE; @@ -2510,10 +2512,11 @@ gum_stalker_iterator_thumb_next (GumStalkerIterator * self, { gc->continuation_real_address = instruction->end; return FALSE; - } - - if (gum_thumb_relocator_eob (rl)) + } + else if (!skip_implicitly_requested && gum_thumb_relocator_eob (rl)) + { return FALSE; + } } instruction = &self->instruction; @@ -2584,13 +2587,25 @@ gum_stalker_iterator_keep (GumStalkerIterator * self) void gum_stalker_iterator_put_chaining_return (GumStalkerIterator * self) { - // GumExecBlock * block = self->exec_block; - // GumGeneratorContext * gc = self->generator_context; + GumExecBlock * block = self->exec_block; + GumGeneratorContext * gc = self->generator_context; + GumBranchTarget target; - // if ((block->ctx->sink_mask & GUM_RET) != 0) - // gum_exec_block_write_ret_event_code (block, gc, GUM_CODE_INTERRUPTIBLE); + target.type = GUM_TARGET_DIRECT_REG_OFFSET; + GumBranchDirectRegOffset * value = &target.value.direct_reg_offset; + value->reg = ARM_REG_LR; + value->offset = 0; + value->mode = GUM_ARM_MODE_CURRENT; - // gum_exec_block_write_chaining_return_code (block, gc, ARM64_REG_X30); + if (gc->is_thumb) + { + gum_exec_block_virtualize_thumb_ret_insn (block, &target, false, 0, gc); + } + else + { + gum_exec_block_virtualize_arm_ret_insn (block, &target, ARM_CC_AL, false, + 0, gc); + } } GumMemoryAccess @@ -2722,11 +2737,13 @@ gum_stalker_iterator_handle_thumb_branch_insn (GumStalkerIterator * self, case ARM_INS_MOV: gum_stalker_get_target_address (insn, TRUE, &target, &mask); gum_exec_block_virtualize_thumb_ret_insn (block, &target, FALSE, 0, gc); + gum_thumb_relocator_skip_one (gc->thumb_relocator); break; case ARM_INS_POP: case ARM_INS_LDM: gum_stalker_get_target_address (insn, TRUE, &target, &mask); gum_exec_block_virtualize_thumb_ret_insn (block, &target, TRUE, mask, gc); + gum_thumb_relocator_skip_one (gc->thumb_relocator); break; case ARM_INS_SMC: case ARM_INS_HVC: @@ -2786,14 +2803,6 @@ gum_stalker_iterator_handle_thumb_it_insn (GumStalkerIterator * self) */ insn->detail->arm.cc = ARM_CC_AL; gum_stalker_iterator_handle_thumb_branch_insn (self, insn); - - /* - * Put a breakpoint to trap and detect any errant continued execution (the - * branch should handle any possible continuation). Skip the original - * branch instruction. - */ - gum_thumb_writer_put_breakpoint (gc->thumb_writer); - gum_thumb_relocator_skip_one (gc->thumb_relocator); } else { @@ -4434,7 +4443,7 @@ gum_exec_block_virtualize_arm_branch_insn (GumExecBlock * block, if (backpatch_prolog_state == GUM_PROLOG_CLOSED) gum_exec_block_arm_open_prolog (block, gc); - + gum_exec_block_write_arm_handle_excluded (block, target, FALSE, gc); gum_exec_block_write_arm_handle_kuser_helper (block, target, gc); gum_exec_block_write_arm_call_switch_block (block, target, gc); @@ -4525,6 +4534,14 @@ gum_exec_block_virtualize_thumb_branch_insn (GumExecBlock * block, gum_exec_block_write_thumb_handle_writeback (block, writeback, gc); gum_exec_block_write_thumb_exec_generated_code (cw, block->ctx); + + /* + * We MUST do this last to account for IT blocks. gum_thumb_relocator_skip_one will complete + * the IT branch, so if we do this early (like in arm), then the end branch will be relocated into the + * middle of the relocated branch + */ + + gum_thumb_relocator_skip_one (gc->thumb_relocator); } static void @@ -4582,6 +4599,14 @@ gum_exec_block_virtualize_thumb_call_insn (GumExecBlock * block, gum_thumb_writer_put_ldr_reg_address (gc->thumb_writer, ARM_REG_LR, GUM_ADDRESS (ret_real_address)); gum_exec_block_write_thumb_exec_generated_code (gc->thumb_writer, block->ctx); + + /* + * We MUST do this last to account for IT blocks. gum_thumb_relocator_skip_one will complete + * the IT branch, so if we do this early (like in arm), then the end branch will be relocated into the middle + * of the relocated branch + */ + + gum_thumb_relocator_skip_one (gc->thumb_relocator); } static void @@ -4641,6 +4666,8 @@ gum_exec_block_virtualize_arm_ret_insn (GumExecBlock * block, } gum_exec_block_write_arm_exec_generated_code (gc->arm_writer, block->ctx); + + gum_arm_relocator_skip_one (gc->arm_relocator); } static void @@ -5077,7 +5104,10 @@ gum_exec_block_write_arm_handle_excluded (GumExecBlock * block, if (target->type == GUM_TARGET_DIRECT_ADDRESS) { if (!check (block->ctx, target->value.direct_address.address)) + { + gum_arm_relocator_skip_one (gc->arm_relocator); return; + } } if (target->type != GUM_TARGET_DIRECT_ADDRESS) @@ -5140,7 +5170,9 @@ gum_exec_block_write_thumb_handle_excluded (GumExecBlock * block, if (target->type == GUM_TARGET_DIRECT_ADDRESS) { if (!check (block->ctx, target->value.direct_address.address)) + { return; + } } if (target->type != GUM_TARGET_DIRECT_ADDRESS) diff --git a/tests/core/arch-arm/stalker-arm.c b/tests/core/arch-arm/stalker-arm.c index a73f84ffc1..f8a5a046d3 100644 --- a/tests/core/arch-arm/stalker-arm.c +++ b/tests/core/arch-arm/stalker-arm.c @@ -3228,7 +3228,7 @@ add_n_return_value_increments (GumStalkerIterator * iterator, TESTCODE (arm_simple_call, 0x04, 0xe0, 0x2d, 0xe5, /* push {lr} */ 0x0d, 0x00, 0x00, 0xe3, /* mov r0, 13 */ - 0x00, 0x00, 0x00, 0xfa, /* blx bump_number */ + 0x00, 0x00, 0x00, 0xeb, /* bl bump_number */ 0x04, 0xf0, 0x9d, 0xe4, /* pop {pc} */ /* bump_number: */ 0x25, 0x00, 0x80, 0xe2, /* add r0, 37 */ @@ -3237,14 +3237,10 @@ TESTCODE (arm_simple_call, TESTCASE (arm_transformer_should_be_able_to_replace_call_with_callout) { - guint32 code[CODE_SIZE (arm_simple_call) / sizeof (guint32)]; - - memcpy (code, arm_simple_call, CODE_SIZE (arm_simple_call)); - fixture->transformer = gum_stalker_transformer_make_from_callback ( replace_call_with_callout, NULL, NULL); - INVOKE_ARM_EXPECTING (GUM_EXEC, code, 0xc001); + INVOKE_ARM_EXPECTING (GUM_NOTHING, arm_simple_call, 0xc001); } static void @@ -3253,16 +3249,19 @@ replace_call_with_callout (GumStalkerIterator * iterator, gpointer user_data) { const cs_insn * insn; - + static int insn_num = 0; while (gum_stalker_iterator_next (iterator, &insn)) { - if (insn->id == ARM_INS_BLX) + if (insn_num == 4) { gum_stalker_iterator_put_callout (iterator, callout_set_cool, - NULL, NULL); - continue; + NULL, NULL); + } + else + { + gum_stalker_iterator_keep (iterator); } - gum_stalker_iterator_keep (iterator); + insn_num++; } } @@ -3276,14 +3275,10 @@ TESTCODE (arm_simple_jumpout, TESTCASE (arm_transformer_should_be_able_to_replace_jumpout_with_callout) { - guint32 code[CODE_SIZE (arm_simple_jumpout) / sizeof (guint32)]; - - memcpy (code, arm_simple_jumpout, CODE_SIZE (arm_simple_jumpout)); - fixture->transformer = gum_stalker_transformer_make_from_callback ( replace_jumpout_with_callout, NULL, NULL); - INVOKE_ARM_EXPECTING (GUM_EXEC, code, 0xc001); + INVOKE_ARM_EXPECTING (GUM_EXEC, arm_simple_jumpout, 0xc001); } static void