IOS逆向学习-Mach-o

IOS逆向学习-Mach-o

  • 1. 动态库
    • 1.1 动态库的缓存
    • 1.2 动态库的加载
    • 1.3 拆分`dyld_share_cache_armX(动态库)`文件
  • 2. Mach-O
    • 2.1 查看Mach-O的文件类型
    • 2.2 常见的Mach-O文件类型
    • 2.3 Universal Binary(通用二进制文件)
    • 2.4窥探Mach-O的结构
      • 2.4.1 查看Mach-o文件常用命令
      • 2.4.2 Mach-O结构
      • 2.4.3 Mach-o和dyld

1. 动态库

1.1 动态库的缓存

  • 从IOS3.1开始,为了提高性能,绝大部分的系统动态库文件都打包存放到一个缓存文件夹中(dyld shared cache

  • 缓存文件的路径: /System/Library/Caches/com.apple.dyld/dyld_share_cache_armX(X: 代表ARM处理器指令集架构)
    IOS逆向学习-Mach-o_第1张图片

  • 所有的框架的可执行文件(Mach-o)文件都不在/System/Library/Frameworks/xxxx.framework中,改路径下存放都的都是各个各个framework的一些资源配置文件,可执行文件都合并到一个caches中,这样做的好处是:节省内存

1.2 动态库的加载

  • 在Mac\IOS中,是使用了/usr/lib/dyld程序来加载动态库
  • dyld
    • dynamic link editor: 动态链接编辑器
    • dynamic loader: 动态加载器
  • dyld源码
  • 苹果开源代码地址
  • dyld源码查看过程截图
    IOS逆向学习-Mach-o_第2张图片
    IOS逆向学习-Mach-o_第3张图片

1.3 拆分dyld_share_cache_armX(动态库)文件

  • 网上有些工具可以拆分,但是我们可以使用苹果官方拆分方法
  1. 下载dyld的源码 ,然后找到dsc_extractor.cpp文件,该文件所在路径(源码823.73版本)dyld/shared_cache文件加下dsc_extractor.cpp
  2. 进入当前文件所在目录,然后在终端使用命令编译该文件(本次编译会报错):在这里插入图片描述
  3. 如果编译报错, 我们把该文件的一些代码删除只保留如下部分,然后再编译:在这里插入图片描述
// test program
#include <stdio.h>
#include <stddef.h>
#include <dlfcn.h>


typedef int (*extractor_proc)(const char* shared_cache_file_path, const char* extraction_root_path,
                              void (^progress)(unsigned current, unsigned total));

int main(int argc, const char* argv[])
{
    if ( argc != 3 ) {
        fprintf(stderr, "usage: dsc_extractor  \n");
        return 1;
    }

    //void* handle = dlopen("/Volumes/my/src/dyld/build/Debug/dsc_extractor.bundle", RTLD_LAZY);
    void* handle = dlopen("/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle", RTLD_LAZY);
    if ( handle == NULL ) {
        fprintf(stderr, "dsc_extractor.bundle could not be loaded\n");
        return 1;
    }

    extractor_proc proc = (extractor_proc)dlsym(handle, "dyld_shared_cache_extract_dylibs_progress");
    if ( proc == NULL ) {
        fprintf(stderr, "dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
        return 1;
    }

    int result = (*proc)(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
    fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
    return 0;
}

  1. 变成该文件之后,我们需要在终端执行该文件, 那么你在执行这个文件的时候需要指明路径,然后开始拆分库:./dsc.extractor(可执行键) dyld_shared_cachexx(缓存文件路径) 拆分文件路径/dsc_extractor dyld_shared_cache_arm64 arm64,最后拆分:IOS逆向学习-Mach-o_第4张图片

  2. 拆解完成之后,你可以使用hopper disassemble来分析你想分析的框架

2. Mach-O

2.1 查看Mach-O的文件类型

  • Mach-O是Mach object的缩写,是Mac\iO上用于储存程序、库的标准格式

  • Mach-O格式的文件类型有:
    IOS逆向学习-Mach-o_第5张图片

  • 可以在xnu源码中,查看到Mach-O格式的详细定义源码地址

  • xnu: Mac系统的一些内核源码,先下载xnu的源码(xnu-7195.81.3版本),然后把整个源码拖拽到sublineText工具中,根据下面路径可以查看Mach-o类包含的文件类型

    • EXTEENAL_HEADERS/mach-o/loader.h
      IOS逆向学习-Mach-o_第6张图片

2.2 常见的Mach-O文件类型

我们在在终端,输入命令file xxx查看某个文件的类型
.o文件被称为目标文件:.c 文件 ---(编译)---> .o文件(目标文件)-----(链接)----> 可执行文件(文件的编译过程)

  • MH_OBJECT: 目标文件(.o)、静态库文件(.a),静态库其实就是N个.o合并在一起

    • 示例:我们可以生成一个.文件,然后编译生成.o文件,然后查看文件类型:IOS逆向学习-Mach-o_第7张图片
    • 由上面过程我们可以看出.o文件其实是Mach-O文件类型,可以通过同样的方式查看.a文件的类型
  • MH_EXECUTE:可执行文件IOS逆向学习-Mach-o_第8张图片

  • MH_DYLIB:动态库文件 ;.dyld.framework/xx

  • MH_DYLINKER:动态链接编辑器;/usr/lib/dyld

  • MH_DSYM:存储这二进制文件符号信息的文件,.dSYM.Content/Resources/DWAFR/xx常用于分析APP的崩溃信息

  • find . -name "*.a": 在当前路径下查找后缀名为.a的文件 (. 代表当前路径)
    IOS逆向学习-Mach-o_第9张图片

  • 在Xcode中查看target的Mach-O类型:IOS逆向学习-Mach-o_第10张图片

2.3 Universal Binary(通用二进制文件)

  • 通用二进制文件 :

    • 同时适用于多种架构的二进制文件
    • 包含了多种不同架构的独立二进制文件
  • 因为需要储存多种代码的结构,通用二进制文件通常比单一平台的二进制文件的程序要大

  • 由于两种架构的有共同的一些资源,所以并不会达到单一版本的两倍之多

  • 由于执行过程中,只调用一部分代码,运行起来也不需要额外的内存

  • 因为文件比原来的大,也被称为胖二进制文件(Fat Binary)
    IOS逆向学习-Mach-o_第11张图片

  • $(ARCHS_STANDARD): Xcode内置的环境变量,不同版本的Xcode的值不一样,通过的一些架构值

    • Xcode9中的$(ARCHS_STANDARD)值可能是arm64、armv7
    • Xcode4中的$(ARCHS_STANDARD)值可能是armv7
  • Xcode打包出的二进制(Mach-O类型)文件包含的架构是这两个变量的交集,也就是说两个变量同时支持的架构,打包出来的文件才会支持这个架构

  • 在开发中我们一般不会去修改两个参数,但是比如在开发静态库的时候, 你可以通过设置这两个参数,来设置静态库支持什么架构

  • 如何拆分和合并多个架构的二进制文件:IOS逆向学习-Mach-o_第12张图片
    在这里插入图片描述
    在这里插入图片描述

2.4窥探Mach-O的结构

2.4.1 查看Mach-o文件常用命令

  • 命令行工具:file:查看Mach-O的文件类型file 文件路径
  • otools: 查看Mach-O特定部分和段的内容,苹果自带的工具
  • lipo :常用与查看多架构Mach-O文件的处理
    • 查看架构信息:lipo -info 文件路径
    • 导出某种特定架构:lipo 文件路径 -thin 架构类型(如:arm64) -output 输出文件路径
    • 合并多种架构: lipo -create 文件路径1 文件路劲2 -output 输出文件路径
  • GUI工具:MachOView

2.4.2 Mach-O结构

  • 内存是分段管理的,常见代码段、数据段
  • 一个Mach-O文件主要包括3个主要区域
    • Header: 文件类型、目标架构类型,等
    • Load commands:描述文件在虚拟内存中的逻辑结构、布局(有点类似指针的作用,告诉原始数据存放的一些位置信息)
    • Raw segement data: 在Load commands中定义的Segement的原始数据
      IOS逆向学习-Mach-o_第13张图片

我么只有了解了Mach-O文件的结构,你才可能往里面注入自己的代码,达到修改app的效果

  • 我们可以通过苹果自带的命令 来查看Mach-O的文件的结构信息:
    IOS逆向学习-Mach-o_第14张图片

  • 除了苹果自带的otools命令,我们还可以通过MachOView工具来查看,可以按照上面下载地址下载源码然后运行项目,如果运行项目报SDK错误,我们要修改工程中的SDK版本,选择最新版本,在运行即可:
    IOS逆向学习-Mach-o_第15张图片

2.4.3 Mach-o和dyld

  • dyld:也是Mach-O类型的文件,属于MH_DYLINKER类型(动态连接器),dyld可以加载三种类型的Mach-O类型的文件:
    • MH_EXECUTE: 可执行文件
    • MH_DYLIB:动态库
    • MH_BUNDLE: bundle类型的文件
  • APP的可执行文件、动态库都是由dyld负责加载的,下面我们从源码中查看dyld支持加载的Mach-O类型的文件:IOS逆向学习-Mach-o_第16张图片

你可能感兴趣的:(IOS逆向,ios)