fishhook
fishhook是如何通过字符串找到符号表的呢?
先来看看如何通过符号找到字符串:
可以看到懒加载符号表的顺序和间接符号表(undefine)的顺序是一样的,这个间接符号表和symbols是有关联的,比如NSLog在间接符号表的data 为0x000000CC十进制为204,这个204就是符号表中的角标,如下图:
在图中可以看到,在字符表中的偏移量为0xCE,我们在看看String table中的偏移的0xce是什么(即0x11378+0xce=0x11446),如图:
所以fishhook正好和这个过程是相反的。
去符号Strip
去掉符号的作用:安全,减小包体积,优化
全局符号 、本地符号
- app : 去掉所有的
- 动态库: 保留全局符号
symbols 最下面,本地的保存的imp, 间接符号找桩,所以为0
去符号 断点短不住
Strip Style
- 去全局符号
- 去非全局符号
- 去debug符号
Deployment Postprocessing
-
改成YES编译阶段就会脱符号
编译
这个是上线后bitcode恢复符号用的
这里是imp,因为间接符号的调用是找桩去执行的,所以为0,但是本地符号,和全局符号就是imp了
去掉符号时候都是unnamed_symbol,这里不好分析,所以可以通过restore-symbol重新恢复符号
./restore-symbol MachO -o NewMachO
可以看到符号恢复了,这里的恢复建立在runtime基础上,动态派发的必定保留了类名,方法名以及imp之间的关系,本质通过MachO下图这两个段重新创建了符号表,但是这个工具c函数以及swift静态调用的是无法恢复的
fishhook防护
这里是一种简单的防护,也有办法破解、
首先OC MethodSwizzle 使用系统函数,那么APP利用fishhook hook系统的MethodSwizzle,可以让他人hook不了
防hook代码最好在framework中写,framework中的load比主工程的load先加载,同时也在别人注入的framework之前
弊端:靠运行时,我只要比你早,找到fishhook ,对内部的fishhook进行hook,hook +load 然后不执行,也可以通过字符串就能定位修改字符串常量,导致防护失效
实例:
+(void)load
{
//exchange
struct rebinding exchange;
exchange.name = "method_exchangeImplementations";
exchange.replacement = my_exchange;
exchange.replaced = (void *)&exchangeP;
//setIMP
struct rebinding setIMP;
setIMP.name = "method_setImplementation";
setIMP.replacement = my_exchange;
setIMP.replaced = (void *)&setIMP_p;
//getIMP
struct rebinding getIMP;
getIMP.name = "method_getImplementation";
getIMP.replacement = my_exchange;
getIMP.replaced = (void *)&getIMP_p;
struct rebinding bds[] = {exchange,setIMP,getIMP};
rebind_symbols(bds, 3);
}
//指针!这个可以暴露给外接!我自己的工程使用!!
void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
IMP _Nonnull (*setIMP_p)(Method _Nonnull m, IMP _Nonnull imp);
IMP _Nonnull (*getIMP_p)(Method _Nonnull m);
void my_exchange(Method _Nonnull m1, Method _Nonnull m2){
NSLog(@"检测到了HOOK!");
}
给自己工程用,在.h中导出,同时将.h拖入public中,给外部用
CF_EXPORT void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
本地使用:
#import <HookFramework/HookFramework.h>
exchangeP(class_getInstanceMethod(self.class, @selector(btnClick2:)),