fishhook
fishhook是如何通過字符串找到符號表的呢?
先來看看如何通過符號找到字符串:

image.png

image.png
可以看到懶加載符號表的順序和間接符號表(undefine)的順序是一樣的,這個間接符號表和symbols是有關(guān)聯(lián)的,比如NSLog在間接符號表的data 為0x000000CC十進制為204,這個204就是符號表中的角標,如下圖:

image.png
在圖中可以看到,在字符表中的偏移量為0xCE,我們在看看String table中的偏移的0xce是什么(即0x11378+0xce=0x11446),如圖:

image.png
所以fishhook正好和這個過程是相反的。
去符號Strip
去掉符號的作用:安全,減小包體積,優(yōu)化
全局符號 、本地符號
- app : 去掉所有的
- 動態(tài)庫: 保留全局符號
symbols 最下面,本地的保存的imp, 間接符號找樁,所以為0

image.png
去符號 斷點短不住
Strip Style
- 去全局符號
- 去非全局符號
- 去debug符號
Deployment Postprocessing
-
改成YES編譯階段就會脫符號
image.png
編譯
image.png
這個是上線后bitcode恢復(fù)符號用的
image.png
image.png
這里是imp,因為間接符號的調(diào)用是找樁去執(zhí)行的,所以為0,但是本地符號,和全局符號就是imp了

image.png
去掉符號時候都是unnamed_symbol,這里不好分析,所以可以通過restore-symbol重新恢復(fù)符號
./restore-symbol MachO -o NewMachO
image.png

image.png
可以看到符號恢復(fù)了,這里的恢復(fù)建立在runtime基礎(chǔ)上,動態(tài)派發(fā)的必定保留了類名,方法名以及imp之間的關(guān)系,本質(zhì)通過MachO下圖這兩個段重新創(chuàng)建了符號表,但是這個工具c函數(shù)以及swift靜態(tài)調(diào)用的是無法恢復(fù)的

image.png
fishhook防護
這里是一種簡單的防護,也有辦法破解、
首先OC MethodSwizzle 使用系統(tǒng)函數(shù),那么APP利用fishhook hook系統(tǒng)的MethodSwizzle,可以讓他人hook不了
防hook代碼最好在framework中寫,framework中的load比主工程的load先加載,同時也在別人注入的framework之前
弊端:靠運行時,我只要比你早,找到fishhook ,對內(nèi)部的fishhook進行hook,hook +load 然后不執(zhí)行,也可以通過字符串就能定位修改字符串常量,導(dǎo)致防護失效
實例:
+(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中導(dǎo)出,同時將.h拖入public中,給外部用
CF_EXPORT void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
本地使用:
#import <HookFramework/HookFramework.h>
exchangeP(class_getInstanceMethod(self.class, @selector(btnClick2:)),



