前言
经过之前的学习,相信你已经能熟练的使用Frida-trace、IDA Pro等逆向工具。不过,仅仅到这肯定是不够的。接下来,学会把你逆向的结果打包成插件并运行,那iOS逆向,你也就真正的入门了。

一、目标
把逆向的结果制作成插件并运行

二、工具

mac系统

Xcode:插件开发工具

已越狱iOS设备:运行deb插件

optool:动态库注入工具,下载地址:optool
MonkeyDev:越狱插件开发集成神器,下载地址:MonkeyDev

三、流程
iOS端的插件按设备分为

越狱插件:扩展名为.deb,类似于安卓的xposed插件

优点:独立于ipa文件,ipa可单独升级(前提是相关的 hook代码逻辑没变)缺点:必须要越狱设备

非越狱插件:扩展名为.dylib或.framework,类似于安卓的so文件

优点:可在非越狱机上运行。由于非越狱机,App自然也就检测不到越狱状态,但仍然可以检测ipa包的完整性缺点:ipa无法单独升级,必须要砸壳,动态库注入,重签名后,才能完成升级操作。注:不管是deb格式、dylib格式还是framework格式,都支持使用c、c++和OC语言进行开发

MonkeyDev,原有iOSOpenDev的升级,非越狱插件开发集成神器!

可以使用Xcode开发CaptainHook Tweak、Logos Tweak 和 Command-line Tool,在越狱机器开发插件,这是原 来iOSOpenDev功能的迁移和改进。
只需拖入一个砸壳应用,自动集成class-dump、restore-symbol、Reveal、Cycript和注入的动态库并重签名安装 到非越狱机器。
支持调试自己编写的动态库和第三方App
支持通过CocoaPods第三方应用集成SDK以及非越狱插件,简单来说就是通过CocoaPods搭建了一个非越狱插件商店。
所以在本教程中,deb插件和dylib插件,主要使用MonkeyDev来完成,安装教程参考官方即可。而framework插件,则直接使用Xcode开发。

deb插件开发

  1. 创建插件工程

启动Xcode后,按如下流程依次点击:

至此,插件已经创建完毕:

2. 编写插件代码

创建完这是MonkeyDev作者写的使用步骤

// Objective-C runtime hooking using CaptainHook:

// 1. declare class using CHDeclareClass()

// 2. load class using CHLoadClass() or CHLoadLateClass() in CHConstructor

// 3. hook method using CHOptimizedMethod()

// 4. register hook using CHHook() in CHConstructor

// 5. (optionally) call old method using CHSuper()

咱按以上步骤编写完的插件代码如下:

