转自:http://hi.baidu.com/onejw/blog/item/47c91bdd0751c2c68c102940.html
MobileSubstrate介绍
2012年03月19日 星期一 15:14
MobileSubstrate MobileSubstrate 实际上是一个框架,允许第三方的开发者在系统的方法里打一些运行时补丁,扩展一些方法.类似于 Application Enhancer(http://www.unsanity.com/haxies/ape). MobileSubstrate 主要有3部分组成. MobileHooker,MobileLoader 和 safe mode. 1 MobileHooker ------------------------------------------------------------------------------------------------------------------- MobileHooker 用于替换覆盖系统的方法,这个过程被称为Hooking(挂钩). 将使用到2个API: IMP MSHookMessage(Class class, SEL selector, IMP replacement, const char* prefix); // prefix should be NULL. void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP *result); void MSHookFunction(void* function, void* replacement, void** p_original); MSHookMessage() 在Objective-C中替换implementation。[class Selector] 通过替换 并返回原来的执行。挂钩一个类的方法, 在MSHookemessage(EX)中调用Objc_getMetaClass得到提供的元数据和类检索,例如下面的注释。这种动态替换是Objective-c的一个功能. 使用method_setImplementation。MSHookMmessage()是线程不安全的,不赞成使用,赞成MSHookMessageEx() MSHookFunction() 很像 MSHookMessage() 但是 适合于c/c++ 的函数。MSHookFunctin() 将写入指令调入指定替换函数,并接会分配一些字节在内存地址,相当于原始切出指令并且跳入原始的挂钩方法。 由于iPhone系统默认的内存页不能同时写和执行,一个内核补丁必须申请MSHookFunction() 工作. 截止MobileSubstrate的最新版本,MSHookMessage() 也需要一个内核补丁 调用关闭的挂钩的所有正确方法。 代码示例: 使用 MSHookfunction: static void (*original_CFShow)(CFTypeRef obj); // a function pointer to store the original CFShow(). void replaced_CFShow(CFTypeRef obj) { // our replacement of CFShow(). printf("Calling original CFShow(%p)...", obj); original_CFShow(obj); // calls the original CFShow. printf(" done.\n"); } ... // hook CFShow to our own implementation. MSHookFunction(CFShow, replaced_CFShow, &original_CFShow); // From now on any call to CFShow will pass through replaced_CFShow first. ... CFShow(CFSTR("test")); 使用 MSHookMessageEX: static IMP original_UIView_setFrame_; void replaced_UIView_setFrame_(UIView* self, SEL _cmd, CGRect frame) { // Note the implicit self and _cmd parameters are needed explicitly here. CGRect originalFrame = self.frame; NSLog("Changing frame of %p from %@ to %@", self, NSStringFromCGRect(originalFrame), NSStringFromCGRect(frame)); original_UIView_setFrame_(self, _cmd, frame); // Remember to pass self and _cmd. } ... MSHookMessageEx([UIView class], @selector(setFrame:), (IMP)replaced_UIView_setFrame_,(IMP *)&original_UIView_setFrame_); ... myView.frame = CGRectMake(0, 0, 100, 100); 注意,如果你挂钩一个类的方法,有必须放一个元类在类参数中。 MSHookMessageEx(objc_getMetaClass("UIView"), @selector(commitAnimations), replaced_UIView_commitAnimations, (IMP *)&original_UIView_commitAnimations); 2 MobileLoader ------------------------------------------------------------------------------------------------------------------- MobileLoader 加载第三方补丁代码在运行的应用程序中。 MobileLoader 先加载它自己在运行的应用程序中时使用DYLD_INSERT_LIBRARIES 环境变量。然后查看所有动态库在目录/Library/MobileSubstrate/DynamicLibraries/ 并且 Dlopen 他们(Dlopen是供用户直接访问(存取)动态链接库的一类函数中的一个). 一个扩展将要使用构造函数代码去完成一些工作. ... // The attribute forces this function to be called on load. __attribute__((constructor)) static void initialize() { NSLog(@"MyExt: Loaded"); MSHookFunction(CFShow, replaced_CFShow, &original_CFShow); } 开发者可能添加 过滤器 来限制延期应该加载或者不是。Filters are implemented as plist that lives beside the dylib(这句话不知怎样理解),如果 dylib 的名字时 foo.dylib,那么过滤器的名字应该是 foo.plist. 过滤器应该是一个字典key过滤器。这个另一种词典,包含这些Key: 1) CoreFoundationVersion(array): The extension is loaded only if the version ofCoreFoundation.framework is above the specified values. Currently, only the first 2 values are checked. Firmware
2.0
2.1
2.2
3.0
3.1
3.2 CF version
478.23
478.26
478.29
478.47
478.52
478.61 2)Bundles(array): 该扩展仅仅加载 运行的应用程序列表中相匹配的ID. 3)Classes (array): 加载该扩展只有 在运行的应用程序中实现指定Objective-C 类. 4)Executables(array):加载该扩展只有一个可执行文件的名称相匹配的运行程序。。 这是必须的挂钩没有其它的可以识别特征。 例如, 限制扩展只在 SpringBoard,中加载,Plist 的配置: Filter = { Bundles = (com.apple.springboard); }; 你也可以使用此方法来限制扩展只加载到特定应用程序的一个指定的(Bundle)绑定. 例如 UIKit,例如: Filter = { Bundles = (com.apple.UIKit); }; 另外,MobileLoader 也挂钩 nilst() 去提高它的性能。并定义安全模式多种信号处理器。 对于标识的应用程序,由于所有嵌入的环境变量被忽略,开发者的应用程序必须明确的dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib")让MobileLoader 运行. 3 Safe mode ------------------------------------------------------------------------------------------------------------------- 当一个扩展在SpringBoard崩溃, MobileLoader 会进入设备的安全模式捕捉并且处理。在安全模式下,所有的第三放扩展将失效. 下列信号将调用的安全模式: 1)SIGTRAP 2)SIGABRT 3)SIGILL 4)SIGBUS 5)SIGSEGV 6)SIGSYS 这是我第一次翻译英文技术文档,我承认我的英语很菜,翻译完后,我还云里雾里,不知该怎样使用... --! 有什么不对的地方请指出,谢谢! 原文地址:http://iphonedevwiki.net/index.php/MobileSubstrate |