IOS逆向学习之命令行工具

1. main函数

  • 命令行工具的本质:Mach-O类型的可执行文件,其实跟App内部的可执行文件差不多,区别的是App有界面,有附带的资源文件,但是命令行工具是没有
  • 首先我们创建一个IOS平台的app项目,如下:在这里插入图片描述

但是如果我们需要编写一个命令行工具, 我们不需要界面 , 我们可以修改main函数的实现,直接返回0,这样就不会创建AppDelegate类和相关界面
在这里插入图片描述

然后我们直接编译, 在Product文件加下生成一个app,我们showFinder,然后显示包内容,就可以看到一个app的可执行文件, 也就是我们需要的命令行工具:在这里插入图片描述

找到对应的命令行工具,然后通过iFunBox工具安装到手机的/usr/bin目录下:在这里插入图片描述

然后我们通过SSH来连接手机,在终端输入指令看看:在这里插入图片描述

第一次执行该命令行工具的时候,可能没有权限,我们需要赋予执行权限

  • chmod +x: 赋予某个文件执行权限

  • 注意:

    • 为什么要用Xcode创建一个IOS项目?
      • 因为使用Xcode帮我们创建项目, Xcode会自动帮我们配置该命令行工具的架构信息证书签名(由于本人使用个人账号签名,所以该命令行工具是有期限,只有7天时间),一些等等信息,这样命令行工具才能再我们的IOS系统跑起来

2. 功能分析

2.1 Mach-O的头文件分析

  • 假设我们编写的命令行工具能读取别的app的应用

我们通过MachOView查看app的Mach-O文件,可以发现app文件的架构是在头部信息的前四个字节来表示的:在这里插入图片描述

我们还可以查看xnu的源码:在这里插入图片描述
在这里插入图片描述

  • 注意:有两个值是大小端的问题,根据机器的不同读取方式可能不同

2.2 编写代码读取Mach-O文件类型信息

  • 所以这里我们可以读取app的可执行文件前4个字节,来确定app的可执行文件的架构信息,那么我如何读取app的可执行文件信息, 假如我们现在知道某个app的可执行文件路径,那么我们如何读取?
    • 通过NSData来读取,[NSData dataWithContentsOfFile:neteasemusicPath];,但是这个方法不太好,因NSData需要把整个可执行文件载进内存,但是我们只需要读取前4个字节,如果整个文件比较大,那就比较费时了
    • NSFileHandle:专门处理文件,一点一点的读取文件,我们可以使用这个类来读取文件
#import <UIKit/UIKit.h>
#import<mach-o/fat.h>
#import <mach-o/loader.h>

int main(int argc, char * argv[]) {
    
    //手机上网易云app的路径
    NSString *neteasemusicPath = @"/var/containers/Bundle/Application/9F846BAA-F5F1-4C26-B886-210458BCE8CC/neteasemusic.app/neteasemusic";
    
    NSFileHandle *fileHanlde = [NSFileHandle fileHandleForReadingAtPath:neteasemusicPath];
    
    NSLog(@"fileHanlde======%@",fileHanlde);
    
    //首先获取头部文件长度(通过xnu的源码我们可知magic 是uint32_t类型数据)
    int length = sizeof(uint32_t);
    
    //读取最前面的4个字节(magic number: 用来标记文件类型)
    NSData *data = [fileHanlde readDataOfLength:length];
    
    //得到文件类型
    uint32_t magicNumber;
    [data getBytes:&magicNumber length:length];
    
    //判断文件类型(由于大端和小端的原因需要比较两个)
    if (magicNumber == FAT_MAGIC || magicNumber == FAT_CIGAM) {
        printf("FAT文件\n");
    } else if (magicNumber == MH_MAGIC || magicNumber == MH_CIGAM) {
        printf("非64bit架构文件\n");
    }else if (magicNumber == MH_MAGIC_64 || magicNumber == MH_CIGAM_64) {
        printf("64bit架构文件\n");
    } else {
        printf("读取失败\n");
    }
    
    printf("magicNumber = 0x%x \n",magicNumber);
    
    //关闭
    [fileHanlde closeFile];
    
    return 0;
}

2.3 终端的输入参数

  • argc : 参数个数
  • argv: 存放参数的数组
  • argv[0]: 是存放当前可执行文件的路径
    在这里插入图片描述
    在我们不配置参数的情况下,默认有一个参数, 当前可执行文件的路径:
    在这里插入图片描述

我们可以设置根据终端设置的参数不一样,执行不同的代码:

 //判断终端输入参数
    if (argc == 1) {
        //表示没有输入参数
        printf("-l 产看Mach-o信息\n");
        return 0;
    }
    
    //strcmp() : c语言中比较两个字符串是否相等 等于0 就是相等  不等0则不相等
    if (strcmp(argv[1], "-l") != 0) {
        //表示输入指令不正确
        printf("-l 产看Mach-o信息\n");
        return 0;
    }
    

在这里插入图片描述

2.4 可执行文件权限

读取别的app的可执行文件,我们上面是读取正常, 但是如果发生文件读取失败,可能是你编写的可执行文件没有权限读访问别的app。我们知道每个app都有沙盒的概念,那么我们让我们编写的命令行工具,具有访问别人app的权限了。

我们需要给我们的可执行文件签名(给可执行文件签上一定的权限,让可执行文件可以访问其它App的可执行文件),签名的方式目前有两种:codesignldid

  • entitlements:表示权限

但是codesign比较麻烦,这里采用ldid来签名, ldid在我们安装theos的时候已经安装了。

2.4.1 ldid导出权限

  • 查看ldid的指令:在这里插入图片描述

  • 查看可执行文件权限:ldid -e xxxx(可执行文件路径) > xxxx.entitlements(权限文件路径)

    • 权限文件: entitlementsplistxml这三种后缀都是可以的,但是最好还是以entitlements为后缀
    • >: 表示直接覆盖这个文件
    • >>:表示追加到文件的尾部
    • 看个人需要是追加还是覆盖

在这里插入图片描述

2.4.2 签权限

我们如何给可执行文件签一个很高的权限,让其可以访问其它APP, 我们可以找一个权限很高的app,导出其权限,在把该权限签给我们自己的可执行文件。下面我们以SpringBoard为例

  • SpringBoard可执行文件所在路径:在这里插入图片描述

  • 首先我们需要导出SpringBoard的权限(ldid -e SpringBoard > SpringBoard.entitlements):在这里插入图片描述

然后我们把Springboard的权限签给自己的可执行文件,然后再导出自己的可执行文件权限比对,看看是否签入成功ldid -SSpringBoard.entitlements GYAppTools(把SpringBoard的权限签给GYAppTools)ldid -e GYAppTools > GYAppTools.entitlements(导出GYAppTools的权限)
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值