CydiaSubstrate的简单使用
CydiaSubstrate
CydiaSubstrate 是绝大部分tweak正常工作的基础,主要分为三部分:MobileHooker,CydiaSubstrate,Safe mode
MobileHooker
MobileHooker的作用是替换系统函数(即hook)
// 作用于OC函数,可直接替换掉方法
void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP *result);
(Logos语法对此函数进行了封装,但底层实现完全基于MSHookMessageEx)
// 作用于C , C++
void MSHookFunction(void* function, void* replacement, void** original);
(通过编写汇编指令,在进程执行到function时转而执行replacement,同时保存function的指令返回其地址,可选择性的执行function,并保证进程能够执行完replacement后继续正常执行)
ps:之前hook必须进行越狱才能操作,现在直接汇编就能实现hookrepalce替换进程—>下表进程由上向下执行进程
正常执行的进程1 勾住函数A替换为函数B的进程2 ☟Instructions ☟Instructions ☟FunctionA ☟FunctionB (FunctionA暂存) ☟Instructions ☟Instructions 进程先执行一些指令,在原本应该执行的函数A的地方跳转到了函数B的位置执行函数B,同时函数A的 代码被MobielHooker暂时保存了下来。在函数B中,可以选择是否执行函数A,在函数B执行完成 后,则会继续执行剩下的指令。(ps:MSHookFunction的指令长度是有限制的,至少为8字节,如 果要hook住那些段函数该怎么办?—->一种变通的方法是hook住短函数内部调用的其他函数—- 短函数之所以短,是因为内部一般都是调用了其他函数,由其他函数来做出实际操作。因此,把长度 符合要求的其他函数作为MSHookFunction的目标,然后在replacement里做一些逻辑判断,将它 与函数关联上,再把对应的短函数的修改写在这里)
MobileLoader
MobileLoader的作用是加载第三方dylib。在iOS启动时,会由launched将MobileLoader载入内存,然后MobileLoader会根据dylib的同名plist文件指定的作用范围,有选择的在不同进程里通过dlopen函数打开目录/Library/MobileSubstrate/DynamicLibraries/下的所有dylib.
Safe mode
应用的质量良莠不齐,程序崩溃再说难免,因为tweak的本质是dylib,寄生在别的进程里,一旦出错,可能导致整个进程崩溃,而一旦崩溃的是SpringBoard等系统进程,则会造成iOS瘫痪,所以CydiaSubstrate引入了Safe mode,它会补获SIGTRAP、SIGTBRT、SIGILL、SIGBUS、SIGSEGV、SIGSYS这六种信号,然后进入安全模式。
(ps:在安全模式里,所有基于CydiaSubstrate的第三方dylib会被禁用,便于查找于修复;如果设备因为dylib的原因无法进入系统,比如,开机一直卡在白苹果上,或者进度圈不停地转—>home+lock+然后音量上键禁用CydiaSubstrate,系统重启后再查错与排修,修复后重启iOS,CydiaSubstrate会自动重启)
demo1核心代码
// MSFindSymbol的作用--->查找待hook的symbol,函数的指令被放在内存中,当进程需要执行这个函数时,它必须要知道去内存的哪个地方找到这个函数,然后执行它的指令,也就是说
// 进程要根据函数名,找到它在内存中的地址,而这个名称与地址的映射关系,是存储在"symbol table"中的-----"symbol table" 中的symbol就是这个函数的名称,进程会根据这个
// symbol找到它在内存中的地址.然后跳转过去执行.#import <substrate.h>void (*old_ZN8CPPClass11CPPFuctionEPKc)(void *, const char *);void new__ZN8CPPClass11CPPFunctionEPKc(void *hiddenThis, const char *arg0)
{if (strcmp(arg0,"this is a short C function!") == 0) old_ZN8CPPClass11CPPFuctionEPKc(hiddenThis,"this is a hijacked short C function form new__ZN8CPPClass11CPPFunctionEPKc!");else old_ZN8CPPClass11CPPFuctionEPKc(hiddenThis,"this is a hijacked c++ function");
}void (*old_CFunction)(const char *);void new_CFunction(const char *arg0)
{old_CFunction("this is a hijacked C function!"); // call the original CFunction
}void (*old_ShortCFuntion)(const char *);void new_ShortCFunction(const char *arg0)
{old_ShortCFuntion("this is a hijacked short C function form new_ShortCFunction!"); // call the original ShortCFunction
}%ctor{@autoreleasepool{MSImageRef image = MSGetImageByName("/Application/iostargetapphhly.app/iostargetapphhly");void *__ZN8CPPClass11CPPFunctionEPKc = MSFindSymbol(image,"__ZN8CPPClass11CPPFunctionEPKc");if (__ZN8CPPClass11CPPFunctionEPKc) NSLog(@"iosre : found cppfunction!");MSHookFunction((void *)__ZN8CPPClass11CPPFunctionEPKc, (void *)&new__ZN8CPPClass11CPPFunctionEPKc, (void **)&old_ZN8CPPClass11CPPFuctionEPKc);void *_CFunction = MSFindSymbol(image,"_CFunction");if (_CFunction) NSLog(@"iosre:found CFunction");MSHookFunction((void *)_CFunction, (void *)&new_CFunction, (void **)&old_CFunction);void *_ShortCFunction = MSFindSymbol(image, "_ShortCFunction");if (_ShortCFunction) NSLog(@"iosre: found ShortCFunction");MSHookFunction((void *)_ShortCFunction, (void *)&new_ShortCFunction, (void **)&old_ShortCFuntion); // This MSHookFunction will fail because ShortCFunction is too short to be hooked}
}
demo2核心代码
//
// RootViewController.cpp
// ssd
//
// Created by esirnus on 16/5/23.
// Copyright © 2016年 esirnus. All rights reserved.
//#import "RootViewController.h"class CPPClass
{
public:void CPPFunction(const char *);
};void CPPClass::CPPFunction(const char *args0)
{for (int i = 0; i < 66; i++) // 这个循环可以有足够长的时间来验证 MSHookFunction{u_int32_t randomNumber;if (i % 3 == 0) randomNumber = arc4random_uniform(i);NSProcessInfo *processInfo = [NSProcessInfo processInfo];NSString *hostName = processInfo.hostName;int pid = processInfo.processIdentifier;NSString *globallyUniqueString = processInfo.globallyUniqueString;NSString *processName = processInfo.processName;NSArray *junks = @[hostName,globallyUniqueString,processName];NSString *junk = @"";for (int j = 0; j < pid; j++){if (pid % 6 == 0) junk = junks[j % 3];}if (i % 68 == 1) NSLog(@"Junk: %@",junk);}NSLog(@"HHLY: CPPFunction:%s",args0);
}extern "C" void CFunction(const char *args0)
{for (int i = 0; i < 66; i++){u_int32_t randomNumber;if (i % 3 == 0) randomNumber = arc4random_uniform(i);NSProcessInfo *processInfo = [NSProcessInfo processInfo];NSString *hostName = processInfo.hostName;int pid = processInfo.processIdentifier;NSString *globallyUniqueString = processInfo.globallyUniqueString;NSString *processName = processInfo.processName;NSArray *junks = @[hostName,globallyUniqueString,processName];NSString *junk = @"";for (int j = 0; j < pid; j++){if (pid % 6 == 0) junk = junks[j % 3];}if (i % 68 == 1) NSLog(@"Junk: %@",junk);}NSLog(@"HHLY: CFunction:%s",args0);
}extern "C" void shortCFunction(const char *args0) // shortCFunction is too short to be hooked
{CPPClass cppclass;cppclass.CPPFunction(args0);
}@implementation RootViewController- (void)loadView {self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];// self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];self.view.backgroundColor = [UIColor redColor];
}- (void)viewDidLoad
{[super viewDidLoad];CPPClass cppclass;cppclass.CPPFunction("this is cpp function");CFunction("this is c function");shortCFunction("this is a short C function");
}@end
Demo说明
Demo—>iostargetapphhly目的:验证MSHookFunction对Function的指令总长度有限制
- 说明:针对MobileHooker的使用,CPPClass::CPPFunction,一个CFunction和一个ShortCFunction,作为hook的对象,CPPClass::CPPFunction和CFunction的目的是为了增加这两个函数的长度,使得针对它们俩的MSHookFunction生效,而ShortCFunction会因长度太短,导致针对它的MSHookFunction失效
Demo—>hhlydemoioshookertweak目的:间接hook短函数
对函数(ShortCFunction)直接hook失败了,而对短函数内部调用的其他函数hook是有效的,可通过判断参数,检测它的调用者是ShortCFunction,这样既可实现间接hook短函数
MSHookFunction的指令长度是有限制的,至少为8字节,如果要hook住那些段函数该怎么办?—->一种变通的方法是hook住短函数内部调用的其他函数—-短函数之所以短,是因为内部一般都是调用了其他函数,由其他函数来做出实际操作。因此,把长度符合要求的其他函数作为MSHookFunction的目标,然后在replacement里做一些逻辑判断,将它与函数关联上,再把对应的短函数的修改写在这里)