目录
相关资料下载链接: https://pan.baidu.com/s/1MKKYtjasGPblXDSWGwjz6w 密码: c3so
一、代码注入
一般修改原始的程序,是利用代码注入的方式,注入代码就会选择利用FrameWork或者Dylib等三方库的方式注入。
-
Framwork注入
- 通过Xcode新建Framwork,将库安装进入APP包
- 通过yololib注入Framwork库路径。命令:$yololib(空格)MachO文件路径(空格)库路径
- 所有的Framwork加载都是由DYLD加载进入内存被执行的
- 注入成功的库路径会写入到MachO文件的LC_LOAD_DYLIB字段中
-
Dylib注入
- 通过Xcode新建Dylib库(注意:Dylib属于MacOS所以需要修改属性)
- 添加Target依赖,让Xcode将自定义Dylib文件打包进入APP包。
- 利用yololib进行注入。
1.1 Framwork注入演示
接着上一篇文章将WeChat重签名安装到了真机上:

项目-->Products-->Show in Finder-->显示包内容-->将WeChat可执行文件拷贝出来-->将WeChat 拖入到MachOView

MachO通过Load Commands告诉dyld需要加载的各种库以及库的位置(@rpath)参考:iOS-开发进阶05:动态库
1.1.1 创建动态库MyHook

1.1.2 添加Inject类

Build项目既可在包内容中看到MyHook添加到WeChat的Frameworks中了

Inject.m中添加如下代码并重新Build、安装到手机
+ (void)load {
NSLog(@"\n\n注入成功!\n\n");
}
现在运行项目Inject.m中的load方法是不能执行的。虽然WeChat的Frameworks中加入了MyHook,但WeChat的MachO中没有MyHook 相关的Load Command。因此需要修改MachO才能让dyld加载MyHook。
1.1.3 修改MachO
yololib:专门用来修改MachO文件的(添加Load Command字段)
修改appSign.sh脚本,最后一行添加修改MachO的命令
./yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/MyHook.framework/MyHook"
拷贝yololib到appSign.sh同级目录-->Command + Shift + K --->Command + R直接安装到真机

可以看到MachO中已经添加了MyHook 相关的Load Command

1.2 Dylib注入演示
新建项目Dylib注入--->安装项目到真机--->拷贝Shell脚本、ipa包、yololib--->Build Phase添加脚本执行命令--->将重签名的包安装到真机上

1.2.1 创建Dylib:MyHooK


1.2.2 修改Base SDK和签名


1.2.3 Copy Files

1.2.4 MyHooK.m添加代码
+ (void)load {
NSLog(@"\n\n注入成功!!!\n\n");
}
1.2.5 编译MyHooK和项目(Dylib注入),将libMyHooK.dylib添加进Frameworks中

1.2.6 修改appSign.sh脚本,最后一行添加修改MachO的命令
./yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/libMyHooK.dylib"
1.2.7 安装项目到真机
Command + Shift + K --->Command + R直接安装到真机(不要先Build再安装不然会导致ibMyHooK.dylib无法添加进Frameworks中)

二、MethodSwizzle
利用OC的Runtime
特性,动态改变SEL
(方法编号)和IMP
(方法实现)的对应关系,达到OC方法调用流程改变的目的。主要用于OC方法
。

多种HOOK方式
-
class_addMethod方式:
利用AddMethod方式,让原始方法可以被调用,不至于因为找不到SEL而崩溃 -
class_replaceMethod方式:
利用class_replaceMethod,直接给原始的方法替换IMP -
method_setImplementation方式:
利用method_setImplementation,直接重新赋值原始的新的IMP
2.1 拿到注册方法
2.1.1 继续使用在上面1.1的WeChat项目,安装WeChat到真机,开启Debug调试

Target:WCAccountLoginControlLogic(控制器)
Action:onFirstViewRegister(注册方法)
2.1.2 添加MethodSwizzle方法
#import <objc/runtime.h>
+ (void)load {
NSLog(@"\n\n注入成功!\n\n");
Class class = objc_getClass("WCAccountLoginControlLogic");
SEL originalSelector = @selector(onFirstViewRegister);
SEL swizzledSelector = @selector(my_register);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
method_exchangeImplementations(originalMethod, swizzledMethod);
}
- (void) my_register {
NSLog(@"my_register");
}
2.2 拿到登录密码
2.2.1 使用class-dump静态分析WeChat可执行文件
- 将class-dump和WeChat可执行文件拷贝到同一目录下

