天天看点

IOS逆向学习之命令行工具1. main函数2. 功能分析

IOS逆向学习之命令行工具

  • 1. main函数
  • 2. 功能分析
    • 2.1 Mach-O的头文件分析
    • 2.2 编写代码读取Mach-O文件类型信息
    • 2.3 终端的输入参数
    • 2.4 可执行文件权限
      • 2.4.1 ldid导出权限
      • 2.4.2 签权限

1. main函数

  • 命令行工具的本质:Mach-O类型的可执行文件,其实跟App内部的可执行文件差不多,区别的是App有界面,有附带的资源文件,但是命令行工具是没有
  • 首先我们创建一个IOS平台的app项目,如下:
    IOS逆向学习之命令行工具1. main函数2. 功能分析

但是如果我们需要编写一个命令行工具, 我们不需要界面 , 我们可以修改

main

函数的实现,直接返回0,这样就不会创建

AppDelegate

类和相关界面

IOS逆向学习之命令行工具1. main函数2. 功能分析

然后我们直接编译, 在

Product

文件加下生成一个app,我们

showFinder

,然后显示包内容,就可以看到一个app的可执行文件, 也就是我们需要的命令行工具:

IOS逆向学习之命令行工具1. main函数2. 功能分析

找到对应的命令行工具,然后通过

iFunBox

工具安装到手机的

/usr/bin

目录下:

IOS逆向学习之命令行工具1. main函数2. 功能分析

然后我们通过

SSH

来连接手机,在终端输入指令看看:

IOS逆向学习之命令行工具1. main函数2. 功能分析

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

  • chmod +x

    : 赋予某个文件执行权限
  • 注意:
    • 为什么要用Xcode创建一个IOS项目?
      • 因为使用Xcode帮我们创建项目, Xcode会自动帮我们配置该命令行工具的

        架构信息

        证书签名(由于本人使用个人账号签名,所以该命令行工具是有期限,只有7天时间)

        ,一些等等信息,这样命令行工具才能再我们的IOS系统跑起来

2. 功能分析

2.1 Mach-O的头文件分析

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

我们通过

MachOView

查看app的Mach-O文件,可以发现app文件的架构是在头部信息的前四个字节来表示的:

IOS逆向学习之命令行工具1. main函数2. 功能分析

我们还可以查看

xnu

的源码:

IOS逆向学习之命令行工具1. main函数2. 功能分析
IOS逆向学习之命令行工具1. main函数2. 功能分析
  • 注意:有两个值是大小端的问题,根据机器的不同读取方式可能不同

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]

    : 是存放当前可执行文件的路径
    IOS逆向学习之命令行工具1. main函数2. 功能分析
    在我们不配置参数的情况下,默认有一个参数, 当前可执行文件的路径:
    IOS逆向学习之命令行工具1. main函数2. 功能分析

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

//判断终端输入参数
    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;
    }
    
           
IOS逆向学习之命令行工具1. main函数2. 功能分析

2.4 可执行文件权限

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

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

codesign

ldid

  • entitlements

    :表示权限

但是

codesign

比较麻烦,这里采用

ldid

来签名,

ldid

在我们安装

theos

的时候已经安装了。

2.4.1 ldid导出权限

  • 查看

    ldid

    的指令:
    IOS逆向学习之命令行工具1. main函数2. 功能分析
  • 查看可执行文件权限:

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

    • 权限文件:

      entitlements

      plist

      xml

      这三种后缀都是可以的,但是最好还是以

      entitlements

      为后缀
    • >

      : 表示直接覆盖这个文件
    • >>

      :表示追加到文件的尾部
    • 看个人需要是追加还是覆盖
IOS逆向学习之命令行工具1. main函数2. 功能分析

2.4.2 签权限

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

SpringBoard

为例

  • SpringBoard

    可执行文件所在路径:
    IOS逆向学习之命令行工具1. main函数2. 功能分析
  • 首先我们需要导出

    SpringBoard

    的权限(

    ldid -e SpringBoard > SpringBoard.entitlements

    ):
    IOS逆向学习之命令行工具1. main函数2. 功能分析

然后我们把

Springboard

的权限签给自己的可执行文件,然后再导出自己的可执行文件权限比对,看看是否签入成功

ldid -SSpringBoard.entitlements GYAppTools(把SpringBoard的权限签给GYAppTools)

ldid -e GYAppTools > GYAppTools.entitlements(导出GYAppTools的权限)

IOS逆向学习之命令行工具1. main函数2. 功能分析