#if TARGET_OS_SIMULATOR
#error Do not support the simulator, please use the real iPhone Device.
#endif// 导入常用的UI框架和Foundation框架
#import "AppHelper.h" // 注意,一定要导入这,因为这头文件里有Monkey dev定义的宏
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>// 导入MonkeyDev提供的头文件,这头文件,后边我们创建framework插件时也可使用
#import "CaptainHook/CaptainHook.h"/*定义你需要Hook的类及需要Hook的方法。*/
@interface DetailViewController : NSObject// 需要Hook的实例方法
- (void)loginButtonDidClick:(UIButton *)sender;// 以下两个方法并不存在,在这只是为了演示如何hook多个参数的方法和hook类方法
- (NSString *)loginWithPhone:(NSString *)phone password:(NSString *)pwd;
+ (id)factory:(id)arg1;@endCHDeclareClass(DetailViewController); // 步骤1、申明需要Hook的类/*步骤3、你的勾子函数,Hook函数被调用时,会执行到这CHOptimizedMethod的参数说明第一个参数:固定写死self即可第二个参数:返回值类型,无返回值写void。c语言的类型,直接写对应的类型即可(int,float,double...)。其他类型,直接写id即可,如果你知道具体的类型,也可写具体的类型第三个参数:类名第四个参数:方法名// 方法名有一个参数时第五个参数:第一个入参的类型,和第二个参数写法类型第六个参数:第一个入参的形参名// 方法名有两个参数时第七个参数:第二个入参的类型,和第二个参数写法类型第八个参数:第二个入参的形参名...
*/
CHOptimizedMethod1(self, void, DetailViewController, loginButtonDidClick, UIButton*, sender) {CHSuper1(DetailViewController, loginButtonDidClick, sender);  // 调用原方法NSLog(@"witchan =该方法的入参为:%@", sender);
}// Hook两个入参的实例方法
CHOptimizedMethod2(self, id, DetailViewController, loginWithPhone, NSString *, p, password, NSString*, pwd) {id result = CHSuper2(DetailViewController, loginWithPhone, p, password, pwd); // 调用原方法NSLog(@"witchan =该方法的第一个入参为:%@", p);NSLog(@"witchan =该方法的第二个入参为:%@", pwd);NSLog(@"witchan =该方法的返回值为:%@", result);return result;
}// Hook一个入参的类方法,相对于实例方法,只是在Method前多了个Class单词。其他操作完全一样
CHOptimizedClassMethod1(self, id, DetailViewController, factory, id, arg1) {id result = CHSuper1(DetailViewController, factory, arg1);  // 调用原方法NSLog(@"witchan =该方法的入参为:%@", arg1);NSLog(@"witchan =该方法的返回值为:%@", result);/* 由于deb格式、dylib格式还是framework格式,都支持使用c、c++和OC语言进行开发。以下代码为oc语法的简单示例。注意:整个插件的写法,和ios开发完全一致,你可以创建新类,也可以调用oc提供的类及相关方法如果你不熟悉oc语法,请看我公众号的另一篇文章,iOS快速入门:https://mp.weixin.qq.com/s/g89Sdyqc4ONlyAWtXTCwRA*/NSMutableDictionary *params = [NSMutableDictionary dictionary];params[@"微信公众号"] = @"移动端Android和iOS开发技术分享";params[@"QQ群"] = @"812546729";NSData *body = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];// 调用登录接口NSURL *loginURL = [NSURL URLWithString:@"https://127.0.0.1:9080/login"];    // 接口NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:loginURL]; // 请求对象request.HTTPMethod = @"POST";    // 请求方式[request setValue:@"d83kd9d323" forHTTPHeaderField:@"x-sign"];   // 设置headerrequest.HTTPBody = body;    // 注意,HTTPBody是一个16进制数据,一般直接16进制输出,再转换成文本查看NSURLSession *session = [NSURLSession sharedSession];   // 获取网络对象NSURLSessionTask *task = [session dataTaskWithRequest:requestcompletionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {// 请求结果会调到这if (error != nil) {NSLog(@"witchan =网络请求出错了");} else {NSLog(@"witchan =网络请求成功");}}]; // 创建请求任务[task resume];  // 发起网络请求return result;
}// 入口函数
CHConstructor
{@autoreleasepool{NSLog(@"witchan =FirsDeb hook success!=");    // 一般在入口函数输出一条日志,确定你的插件是否加载成功CHLoadLateClass(DetailViewController);  // 步骤2、加载需要Hook的类CHHook1(DetailViewController, loginButtonDidClick); // 步骤4、注册你需要hook的实例方法CHHook2(DetailViewController, loginWithPhone, password);CHClassHook1(DetailViewController, factory);    // 注册需要hook的类方法}
}

填写目标ipa的包名:

编辑插件扩展信息(可选):

3. 编译插件
编译:依次选择菜单栏的Product → Build

编译后的结果是这样的:

打开目录,就能看到你需要的deb文件了


*安装方式1:**拿到deb文件后,你可以用爱思或ssh工具,把deb文件换过血到手机,再使用Filza工具找到对应的文件,安装即可:


安装方式2: 如果你是mac电脑,那你可使用隔空投送功能来把deb文件传输至手机并安装:



**安装方式3:**是不是觉得上边的安装方式有点麻烦,如果是自己真机调试,那你可以这样玩:

然后依次选择菜单栏的Product → Build或快捷键command+b,这次编译完成后,没有报错。并且你的手机已自动注销了。打开cyida查看你最近安装的deb,就会发现刚编写的插件已经安装成功,简单吧。

在电脑端打开控制台工具:

这时启动被注入deb插件的App后,看到的日志如下:

如果你编辑时,遇到这错误:

An empty identity is not valid when signing a binary for the product type ‘Dynamic Library’.

解决办法:

2.dylib插件使用

在deb插件开发教程中,我们已经同时得到了deb插件和dylib插件,所以在本教程中,则教大家如何把dylib插件注入到ipa,注入工具为optool,该工具主要有两条命令:

注入:optool install -c load -p “@executable_path/Frameworks/aaa.framework/aaa” -t demo.app/demo

卸载:optool uninstall -p “@executable_path/Frameworks/aaa.framework/aaa” -t demo.app/demo

把ipa文件的扩展名改为zip,解压后,得到Payload文件夹:


切换到Payload目录cd Desktop/Payload,然后执行注入命令optool install -c load -p “@executable_path/Frameworks/FirstDeb.dylib” -t ExampleCode.app/ExampleCode,至此,我们的dylib文件已经注入完成:

witchan@witchandeMacBook-Air Payload % optool install -c load -p "@executable_path/Frameworks/FirstDeb.dylib" -t ExampleCode.app/ExampleCode
Found thin header...
Inserting a LC_LOAD_DYLIB command for architecture: arm64
Successfully inserted a LC_LOAD_DYLIB command for arm64
Writing executable to ExampleCode.app/ExampleCode...
witchan@witchandeMacBook-Air Payload %

接下来将Payload文件夹压缩成zip包,然后把扩展名改为ipa,然后用爱思,或其他重签名工具对该ipa进行签名后,即可在越狱或非越狱机上安装使用了。运行后的日志如下:

3.Framework插件开发
1. 创建插件工程

启动Xcode后,按如下流程依次点击:





2. 编写插件代码

创建AppHelper类



创建完成后的目录结构如下:

在这。我们使用之前的deb插件编写方式来写。先把CaptainHook.h文件的所有内容复制到AppHelper.h:

复制整个头文件的内容到AppHelper.h即可。然后把deb插件.m文件的全部代码复制到AppHelper.m,再在.m文件的顶部引入AppHelper.h文件,然后剩下的代码编写方式就和deb的编写完全一样。

最终的AppHelper.h的完整代码如下:

由于该文件较大,在这进行删除,完整代码请看文末。
AppHelper.m的完整代码如下(和deb相比,只多了#import “AppHelper.h”):

#if TARGET_OS_SIMULATOR
#error Do not support the simulator, please use the real iPhone Device.
#endif// 导入常用的UI框架和Foundation框架
#import "AppHelper.h" // 注意,一定要导入这,因为这头文件里有Monkey dev定义的宏
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>// 导入MonkeyDev提供的头文件,这头文件,后边我们创建framework插件时也可使用
#import "CaptainHook/CaptainHook.h"/*定义你需要Hook的类及需要Hook的方法。*/
@interface DetailViewController : NSObject// 需要Hook的实例方法
- (void)loginButtonDidClick:(UIButton *)sender;// 以下两个方法并不存在,在这只是为了演示如何hook多个参数的方法和hook类方法
- (NSString *)loginWithPhone:(NSString *)phone password:(NSString *)pwd;
+ (id)factory:(id)arg1;@endCHDeclareClass(DetailViewController); // 步骤1、申明需要Hook的类/*步骤3、你的勾子函数,Hook函数被调用时,会执行到这CHOptimizedMethod的参数说明第一个参数:固定写死self即可第二个参数:返回值类型,无返回值写void。c语言的类型,直接写对应的类型即可(int,float,double...)。其他类型,直接写id即可,如果你知道具体的类型,也可写具体的类型第三个参数:类名第四个参数:方法名// 方法名有一个参数时第五个参数:第一个入参的类型,和第二个参数写法类型第六个参数:第一个入参的形参名// 方法名有两个参数时第七个参数:第二个入参的类型,和第二个参数写法类型第八个参数:第二个入参的形参名...
*/
CHOptimizedMethod1(self, void, DetailViewController, loginButtonDidClick, UIButton*, sender) {CHSuper1(DetailViewController, loginButtonDidClick, sender);  // 调用原方法NSLog(@"witchan =该方法的入参为:%@", sender);
}// Hook两个入参的实例方法
CHOptimizedMethod2(self, id, DetailViewController, loginWithPhone, NSString *, p, password, NSString*, pwd) {id result = CHSuper2(DetailViewController, loginWithPhone, p, password, pwd); // 调用原方法NSLog(@"witchan =该方法的第一个入参为:%@", p);NSLog(@"witchan =该方法的第二个入参为:%@", pwd);NSLog(@"witchan =该方法的返回值为:%@", result);return result;
}// Hook一个入参的类方法,相对于实例方法,只是在Method前多了个Class单词。其他操作完全一样
CHOptimizedClassMethod1(self, id, DetailViewController, factory, id, arg1) {id result = CHSuper1(DetailViewController, factory, arg1);  // 调用原方法NSLog(@"witchan =该方法的入参为:%@", arg1);NSLog(@"witchan =该方法的返回值为:%@", result);/* 由于deb格式、dylib格式还是framework格式,都支持使用c、c++和OC语言进行开发。以下代码为oc语法的简单示例。注意:整个插件的写法,和ios开发完全一致,你可以创建新类,也可以调用oc提供的类及相关方法如果你不熟悉oc语法,请看我公众号的另一篇文章,iOS快速入门:https://mp.weixin.qq.com/s/g89Sdyqc4ONlyAWtXTCwRA*/NSMutableDictionary *params = [NSMutableDictionary dictionary];params[@"微信公众号"] = @"移动端Android和iOS开发技术分享";params[@"QQ群"] = @"812546729";NSData *body = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];// 调用登录接口NSURL *loginURL = [NSURL URLWithString:@"https://127.0.0.1:9080/login"];    // 接口NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:loginURL]; // 请求对象request.HTTPMethod = @"POST";    // 请求方式[request setValue:@"d83kd9d323" forHTTPHeaderField:@"x-sign"];   // 设置headerrequest.HTTPBody = body;    // 注意,HTTPBody是一个16进制数据,一般直接16进制输出,再转换成文本查看NSURLSession *session = [NSURLSession sharedSession];   // 获取网络对象NSURLSessionTask *task = [session dataTaskWithRequest:requestcompletionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {// 请求结果会调到这if (error != nil) {NSLog(@"witchan =网络请求出错了");} else {NSLog(@"witchan =网络请求成功");}}]; // 创建请求任务[task resume];  // 发起网络请求return result;
}// 入口函数
CHConstructor
{@autoreleasepool{NSLog(@"witchan =FirsFramework hook success!=");    // 一般在入口函数输出一条日志,确定你的插件是否加载成功CHLoadLateClass(DetailViewController);  // 步骤2、加载需要Hook的类CHHook1(DetailViewController, loginButtonDidClick); // 步骤4、注册你需要hook的实例方法CHHook2(DetailViewController, loginWithPhone, password);CHClassHook1(DetailViewController, factory);    // 注册需要hook的类方法}
}

3.编译Framework

然后依次选择菜单栏的Product → Build或快捷键command+b。再选择菜单栏的Product → Show Build Folder in Finder


4.framework插件使用

使用optool工具把framework插件注入到ipa,该工具主要有两条命令:

注入:optool install -c load -p “@executable_path/Frameworks/aaa.framework/aaa” -t demo.app/demo

卸载:optool uninstall -p “@executable_path/Frameworks/aaa.framework/aaa” -t demo.app/demo

把ipa文件的扩展名改为zip,解压后,得到Payload文件夹:


切换到Payload目录cd Desktop/Payload,然后执行注入命令optool install -c load -p “@executable_path/Frameworks/FirstFramework.framework/FirstFramework” -t ExampleCode.app/ExampleCode,至此,我们的framework文件已经注入完成:

witchan@witchandeMacBook-Air Payload % optool install -c load -p "@executable_path/Frameworks/FirstFramework.framework/FirstFramework" -t ExampleCode.app/ExampleCode
Found thin header...
Inserting a LC_LOAD_DYLIB command for architecture: arm64
Successfully inserted a LC_LOAD_DYLIB command for arm64
Writing executable to ExampleCode.app/ExampleCode...
witchan@witchandeMacBook-Air Payload %

接下来将Payload文件夹压缩成zip包,然后把扩展名改为ipa,然后用爱思,或其他重签名工具对该ipa进行签名后,即可在越狱或非越狱机上安装使用了。运行后的日志如下:

总结
以上就是iOS插件相关的教程,希望该文章对你有所帮助。deb格式的叫插件,其实dylib和framework文件,在iOS里,叫动态库。就和安卓的so文件类似。在这之所以都叫插件,是因为市场需要。

【iOS逆向与安全】iOS插件开发入门相关推荐

  1. 【iOS逆向与安全】iOS插件开发光速入门

    前言 经过之前的学习,相信你已经能熟练的使用Frida-trace.IDA Pro等逆向工具.不过,仅仅到这肯定是不够的.接下来,学会把你逆向的结果打包成插件并运行,那iOS逆向,你也就真正的入门了. ...

  2. iOS小技能:逆向的一般思路及入门工具

    文章目录 前言 I 逆向的一般思路 1.1 iOS逆向工程的作用 1.2 iOS逆向的过程 1.3 工具 1.4 iOS的安全措施 II 入门工具 2.1 自己写按键精灵:Simulate touch ...

  3. ios逆向傻瓜入门教程(一)

    1.准备工作: (1)一台越狱手机,并装有以下软件:cycript,openssh (2)下载工具库,内容列表: (3)在越狱手机上,从appstore上,下载WeChat(微信). 2.ssh到手机 ...

  4. ios逆向入门笔记-HOOK-QQ登录

    ios逆向入门笔记-HOOK-QQ登录 选择目标 砸壳 基本调试 Reveal+确定目标action及target 利用Logos 进行 hook 后续 选择目标 在经过之前的配置,这次有点小改动= ...

  5. iOS 逆向 - 收藏集 - 掘金

    分分钟让你在 微信运动 霸占榜首 - iOS - 掘金 为了纪念我失去的已越狱iPad, 不得不写点什么. 所以...以下内容 不需要越狱. 微信运动 6万步是什么概念,我不知道,因为我没走过,不过有 ...

  6. IOS逆向(1)IOS越狱

    前段时间学习完JS逆向后,准备入门IOS逆向了.打算写在博客中记录下学习的过程,也会把踩过的坑记录下来让大家一起交流学习.JS逆向相关的基础网上比比皆是,后续会分享一些关于JS逆向相关的项目,就不从基 ...

  7. iOS 逆向编程(三)实操越狱详细流程

    一.使用 CheckRa1n 越狱 常见越狱工具可以看这篇 iOS 逆向编程(二)越狱入门知识 我的手机是 iPhone 5s 版本为 ios 12.4.6 (推荐先看) 如果嫌麻烦,直接下面有推荐手 ...

  8. iOS逆向(1)——利用ipa重签名,3分钟iPhone安装多个微信

    本文要达成如图效果,在一台iPhone上安装第二个微信: 准备: Xcode 微信ipa(可通过iTool进行下载) 重签名脚本 步骤 打开Xcode,新建Single View App项目,名字可以 ...

  9. android r 编译找不到头文件_「投稿」iOS逆向——砸壳与反编译

    作者:疯狂的蛋神 近来对iOS逆向十分感兴趣,就在业余时间里自己在上网找了各种资料学习,发现许多资料对于一些细节描述的不够详细,所以也踩了很多坑,我也将自己踩的一些坑总结出来,希望对大家有所帮助. 注 ...

最新文章

  1. 【多线程】C++11进行多线程开发 (std::thread)
  2. 【若依(ruoyi)】弹框图标 / layer 图标
  3. 安卓编程用什么软件_震惊!安卓IOS都可以用的牛逼软件
  4. Codeforces Round #245 (Div. 1) E. Points and Segments 欧拉回路 + 建模
  5. (Java)Integer类的其他常用方法
  6. 算法总结之求解模线性方程组
  7. 关于单页面应用一些随想
  8. Desktop imags
  9. error C2864 只有静态常量整型数据成员才可以在类中初始化
  10. java下标和相等的矩阵_39.数组中数值和下标相等的元素
  11. UE4纯蓝图项目接入Steam服务(一)将游戏连接到Steam
  12. box-sizing: border-box的作用
  13. 5 行 Python 代码就能让你的电脑永不息屏!
  14. 心灵捕手~ 鸡汤悄悄话
  15. 开箱-艳云脚本云控系统
  16. win7安装OpenCV:计算机中丢失opencv_world300d.dll
  17. java fxml教程_openjfx(javaFX)完整学习指南(教程)
  18. 递归函数求解阶层(C语言)
  19. 加速度传感器灵敏度的几种表示方式
  20. Windows CMD命令添加开机启动项

热门文章

  1. 魅族MX5真机调试时部分日志丢失
  2. c++下程序的运行(第3方库的安装及安装gdal)
  3. 计算机专业面试知识点整理(计网与操作系统)
  4. 听说你对塞博朋克2077很感兴趣?
  5. java 使用lambda表达式创建线程
  6. 基于 Nacos Config 事件监听 动态调整线程池参数
  7. 乐观不是盲目不是极端自信
  8. word学习-基础排版(标尺+查看标题+显示标记)
  9. php程序定制,PHP定制明信片
  10. js合并两个或多个数组的方法