Skip to content

Commit

Permalink
stalker: Add StalkerIterator.put_chaining_return() (#777)
Browse files Browse the repository at this point in the history
To be able to add early returns.

Co-authored-by: Ole André Vadla Ravnås <[email protected]>
Co-authored-by: sharad <[email protected]>
  • Loading branch information
3 people authored May 10, 2024
1 parent f1d4319 commit 947d1ba
Show file tree
Hide file tree
Showing 11 changed files with 473 additions and 15 deletions.
35 changes: 35 additions & 0 deletions bindings/gumjs/gumquickstalker.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ GUMJS_DECLARE_GETTER (gumjs_default_iterator_get_memory_access)
GUMJS_DECLARE_FUNCTION (gumjs_default_iterator_next)
GUMJS_DECLARE_FUNCTION (gumjs_default_iterator_keep)
GUMJS_DECLARE_FUNCTION (gumjs_default_iterator_put_callout)
GUMJS_DECLARE_FUNCTION (gumjs_default_iterator_put_chaining_return)

static JSValue gum_quick_special_iterator_new (GumQuickStalker * parent,
GumQuickSpecialIterator ** iterator);
Expand All @@ -125,6 +126,7 @@ GUMJS_DECLARE_GETTER (gumjs_special_iterator_get_memory_access)
GUMJS_DECLARE_FUNCTION (gumjs_special_iterator_next)
GUMJS_DECLARE_FUNCTION (gumjs_special_iterator_keep)
GUMJS_DECLARE_FUNCTION (gumjs_special_iterator_put_callout)
GUMJS_DECLARE_FUNCTION (gumjs_special_iterator_put_chaining_return)

static void gum_quick_callout_free (GumQuickCallout * callout);
static void gum_quick_callout_on_invoke (GumCpuContext * cpu_context,
Expand Down Expand Up @@ -200,6 +202,8 @@ static const JSCFunctionListEntry gumjs_default_iterator_entries[] =
JS_CFUNC_DEF ("next", 0, gumjs_default_iterator_next),
JS_CFUNC_DEF ("keep", 0, gumjs_default_iterator_keep),
JS_CFUNC_DEF ("putCallout", 0, gumjs_default_iterator_put_callout),
JS_CFUNC_DEF ("putChainingReturn", 0,
gumjs_default_iterator_put_chaining_return),
};

static const JSClassDef gumjs_special_iterator_def =
Expand All @@ -215,6 +219,8 @@ static const JSCFunctionListEntry gumjs_special_iterator_entries[] =
JS_CFUNC_DEF ("next", 0, gumjs_special_iterator_next),
JS_CFUNC_DEF ("keep", 0, gumjs_special_iterator_keep),
JS_CFUNC_DEF ("putCallout", 0, gumjs_special_iterator_put_callout),
JS_CFUNC_DEF ("putChainingReturn", 0,
gumjs_special_iterator_put_chaining_return),
};

static const JSClassExoticMethods gumjs_probe_args_exotic_methods =
Expand Down Expand Up @@ -1016,6 +1022,15 @@ gum_quick_stalker_iterator_put_callout (GumQuickIterator * self,
return JS_UNDEFINED;
}

static JSValue
gum_quick_stalker_iterator_put_chaining_return (GumQuickIterator * self,
JSContext * ctx)
{
gum_stalker_iterator_put_chaining_return (self->handle);

return JS_UNDEFINED;
}

static JSValue
gum_quick_default_iterator_new (GumQuickStalker * parent,
GumQuickDefaultIterator ** iterator)
Expand Down Expand Up @@ -1135,6 +1150,16 @@ GUMJS_DEFINE_FUNCTION (gumjs_default_iterator_put_callout)
return gum_quick_stalker_iterator_put_callout (&self->iterator, ctx, args);
}

GUMJS_DEFINE_FUNCTION (gumjs_default_iterator_put_chaining_return)
{
GumQuickDefaultIterator * self;

if (!gum_quick_default_iterator_get (ctx, this_val, core, &self))
return JS_EXCEPTION;

return gum_quick_stalker_iterator_put_chaining_return (&self->iterator, ctx);
}

static JSValue
gum_quick_special_iterator_new (GumQuickStalker * parent,
GumQuickSpecialIterator ** iterator)
Expand Down Expand Up @@ -1254,6 +1279,16 @@ GUMJS_DEFINE_FUNCTION (gumjs_special_iterator_put_callout)
return gum_quick_stalker_iterator_put_callout (&self->iterator, ctx, args);
}

