PAGalaxyLab/YAHFA

origin执行的问题

Closed this issue · 11 comments

代码如下:
public static void hook(Object thiz, int arg0) {

    Log.i("YAHFA", "hook here");
   
    origin(thiz, arg0);
}

public static void origin(Object thiz, int arg0) {
    Log.w("YAHFA", "should not be here");
    return;
}

前面执行是正常的,一直执行hook,并没有输出 should not be here,但是运行一会以后,就会出现should not be here了,然后就不正常了

加1:但奇怪的是,我还有几个其他类似的都没有问题,只有这个有问题

加2:再进一步测试,发现其他几个也有此问题,只是需要过的时间较长才会出现问题

改一下这个机器码,init函数和genTrampoline1函数的某些offset需要修改,自己研究一下吧
`#if defined(i386)
// b8 78 56 34 12 ; mov eax, 0x12345678
// 66 c7 40 12 00 00 ; mov word [eax + 0x12], 0
// ff 70 20 ; push dword [eax + 0x20]
// c3 ; ret
unsigned char trampoline1[] = {
0xb8, 0x78, 0x56, 0x34, 0x12,
0x66, 0xc7, 0x40, 0x12, 0x00, 0x00,
0xff, 0x70, 0x20,
0xc3
};
static unsigned int t1Size = roundUpToPtrSize(sizeof(trampoline1)); // for alignment

#elif defined(arm)
//------------------------------> 10 00 9f e5 ; ldr r0, [pc, #20]
//------------------------------> 04 40 2d e5 ; push {r4}
//------------------------------> 00 40 a0 e3 ; mov r4, #0
//------------------------------> b2 41 c0 e1 ; strh r4, [r0, #18]
//------------------------------> 04 40 9d e4 ; pop {r4}
// 00 00 9F E5 ; ldr r0, [pc]
// 20 F0 90 E5 ; ldr pc, [r0, 0x20]
// 78 56 34 12 ; 0x12345678
unsigned char trampoline1[] = {
0x14, 0x00, 0x9f, 0xe5,
0x04, 0x40, 0x2d, 0xe5,
0x00, 0x40, 0xa0, 0xe3,
0xb2, 0x41, 0xc0, 0xe1,
0x04, 0x40, 0x9d, 0xe4,
0x00, 0x00, 0x9f, 0xe5,
0x20, 0xf0, 0x90, 0xe5,
0x78, 0x56, 0x34, 0x12
};
static unsigned int t1Size = sizeof(trampoline1);

#elif defined(aarch64)
// 60 00 00 58 ; ldr x0, 12 ------->// 80 00 00 58 ; ldr x0, 16 解决同dex时hotness的问题
// 1f 24 00 79 ; strh wzr, [x0, #18]

// 10 18 40 f9 ; ldr x16, [x0, #48]
// 00 02 1f d6 ; br x16
// 78 56 34 12
// 89 67 45 23 ; 0x2345678912345678
unsigned char trampoline1[] = {
0x80, 0x00, 0x00, 0x58,
0x1f, 0x24, 0x00, 0x79,
// 0x60, 0x00, 0x00, 0x58,
0x10, 0x18, 0x40, 0xf9,
0x00, 0x02, 0x1f, 0xd6,
0x78, 0x56, 0x34, 0x12,
0x89, 0x67, 0x45, 0x23
};
static unsigned int t1Size = roundUpToPtrSize(sizeof(trampoline1));
#endif`

