简介

Mach-O 组件的主要作用是加载二进制文件,将 mach-o 文件内容以 mmap 的方式加载到内存中,并读取 mach-o headers 来获取 text 段, 符号表, objc 等关键段的地址。

使用方法

加载一个包含 ARM64 架构的 Mach-O

  1. #include <iostream>
  2. #include <iblessing-core/v2/mach-o/mach-o.hpp>
  3. using namespace std;
  4. using namespace iblessing;
  5. int main(int argc, const char * argv[]) {
  6. string filePath = "/Users/soulghost/Desktop/research/ib-sample/ib-sample/iblessing-sample.benchmark";
  7. shared_ptr<MachO> macho = MachO::createFromFile(filePath);
  8. assert(macho->loadSync() == IB_SUCCESS);
  9. return 0;
  10. }

ScannerContext

在调用完 loadSync 并返回 IB_SUCCESS 后,MachO 模块会构建起一个与二进制信息有关的 context,可通过 macho->context 访问,你可以打开 ScannerContext.hpp 来查看:

class ScannerContext {
public:
    // ...
    // fileMemory 是指 mach-o 载入进程后的 fileData 信息
    std::shared_ptr<VirtualMemory> fileMemory;

    // 基于 unicorn 的虚拟内存的挂载点,在 mach-o 初始化时还不可用
    std::shared_ptr<VirtualMemoryV2> readonlyMemory;

    // mach-o 的 string table,在这里提供了基于 index 访问的 API
    std::shared_ptr<StringTable> strtab;

    // mach-o 的 symbol table,同时包含了 dynamic symbol table,通过名称、地址等倒排索引
    // 提供查询能力
    std::shared_ptr<SymbolTable> symtab;

    // objc runtime 模块的挂载点,** 在 mach-o 初始化时还不可用 **
    std::shared_ptr<ObjcRuntime> objcRuntime;
    // ...
};

FileMemory (VirtualMemory)

macho->context->fileMemory (VirtualMemory) 是 iblessing 早期的模块,它最早用于直接在当前进程内模拟 mach-o 的内存,这并不安全,因此大部分 API 已被废弃(目前模拟 mach-o 内存是直接使用 unicorn 提供的虚拟地址空间),因此请不要使用 VirtualMemory 模块的读写 API。目前它仅仅用来记录 mach-o 相关的段信息:

class VirtualMemory {
public:
    // ...
    uint64_t spUpperBound;
    uint64_t spLowerBound;
    uint64_t heapCursor;
    uint64_t heapCopyCursor;

    // mach-o 文件的 data,这里是直接将整个文件 mmap 进来的,mappedFile 永远指向文件起始
    uint8_t *mappedFile;
    // mach-o 文件的 size
    uint64_t mappedSize;

    // vmaddr base, 文件载入虚拟内存的起点,这里用的是 __text 段的 vmaddr - fileoff 得到的
    // 一般是 0x100000000,即从 PAGE_ZERO 之后开始加载
    uint64_t vmaddr_base;

    // symtab、dlsymtab、strtab's vmaddr base on LINKEDIT's vmaddr
    uint64_t linkedit_base;

    // __bss section
    uint64_t vmaddr_bss_start;
    uint64_t vmaddr_bss_end;

    // objc classlist & categorylist 地址
    uint64_t objc_classlist_addr;
    uint64_t objc_classlist_size;
    uint64_t objc_catlist_addr;
    uint64_t objc_catlist_size;

    // 所有段的信息,这里已经按照 offset 正序排列
    std::vector<struct ib_segment_command_64 *> segmentHeaders;
    // dyld_info load_command
    ib_dyld_info_command *dyldinfo;
    // __TEXT,__text load_command
    struct ib_segment_command_64 *textSeg;
    struct ib_section_64 *textSect;

    // ...
};

目前暴露的 API 是基于 iblessing 目前的需求,并未全面透出,如果有需求可以通过 GitHub 或 README 中的联系方式反馈给作者。