- 执行以下命令
./class-dump -H WeChat -o ./headers/
-
将导出的headers拖入到Sublime Text打开
-
参照2.1.1 拿到登录界面的控制器:WCAccountNewPhoneVerifyViewController 和登录方法:onNext
-
Command + Shift + F 查找@interface WCAccountNewPhoneVerifyViewController
-
双击进入WCAccountNewPhoneVerifyViewController

由于onNext方法没有参数因此是通过控件传递的参数

- 继续搜索可以看到m_textField属性
@interface WCAccountTextFieldItem : WCBaseTextFieldItem
@interface WCBaseTextFieldItem : WCBaseInfoItem
{
WCUITextField *m_textField;
}
@interface WCUITextField : UITextField
使用class-dump只能dump出OC相关的方法,不能dump Swift的方法。并且dump出的也不是头文件,可执行文件中本来也没有头文件,class-dump只是类似头文件形式的格式方便我们查看
- 验证

2.2.2 代码中拿到登录密码
改变MethodSwizzle中交换的方法
- 方法一:class_addMethod
#import <UIKit/UIKit.h>
+ (void)load {
NSLog(@"\n\n注入成功!\n\n");
Class class = objc_getClass("WCAccountNewPhoneVerifyViewController");
SEL originalSelector = @selector(onNext);
SEL swizzledSelector = @selector(my_onNext);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
// VC中没有my_onNext(如果是在分类中操作就没有这个问题)
class_addMethod(class, swizzledSelector, my_onNext, "v@:");
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
method_exchangeImplementations(originalMethod, swizzledMethod);
}
// 新的IMP
void my_onNext(id self, SEL _cmd) {
NSLog(@"my_onNext");
UITextField *pwd = (UITextField *)[[self valueForKey:@"_textFieldPwdItem"] valueForKey:@"m_textField"];
NSLog(@"密码是:%@", pwd.text);
// 调回原来的方法
[self performSelector:@selector(my_onNext)];
}
- 方法二:class_replaceMethod
+ (void)load {
NSLog(@"\n\n注入成功!\n\n");
Class class = objc_getClass("WCAccountNewPhoneVerifyViewController");
old_onNext = class_replaceMethod(class, @selector(onNext), my_onNext, "v@:");
}
// 原来的IMP
IMP (*old_onNext)(id self, SEL _cmd);
// 新的IMP
void my_onNext(id self, SEL _cmd) {
NSLog(@"my_onNext");
UITextField *pwd = (UITextField *)[[self valueForKey:@"_textFieldPwdItem"] valueForKey:@"m_textField"];
NSLog(@"密码是:%@", pwd.text);
// 调回原来的方法
old_onNext(self, _cmd);
}
- 方法三:method_setImplementation
+ (void)load {
NSLog(@"\n\n注入成功!\n\n");
Class class = objc_getClass("WCAccountNewPhoneVerifyViewController");
Method originalMethod = class_getInstanceMethod(class, @selector(onNext));
old_onNext = method_getImplementation(originalMethod);//原始的Method
method_setImplementation(originalMethod, my_onNext);
}
// 原来的IMP
IMP (*old_onNext)(id self, SEL _cmd);
// 新的IMP
void my_onNext(id self, SEL _cmd) {
NSLog(@"my_onNext");
UITextField *pwd = (UITextField *)[[self valueForKey:@"_textFieldPwdItem"] valueForKey:@"m_textField"];
NSLog(@"密码是:%@", pwd.text);
// 调回原来的方法
old_onNext(self, _cmd);
}
推荐使用方法二和方法三,更加安全
三、总结
- 代码注入
- Framework注入、 Dylib注入
- Xcode自动打包进入APP包
- MachO中Load commonds里面需要有LC_LOAD_DYLIB字段
- DYLD会加载我们的动态库!
- 案例:
- 分析思路:
- 动态调试:界面入手
- 静态分析. class-dump: (头文件) 0C的类、方法列表。
- MethodSwizzle (Runtime) -重点! !
-
exchange
函数去交换SEL 与IMP的对应关系(书的目录! ) .- 隐患:回不去了! ! ! (没法调用原来的实现!新方法写在
分类
中就不会出现这个问题) - 解决方法:
- 添加方法列表,解决-过程比较复杂不推荐
-
replace
函数替换IMP
-
getIMP
和setIMP
配合!推荐:逻辑清晰! ! (大部分HOOK框架使用的这个方式! ! )
- 隐患:回不去了! ! ! (没法调用原来的实现!新方法写在
网友评论