Skip to content

Commit

Permalink
Merge pull request #785 from mineo333/transformer_replace_tailjmp_wit…
Browse files Browse the repository at this point in the history
…h_callout_arm_impl

ARM/Thumb implementation for tail jump/skipping the branch instruction
  • Loading branch information
s1341 authored Feb 28, 2024
2 parents aa9b062 + b81cb31 commit 05b3c60
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 36 deletions.
72 changes: 52 additions & 20 deletions gum/backend-arm/gumstalker-arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
27 changes: 11 additions & 16 deletions tests/core/arch-arm/stalker-arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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
Expand All @@ -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++;
}
}

Expand All @@ -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
Expand Down

0 comments on commit 05b3c60

Please sign in to comment.