GUMJS_DEFINE_FUNCTION (gumjs_special_iterator_put_chaining_return)
{
GumQuickSpecialIterator * self;

if (!gum_quick_special_iterator_get (ctx, this_val, core, &self))
return JS_EXCEPTION;

return gum_quick_stalker_iterator_put_chaining_return (&self->iterator, ctx);
}

static void
gum_quick_callout_free (GumQuickCallout * callout)
{
Expand Down
28 changes: 28 additions & 0 deletions bindings/gumjs/gumv8stalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ GUMJS_DECLARE_GETTER (gumjs_stalker_default_iterator_get_memory_access)
GUMJS_DECLARE_FUNCTION (gumjs_stalker_default_iterator_next)
GUMJS_DECLARE_FUNCTION (gumjs_stalker_default_iterator_keep)
GUMJS_DECLARE_FUNCTION (gumjs_stalker_default_iterator_put_callout)
GUMJS_DECLARE_FUNCTION (gumjs_stalker_default_iterator_put_chaining_return)

static GumV8StalkerSpecialIterator *
gum_v8_stalker_special_iterator_new_persistent (GumV8Stalker * parent);
Expand All @@ -149,6 +150,7 @@ GUMJS_DECLARE_GETTER (gumjs_stalker_special_iterator_get_memory_access)
GUMJS_DECLARE_FUNCTION (gumjs_stalker_special_iterator_next)
GUMJS_DECLARE_FUNCTION (gumjs_stalker_special_iterator_keep)
GUMJS_DECLARE_FUNCTION (gumjs_stalker_special_iterator_put_callout)
GUMJS_DECLARE_FUNCTION (gumjs_stalker_special_iterator_put_chaining_return)

static void gum_v8_callout_free (GumV8Callout * callout);
static void gum_v8_callout_on_invoke (GumCpuContext * cpu_context,
Expand Down Expand Up @@ -227,6 +229,7 @@ static const GumV8Function gumjs_stalker_default_iterator_functions[] =
{ "next", gumjs_stalker_default_iterator_next },
{ "keep", gumjs_stalker_default_iterator_keep },
{ "putCallout", gumjs_stalker_default_iterator_put_callout },
{ "putChainingReturn", gumjs_stalker_default_iterator_put_chaining_return },

{ NULL, NULL }
};
Expand All @@ -243,6 +246,7 @@ static const GumV8Function gumjs_stalker_special_iterator_functions[] =
{ "next", gumjs_stalker_special_iterator_next },
{ "keep", gumjs_stalker_special_iterator_keep },
{ "putCallout", gumjs_stalker_special_iterator_put_callout },
{ "putChainingReturn", gumjs_stalker_special_iterator_put_chaining_return },

{ NULL, NULL }
};
Expand Down Expand Up @@ -1083,6 +1087,16 @@ gum_v8_stalker_iterator_put_callout (GumV8StalkerIterator * self,
}
}

static void
gum_v8_stalker_iterator_put_chaining_return (GumV8StalkerIterator * self,
Isolate * isolate)
{
if (!gum_v8_stalker_iterator_check_valid (self, isolate))
return;

gum_stalker_iterator_put_chaining_return (self->handle);
}

