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 + trampolineSizehookCount;
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即可,你可以提交代码给作者
@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);
gc分支为了hook一个方法,需要再写3个java method,其中的origin()是供hook()调用,作用只是跳转到copy(),copy()是对原方法ArtMethod的完全复制。
不在origin()做复制ArtMethod
,是由于hook在首次调用origin时,因其是静态方法故需要按照方法名解析
可以考虑回退到之前的实现,通过覆盖method cache的方式人工将origin()的解析完成,这样就不需要copy()方法。这么做的话就需要在trampoline1中清理hotness