frida / frida-gum

Cross-platform instrumentation and introspection library written in C
https://frida.re
Other
734 stars 242 forks source link

Is gum_stalker_iterator_put_callout in CModule async? #686

Open aeskkkey opened 1 year ago

aeskkkey commented 1 year ago

The transform code in CModule looks like below

static void on_ret (GumCpuContext * ctx, gpointer user_data);

void transform(GumStalkerIterator *iterator, GumStalkerOutput *output, gpointer user_data) {
    cs_insn *insn;
    while (gum_stalker_iterator_next(iterator, &insn)) {
        gboolean in_target = false;
        // ... some code checking whether insn->address is in lib range from user_data.
        if (in_target) {
            gpointer data = (gpointer) insn; 
            gum_stalker_iterator_put_callout(iterator, on_ret , data, NULL);
        }
        gum_stalker_iterator_keep(iterator);
    }
}

static void on_ret(GumCpuContext *ctx, gpointer data) {
    cs_insn *insn = (cs_insn*) data;
    log("insn: 0x%lx %s %s", (gpointer) insn->address, insn->mnemonic, insn->op_str, ctx->pc);
}

Everything runs right at the begining, but after a while the pc value is going wrong. I search the address 0xa2808 and found the instruction change.

log line 13930-13940
0xa2a44 ldr w8, [x27]
0xa2a48 ldr x8, [x20, x8, lsl #3]
0xa27f4 ldr x0, [x27, #8]
0xa27f8 add x27, x27, x0, lsl #4
0xa27fc ldr w8, [x27]
0xa2800 ldr x8, [x20, x8, lsl #3]
0xa2804 str x27, [x28, #0x10]
->0xa2808   br  x8
0xa30f8 ldr x0, [x27, #8]
0xa30fc add x27, x27, x0, lsl #4
0xf3100 ldr w8, [x27]

log line 25450-25460
0xa2a3c cmp x12, x13
0xa2a40 b.hs    #0x7a409366cc
0xa2a44 str x27, [x28, #0x10]
0xa2a48 br  x8
0xa27f4 cmp x12, x13
0xa27f8 b.hs    #0x7a409366cc
0xa27fc str x27, [x28, #0x10]
0xa2800 br  x8
0xa2804 adr x2, #0x7a409368d4
->0xa2808   ldrb    w2, [x2, x0]
0xa30f8 cmp x12, x13

log line 38320-38330
0xa2a44 ldp x22, x21, [sp, #0x30]
0xa2a48 ldp x26, x25, [sp, #0x20]
0xa27f4 ldp x29, x30, [sp, #0x50]
0xa27f8 ldp x20, x19, [sp, #0x40]
0xa27fc ldp x22, x21, [sp, #0x30]
0xa2800 ldp x26, x25, [sp, #0x20]
0xa2804 ldr x28, [sp, #0x10]
->0xa2808   add sp, sp, #0x60
0xa30f8 ldp x29, x30, [sp, #0x50]
0xa30fc ldp x20, x19, [sp, #0x40]
0xa3100 ldp x22, x21, [sp, #0x30]

With the js script, the pc is right. All 0xa2808 pc instruction are br x8.

var lib = Process.findModuleByName("lib-native.so");
Stalker.follow(Process.getCurrentThreadId(), {
    transform(it) {
        var insn = it.next();
        var addr = insn.address;
        do {
            if (addr.compare(lib.base) >= 0 && addr.compare(lib.base.add(lib.size)) === -1) {
                it.putCallout(function (ctx) {
                    var nme = Instruction.parse(ptr(ctx.pc));
                    console.log("onReceive", lib.name + "!" + ptr(ctx.pc).sub(lib.base), nme);
                })
            }
            it.keep();
        } while (insn = it.next() !== null)
    }
})

So I guess the gum_stalker_iterator_keep runs async, and *insn change when the on_ret callback was called.

I also try to malloc a new cs_insn struct and copy one to the on_ret callback, then release it. But the CModule doesn't found the malloc function when compiling.

#include <gum/gumstalker.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// ... other function
void transform(GumStalkerIterator *iterator, GumStalkerOutput *output, gpointer user_data) {
    cs_insn *insn;
    while (gum_stalker_iterator_next(iterator, &insn)) {
        gboolean in_target = false;
        // ... some code checking whether insn->address is in lib range from user_data.
        if (in_target) {
            struct cs_insn *insn_cp;
            insn_cp = (cs_insn*) malloc(sizeof(struct cs_insn));
            insn_cp->address = insn->address;
            memcpy(insn_cp->mnemonic, insn->mnemonic, CS_MNEMONIC_SIZE);
            memcpy(insn_cp->op_str, insn->op_str, 160);
            gum_stalker_iterator_put_callout(iterator, on_ret , (gpointer)insn_cp, NULL);
        }
        gum_stalker_iterator_keep(iterator);
    }
}

static void on_ret(GumCpuContext *ctx, gpointer data) {
    cs_insn *insn = (cs_insn*) data;
    log("insn: 0x%lx %s %s", (gpointer) insn->address, insn->mnemonic, insn->op_str, ctx->pc);
    free(data);
}
compilation failed: module.c:46: error: implicit declaration of function 'malloc' at <eval>