a3221002 发表于 2022-12-5 15:19:40

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

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

一、目标把逆向的结果制作成插件并运行
二、工具
[*]mac系统
[*]Xcode:插件开发工具
[*]已越狱iOS设备:运行deb插件
[*]optool:动态库注入工具,下载地址:https://github.com/alexzielenski/optool
[*]MonkeyDev:越狱插件开发集成神器,下载地址:https://github.com/AloneMonkey/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后,按如下流程依次点击:https://tva1.sinaimg.cn/large/008vxvgGly1h8nixcpyx3j318k0pkwhm.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8nj2dki89j314k0sw0vv.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8nj3rqtf9j314k0swdj2.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8nj72cyc7j314k0swmzu.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8nja6lixcj31640smact.jpg至此,插件已经创建完毕:https://tva1.sinaimg.cn/large/008vxvgGly1h8njocv90dj31c00u00yp.jpg
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;

@end

CHDeclareClass(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 = ;
    params[@"微信公众号"] = @"移动端Android和iOS开发技术分享";
    params[@"QQ群"] = @"812546729";
   
    NSData *body = ;
   
    // 调用登录接口
    NSURL *loginURL = ;    // 接口
    NSMutableURLRequest *request = ; // 请求对象
    request.HTTPMethod = @"POST";    // 请求方式
    ;   // 设置header
    request.HTTPBody = body;    // 注意,HTTPBody是一个16进制数据,一般直接16进制输出,再转换成文本查看
   
    NSURLSession *session = ;   // 获取网络对象
    NSURLSessionTask *task = [session dataTaskWithRequest:request
                                        completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
      // 请求结果会调到这
      
      if (error != nil) {
            NSLog(@"witchan =网络请求出错了");
      } else {
            NSLog(@"witchan =网络请求成功");
      }
      
    }]; // 创建请求任务
    ;// 发起网络请求
   
    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的包名:https://tva1.sinaimg.cn/large/008vxvgGly1h8nkxmazfzj31c00u0q6i.jpg
编辑插件扩展信息(可选):https://tva1.sinaimg.cn/large/008vxvgGly1h8nktmxrkij31c00u0n0q.jpg3. 编译插件编译:依次选择菜单栏的Product -> Buildhttps://tva1.sinaimg.cn/large/008vxvgGly1h8puu8rr8vj31a80u0n21.jpg编译后的结果是这样的:https://tva1.sinaimg.cn/large/008vxvgGly1h8pv5xn4wpj31970u0wnh.jpg打开目录,就能看到你需要的deb文件了https://tva1.sinaimg.cn/large/008vxvgGly1h8pv7jqso2j313q0noac2.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8pvs5x80jj313m0nwjt5.jpg安装方式1:拿到deb文件后,你可以用爱思或ssh工具,把deb文件换过血到手机,再使用Filza工具找到对应的文件,安装即可:https://tva1.sinaimg.cn/large/008vxvgGly1h8pwce4j9cj315o0u0q64.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8pwmofdbxj30pm19qahx.jpg
安装方式2: 如果你是mac电脑,那你可使用隔空投送功能来把deb文件传输至手机并安装:https://tva1.sinaimg.cn/large/008vxvgGly1h8rz4hjcccj317k0u0wna.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8saksnyd9j31f40o8wi1.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8sasz9bd2j31er0u0qas.jpg
安装方式3:是不是觉得上边的安装方式有点麻烦,如果是自己真机调试,那你可以这样玩:https://tva1.sinaimg.cn/large/008vxvgGly1h8pwt4fqm0j31970u07a3.jpg然后依次选择菜单栏的Product -> Build或快捷键command+b,这次编译完成后,没有报错。并且你的手机已自动注销了。打开cyida查看你最近安装的deb,就会发现刚编写的插件已经安装成功,简单吧。在电脑端打开控制台工具:https://tva1.sinaimg.cn/large/008vxvgGly1h8px0d2tuij307807sq2y.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8px163qsuj31dd0u0wfz.jpg这时启动被注入deb插件的App后,看到的日志如下:https://tva1.sinaimg.cn/large/008vxvgGly1h8px5goeuaj31d80u0tbl.jpg
如果你编辑时,遇到这错误:An empty identity is not valid when signing a binary for the product type 'Dynamic Library'.https://tva1.sinaimg.cn/large/008vxvgGly1h8nl2fqci4j322p0u0aeg.jpg解决办法:https://tva1.sinaimg.cn/large/008vxvgGly1h8nl4snju3j31c00u043v.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8nl77r50wj31c00u0afs.jpg
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文件夹:https://tva1.sinaimg.cn/large/008vxvgGly1h8pxsbdkekj31f40o8jur.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8pxulvynzj31f40o877u.jpg切换到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进行签名后,即可在越狱或非越狱机上安装使用了。运行后的日志如下:https://tva1.sinaimg.cn/large/008vxvgGly1h8py2qcpglj31vg0u0whv.jpg
Framework插件开发
1. 创建插件工程启动Xcode后,按如下流程依次点击:https://tva1.sinaimg.cn/large/008vxvgGly1h8nixcpyx3j318k0pkwhm.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8py7f43vbj314k0swn08.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8py8gyf07j314k0sw76g.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8py9azu0dj31640smgog.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8pyakrpg9j31c00u0gpc.jpg2. 编写插件代码创建AppHelper类https://tva1.sinaimg.cn/large/008vxvgGly1h8pychjf9ij312j0u0tcn.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8pydo1bfdj314k0swwhe.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8pyf03kmwj314k0sw76k.jpg创建完成后的目录结构如下:https://tva1.sinaimg.cn/large/008vxvgGly1h8pyfns4lmj31ec0ocmzr.jpg在这。我们使用之前的deb插件编写方式来写。先把CaptainHook.h文件的所有内容复制到AppHelper.h:https://tva1.sinaimg.cn/large/008vxvgGly1h8pzzlnnnpj31b50u0dlz.jpg复制整个头文件的内容到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;