static GumV8StalkerDefaultIterator *
gum_v8_stalker_default_iterator_new_persistent (GumV8Stalker * parent)
{
Expand Down Expand Up @@ -1170,6 +1184,13 @@ GUMJS_DEFINE_DIRECT_SUBCLASS_METHOD (gumjs_stalker_default_iterator_put_callout,
gum_v8_stalker_iterator_put_callout (&self->iterator, args, isolate);
}

GUMJS_DEFINE_DIRECT_SUBCLASS_METHOD (
gumjs_stalker_default_iterator_put_chaining_return,
GumV8StalkerDefaultIterator)
{
gum_v8_stalker_iterator_put_chaining_return (&self->iterator, isolate);
}

static GumV8StalkerSpecialIterator *
gum_v8_stalker_special_iterator_new_persistent (GumV8Stalker * parent)
{
Expand Down Expand Up @@ -1257,6 +1278,13 @@ GUMJS_DEFINE_DIRECT_SUBCLASS_METHOD (gumjs_stalker_special_iterator_put_callout,
gum_v8_stalker_iterator_put_callout (&self->iterator, args, isolate);
}

GUMJS_DEFINE_DIRECT_SUBCLASS_METHOD (
gumjs_stalker_special_iterator_put_chaining_return,
GumV8StalkerSpecialIterator)
{
gum_v8_stalker_iterator_put_chaining_return (&self->iterator, isolate);
}

static void
gum_v8_callout_free (GumV8Callout * callout)
{
Expand Down
60 changes: 50 additions & 10 deletions gum/backend-arm/gumstalker-arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2512,7 +2512,7 @@ gum_stalker_iterator_arm_next (GumStalkerIterator * self,
return FALSE;
}

if (gum_arm_relocator_eob (rl))
if (!skip_implicitly_requested && gum_arm_relocator_eob (rl))
return FALSE;
}

Expand Down Expand Up @@ -2571,7 +2571,7 @@ gum_stalker_iterator_thumb_next (GumStalkerIterator * self,
return FALSE;
}

if (gum_thumb_relocator_eob (rl))
if (!skip_implicitly_requested && gum_thumb_relocator_eob (rl))
return FALSE;
}

Expand Down Expand Up @@ -2769,11 +2769,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 @@ -2833,14 +2835,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 @@ -3419,6 +3413,31 @@ gum_stalker_invoke_callout (GumCalloutEntry * entry,
ec->pending_calls--;
}

void
gum_stalker_iterator_put_chaining_return (GumStalkerIterator * self)
{
GumExecBlock * block = self->exec_block;
GumGeneratorContext * gc = self->generator_context;
GumBranchTarget target;
GumBranchDirectRegOffset * value;

target.type = GUM_TARGET_DIRECT_REG_OFFSET;
value = &target.value.direct_reg_offset;
value->reg = ARM_REG_LR;
value->offset = 0;
value->mode = GUM_ARM_MODE_CURRENT;

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);
}
}

csh
gum_stalker_iterator_get_capstone (GumStalkerIterator * self)
{
Expand Down Expand Up @@ -4572,6 +4591,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 on 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 @@ -4629,6 +4656,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 on 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 @@ -4688,6 +4723,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 @@ -5124,7 +5161,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
22 changes: 22 additions & 0 deletions gum/backend-arm64/gumstalker-arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,8 @@ static void gum_exec_block_write_jmp_transfer_code (GumExecBlock * block,
GumGeneratorContext * gc);
static void gum_exec_block_write_ret_transfer_code (GumExecBlock * block,
GumGeneratorContext * gc, arm64_reg ret_reg);
static void gum_exec_block_write_chaining_return_code (GumExecBlock * block,
GumGeneratorContext * gc, arm64_reg ret_reg);
static void gum_exec_block_write_slab_transfer_code (GumArm64Writer * from,
GumArm64Writer * to);
static void gum_exec_block_backpatch_slab (GumExecBlock * block,
Expand Down Expand Up @@ -3146,6 +3148,18 @@ gum_stalker_invoke_callout (GumCalloutEntry * entry,
ec->pending_calls--;
}

void
gum_stalker_iterator_put_chaining_return (GumStalkerIterator * self)
{
GumExecBlock * block = self->exec_block;
GumGeneratorContext * gc = self->generator_context;

if ((block->ctx->sink_mask & GUM_RET) != 0)
gum_exec_block_write_ret_event_code (block, gc, GUM_CODE_INTERRUPTIBLE);

gum_exec_block_write_chaining_return_code (block, gc, ARM64_REG_X30);
}

csh
gum_stalker_iterator_get_capstone (GumStalkerIterator * self)
{
Expand Down Expand Up @@ -5093,6 +5107,14 @@ static void
gum_exec_block_write_ret_transfer_code (GumExecBlock * block,
GumGeneratorContext * gc,
arm64_reg ret_reg)
{
gum_exec_block_write_chaining_return_code (block, gc, ret_reg);
}

static void
gum_exec_block_write_chaining_return_code (GumExecBlock * block,
GumGeneratorContext * gc,
arm64_reg ret_reg)
{
GumArm64Writer * cw = gc->code_writer;
GumArm64Writer * cws = gc->slow_writer;
Expand Down
5 changes: 5 additions & 0 deletions gum/backend-mips/gumstalker-mips.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ gum_stalker_iterator_put_callout (GumStalkerIterator * self,
{
}

void
gum_stalker_iterator_put_chaining_return (GumStalkerIterator * self)
{
}

csh
gum_stalker_iterator_get_capstone (GumStalkerIterator * self)
{
Expand Down
Loading

0 comments on commit 947d1ba

Please sign in to comment.