1.干扰砸壳
1)在Load方法中检测是否越狱,如果是则直接退出。效果:
越狱机无法运行,无法直接使用frida一键砸壳,增加砸壳的困难性。
2)在load方法中使用ptrace或者svc汇编检测是否有调试器附加,一旦lldb调试,则直接闪退。 效果:
通过第一点,逆向开发人员无法直接砸壳,很可能会使用debugserver对App进行启动前附加调试。
这时候load方法检测到调试器,则直接闪退。进一步干扰砸壳。
解决方法:
创建一个tweak,随便写个类,在该类的load方法执行一个耗时操作,足够frida砸壳即可。
2.指定函数的section
关键防护函数或者关键逻辑使用C语言实现,并指定section为非__text。干扰IDA解析,影响动态调试的堆栈打印。例如:
#include "Test.h"
__attribute__ ((section ("__TEXT,objd")))
void say() {
int a = 10;
int b = 100;
if (a > b) {
printf("hheheh");
}
}
复制代码
另外像今年的抖音技术博客以及戴铭大佬博客中提到的App包瘦身优化,把所有的代码都挪到别的section了。
3.花指令混淆
核心原理:
通过插入一些垃圾指令(例如:”.long 0x0ffbcfa4\n” ), 干扰 IDA等反汇编工具,无法直接反汇编成伪代码,影响静态分析。
假设一个函数,指令1正在执行,那么指令2正在译码,指令3正在取址,而PC寄存器是保存当前正在取值的地址,也就是说PC保存的是指令3的地址,
重点:
1.只能真机调试,不支持模拟器调试;
2.由于arm64不能直接使用lr, pc等寄存器,因此 需要使用 #ifdef arm64 兼容 arm64和 arm v7,7s。
3.对于 arm64,首先定义一个裸函数 getpc(), 该函数全部有汇编代码实现, 该函数的作用就是 将x30寄存器的值 赋值给 x16寄存器。
即该函数调用的下一条指令地址 赋值给 x16. 然后 x16 + 8 + n * 4 , 其中:
8 是 ( “mov x30,x16\n” “ret\n”)两条指令的长度, n * 4 是 花指令的长度,即 每条花指令长度为 4字节,一共 n条, 再调用 ret指令 跳过这些花指令。
#ifdef __arm64__
getpc();
// x16 = x16 + 8 + 4*n, 8是下面两条指令的长度和,4*n 是 n条花指令的长度和。
asm volatile("add x16,x16,0x3c\n”
"mov x30,x16\n"
"ret\n");
复制代码
4.对于armv7, v7s系列:
直接将 pc指令的值赋值给 lr, 然后lr 加上 4 + n * 4 , 其中 4 是
#else
asm volatile(
"mov lr,pc\n"
"add lr,0x34\n"
"mov pc,lr\n"
);
#endif
复制代码
完整示例:
CHDeclareClass(NSURL);
CHMethod1(NSURL *, NSURL, initFileURLWithPath, NSString *, arg1){
#ifdef __arm64__
getpc();
asm volatile("add x16,x16,0x3c\n"
"mov x30,x16\n"
"ret\n");
#else
asm volatile(
"mov lr,pc\n"
"add lr,0x34\n"
"mov pc,lr\n"
);
#endif
asm volatile(
".long 0x0ffbcfa4\n"
".long 0xc89c684a\n"
".long 0xc65a557c\n"
".long 0xfe0772d9\n"
".long 0x3e23ad4d\n”
".long 0x3d8329ff\n"
".long 0xd2193731\n"
".long 0x4e7d2760\n"
".long 0x0e79de99\n"
".long 0xf4d1efaf\n”
".long 0xa82158dd\n"
".long 0x33198ce6\n"
);
if (arg1 != nil) {
return CHSuper1(NSURL, initFileURLWithPath, arg1);
} else {
return nil;
}
}
__attribute__((naked)) void getpc(void) {
#ifdef __arm64__
asm volatile ("sub sp,sp,0x10\n"
"stp x29,x30,[sp]\n"
"mov x0,%0\n"
"add x0,x0,40\n"
"br x0\n"
".long 0x1234dfae\n"
".long 0x1234dfae\n"
".long 0x1234dfae\n"
"ldp x29,x30,[sp]\n"
"mov x16,x30\n"
"add sp,sp,0x10\n"
"ret\n"
:
:"r"(&getpc)
:"x0");
#endif
}
复制代码