@end

CHDeclareClass(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 = ;
    params[@"微信公众号"] = @"移动端Android和iOS开发技术分享";
    params[@"QQ群"] = @"812546729";
   
    NSData *body = ;
   
    // 调用登录接口
    NSURL *loginURL = ;    // 接口
    NSMutableURLRequest *request = ; // 请求对象
    request.HTTPMethod = @"POST";    // 请求方式
    ;   // 设置header
    request.HTTPBody = body;    // 注意,HTTPBody是一个16进制数据,一般直接16进制输出,再转换成文本查看
   
    NSURLSession *session = ;   // 获取网络对象
    NSURLSessionTask *task = [session dataTaskWithRequest:request
                                        completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
      // 请求结果会调到这
      
      if (error != nil) {
            NSLog(@"witchan =网络请求出错了");
      } else {
            NSLog(@"witchan =网络请求成功");
      }
      
    }]; // 创建请求任务
    ;// 发起网络请求
   
    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 Finderhttps://tva1.sinaimg.cn/large/008vxvgGly1h8pza3q2kdj31jm0u07a1.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8pzbfjy85j31sg0nyjuv.jpg4.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文件夹:https://tva1.sinaimg.cn/large/008vxvgGly1h8pxsbdkekj31f40o8jur.jpghttps://tva1.sinaimg.cn/large/008vxvgGly1h8pzg3r1laj31f40o842i.jpg切换到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进行签名后,即可在越狱或非越狱机上安装使用了。运行后的日志如下:https://tva1.sinaimg.cn/large/008vxvgGly1h8q05rzslcj31vg0u0gp1.jpg
总结以上就是iOS插件相关的教程,希望该文章对你有所帮助。deb格式的叫插件,其实dylib和framework文件,在iOS里,叫动态库。就和安卓的so文件类似。在这之所以都叫插件,是因为市场需要。本文所涉及到的源码下载链接: https://pan.baidu.com/s/1g8nIfGRejKYBrT2JbNw-ZQ?pwd=munc 提取码: munc


apaog 发表于 2023-12-1 07:56:47

赞一个~{:lol:}
页: [1]
查看完整版本: 【iOS逆向与安全】iOS插件开发光速入门