补充上吧
`#if defined(i386)
trampoline1[13] = OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
if(SDKVersion < ANDROID_N) { // do not set hotness_count before N
memset(trampoline2+5, '\x90', 6);
}
#elif defined(arm)
trampoline1[24] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
//trampoline1[4] = (unsigned char)OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
if(SDKVersion < ANDROID_N) { // do not set hotness_count before N
for(i=0; i<=16; i+=4) {
memcpy(trampoline1+i, "\x00\x00\xa0\xe1", 4); // mov r0, r0
}
for(i=4; i<=16; i+=4) {
memcpy(trampoline2+i, "\x00\x00\xa0\xe1", 4); // mov r0, r0
}
}
#elif defined(aarch64)
if (SDKVersion < ANDROID_N) { // do not set hotness_count before N
memcpy(trampoline2 + 4, "\x1f\x20\x03\xd5", 4); // nop
memcpy(trampoline1 + 4, "\x1f\x20\x03\xd5", 4); // nop
//下面这个改的没测试
if (SDKVersion == ANDROID_L2) {
memcpy(trampoline1 + 8, "\x10\x1c\x40\xf9",
4); //101c40f9 ; ldr x16, [x0, #56] set entry point offset
// memcpy(trampoline1+4, "\x10\x1c\x40\xf9", 4);
} else if (SDKVersion == ANDROID_L) {
memcpy(trampoline1 + 8, "\x10\x14\x40\xf9",
4); //101440f9 ; ldr x16, [x0, #40] set entry point offset
// memcpy(trampoline1+4, "\x10\x14\x40\xf9", 4);
}
}
#endif

void genTrampoline1(void hookMethod) {
void targetAddr;
/

if(mprotect(trampolineCode, trampolineCodeSize, PROT_READ | PROT_WRITE) == -1) {
LOGE("mprotect RW failed");
return NULL;
}
/
targetAddr = trampolineCode + trampolineSize
hookCount;
memcpy(targetAddr, trampoline1, sizeof(trampoline1)); // do not use t1size since it's a rounded size
// replace with the hook ArtMethod addr
#if defined(i386)
memcpy(targetAddr+1, &hookMethod, pointer_size);
#elif defined(arm)
memcpy(targetAddr+28, &hookMethod, pointer_size);
// memcpy(targetAddr+8, &hookMethod, pointer_size);
#elif defined(aarch64)
memcpy(targetAddr+16, &hookMethod, pointer_size);
#endif
/*
if(mprotect(trampolineCode, trampolineCodeSize, PROT_READ | PROT_EXEC) == -1) {
LOGE("mprotect RX failed");
return NULL;
}
*/
return targetAddr;
}`

@svengong 你这个是对的,第二个方法trampoline2不用清除hotness,只清除第一个trampoline1中的hotness即可,你可以提交代码给作者

@zhuotong 没空弄呢
另外原工程里trampoline2就是清除hotness的,那个也是需要的

@svengong 使用gc这个分支的代码是不需要清除trampoline2的hotness,只会增加hook这个方法的hotness(如果hook这个方法在主程序,即第一次解释执行)

清除trampoline2的hotness是遗留代码,因为一开始备份方法是完全复制源方法,现在都做了跳转,之会增加hook方法的hotness

@zhuotong trampoline2清除的是tmpMethod方法的hotness

static int doBackupAndHook(void *originMethod, void *hookMethod, void *backupMethod, void *tmpMethod) {
if (hookCount >= hookCap) {
    LOGW("not enough capacity. Allocating...");
    if (doInitHookCap(DEFAULT_CAP)) {
        LOGE("cannot hook method");
        return 1;
    }
    LOGI("Allocating done");
}

if (!backupMethod) {
    LOGW("backup method is null");
} else { //do method backup
    memcpy(tmpMethod, originMethod, ArtMethodSize);

    void *realEntryPoint = (void *) readAddr((char *) originMethod +
                                             OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod);
    void *newEntryPoint = genTrampoline2(tmpMethod, realEntryPoint);

@svengong 算了,你自己测试下不就知道增不增加了,我只是给你说下,如果你提交代码可以一并提交

@zhuotong 说的对

rk700 commented

gc分支为了hook一个方法,需要再写3个java method,其中的origin()是供hook()调用,作用只是跳转到copy(),copy()是对原方法ArtMethod的完全复制。

不在origin()做复制ArtMethod,是由于hook在首次调用origin时,因其是静态方法故需要按照方法名解析

可以考虑回退到之前的实现,通过覆盖method cache的方式人工将origin()的解析完成,这样就不需要copy()方法。这么做的话就需要在trampoline1中清理hotness

@rk700
可以考虑回退到之前的实现,通过覆盖method cache的方式人工将origin()的解析完成,这样就不需要copy()方法。这么做的话就需要在trampoline1中清理hotness
这里的“,通过覆盖method cache的方式人工将origin()的解析完成”,不太理解,应该怎么做?因为文档里说是因为ToDexPC的问题才复制origin