MonkeyDev的MonkeyApp模板的開發(fā)
fishhook Hook帶符號的C函數(shù)
XXX.m文件
#include <mach-o/dyld.h>
#include "fishhook/fishhook.h"
/*以_dyld_get_image_name為例,該函數(shù)為獲取當(dāng)前應(yīng)用的二進(jìn)制文件中所有的鏡像完整路徑,配合_dyld_image_count函數(shù)使用*/
static char *(*dyld_get_image_name_old123)(uint32_t index);
char *dyld_get_image_name_mine(uint32_t index);
char *dyld_get_image_name_mine(uint32_t index)
{
char *imageName = dyld_get_image_name_old123(index);
printf("hook到了 \n%s",imageName);
return imageName;
}
CHConstructor{
MSHookFunction((void *)_dyld_get_image_name,(void *)dyld_get_image_name_mine, (void **)&dyld_get_image_name_old123);
struct rebinding bind;//要HOOK系統(tǒng)函數(shù)的函數(shù)名稱
bind.name = "_dyld_get_image_name";
bind.replacement = (void *)dyld_get_image_name_mine;//新的函數(shù)去替換系統(tǒng)的函數(shù)
bind.replaced = (void **)&dyld_get_image_name_old123;//把真正的系統(tǒng)函數(shù)地址保存到dyld_get_image_name_old123
struct rebinding rebs[] = {bind};
rebind_symbols(rebs, 1);
}
Theos開發(fā)
MSHookFunction Hook帶符號的C函數(shù)
XXX.m文件
#include <mach-o/dyld.h>
#import <CydiaSubstrate/CydiaSubstrate.h>
/*以_dyld_get_image_name為例,該函數(shù)為獲取當(dāng)前應(yīng)用的二進(jìn)制文件中所有的鏡像完整路徑,配合_dyld_image_count函數(shù)使用*/
static char *(*dyld_get_image_name_old123)(uint32_t index);
char *dyld_get_image_name_mine(uint32_t index);
char *dyld_get_image_name_mine(uint32_t index)
{
char *imageName = dyld_get_image_name_old123(index);
printf("hook到了 \n%s",imageName);
return imageName;
}
CHConstructor{
MSHookFunction((void *)_dyld_get_image_name,(void *)dyld_get_image_name_mine, (void **)&dyld_get_image_name_old123);
}
MSHookFunction Hook無符號的C函數(shù)
XXX.m文件
#include <mach-o/dyld.h>
#import <CydiaSubstrate/CydiaSubstrate.h>
//偏移量
intptr_t g_slide;
//保存模塊偏移基地址的值
static void _register_func_for_add_image(const struct mach_header *header, intptr_t slide) {
Dl_info image_info;
int result = dladdr(header, &image_info);
if (result == 0) {
NSLog(@"load mach_header failed");
return;
}
//獲取當(dāng)前的可執(zhí)行文件路徑
NSString *execName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleExecutable"];
NSString *execPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingFormat:@"/%@", execName];
if (strcmp([execPath UTF8String], image_info.dli_fname) == 0) {
g_slide = slide;
}
//如果需要獲取可執(zhí)行文件中引入的某一個(gè)模塊(如你加入的XXX.dylib)在內(nèi)存中的偏移量
//則需要判斷image_info.dli_fname中是否h包含字符串XXX.dylib
// NSString *fname = [NSString stringWithUTF8String:image_info.dli_fname];
// if ([fname containsString:@"XXX.dylib"]) {
// g_slide = slide
// }
}
void (*orig_testMethod)(void);
void hook_testMethod(void);
//hook后會(huì)來到這里
void hook_testMethod(void) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"hook了我" message:@"message" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"other", nil];
[alert show];
}
CHConstructor{
//注冊添加鏡像回調(diào),應(yīng)用每加載一個(gè)模塊時(shí)都會(huì)產(chǎn)生一個(gè)回調(diào),此處我們提供這樣一個(gè)回調(diào)函數(shù),以接收每個(gè)模塊的信息
_dyld_register_func_for_add_image(_register_func_for_add_image);
//通過 模塊偏移前的基地址 + ASLR偏移量 找到函數(shù)真正的地址進(jìn)行hook
/*解釋:一個(gè)應(yīng)用的可執(zhí)行文件也屬于一個(gè)模塊,也會(huì)被加載進(jìn)內(nèi)存中,其內(nèi)部引入的所有系統(tǒng)庫或者是第三方庫都會(huì)被加載進(jìn)內(nèi)存中,每個(gè)可執(zhí)行文件或是dylib在IDA/Hopper中打開地址都是從0開始的,注意要正確選擇在IDA/Hopper中打開時(shí)選擇的armv7或arm64架構(gòu)類型,當(dāng)這些模塊被加載進(jìn)內(nèi)存時(shí),這些模塊中的所有方法的地址都會(huì)改變,改變的就是這個(gè)ASLR偏移量,所以我們定位到某個(gè)函數(shù)的地址時(shí),只需找到其在IDA/Hopper中對應(yīng)的地址再加上ASLR偏移量就是該函數(shù)最終真正在內(nèi)存中的地址*/
//這個(gè)0x1000065f0就是testMethod在Hopper中打開時(shí)顯示的地址,注意選擇正確的架構(gòu)
MSHookFunction((void *)(0x1000065f0+g_slide), (void *)hook_testMethod, (void **)&orig_testMethod);
}
如何處理sub_xxx函數(shù)(非越獄環(huán)境)?
如果分析到目標(biāo)sub_xxx函數(shù)之后,可以直接靜態(tài)修改二進(jìn)制文件,用Hopper打開目標(biāo)二進(jìn)制文件,注意選擇正確的架構(gòu),然后定位到調(diào)用sub_xxx函數(shù)的地方(一般是bl sub_xxx這樣的),在要修改的語句上按Alt + A,將當(dāng)前匯編指令修改為nop(nop是arm匯編里的一條空指令,即什么也不做)即可,但這樣只能完全阻止調(diào)用sub_xxx,如果只是需要在sub_xxx函數(shù)中插入一點(diǎn)邏輯,則需另外想辦法,然后Hopper->File->Produce New Executable... 保存為新的二進(jìn)制文件或lib,現(xiàn)在大部分只有arm64,如果還需要armv7的,則將原二進(jìn)制文件以armv7的架構(gòu)打開,找到sub_xxx執(zhí)行上述的操作并保存, 將上面兩個(gè)得到的二進(jìn)制文件合并lipo