简介

Mach-O 模块仅仅管理了文件级的加载,此时只是将 Mach-O 文件的内容原封不动的加载到了当前进程的内存中,并将关键信息记录在 macho->fileMemory,Memory 模块则会完成将 Mach-O 加载到基于 unicorn 的虚拟地址空间的过程。此外针对静态库还会进行 relocation fix。

使用方法

Memory 的初始化依赖于 mach-o 模块,因此你需要先创建 mach-o 模块并完成 load,随后再加载内存模块。

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

Memory 模块

memory.hpp 中展示了 memory 模块的核心功能,其中 fileMemory 来自 mach-o,virtualMemory 是基于 unicorn 的虚拟地址空间(它安全的模拟了 mach-o 实际的虚拟地址空间):

  1. class Memory {
  2. public:
  3. // 这个方法用于将已加载的虚拟地址空间拷贝到其他 unicorn 实例,这非常使用,因为你往往会
  4. // 创建自己的 unicorn 实例来进行扫描
  5. ib_return_t copyToUCEngine(uc_engine *uc);
  6. // fileMemory 来自于 mach-o 模块
  7. std::shared_ptr<VirtualMemory> fileMemory;
  8. // mach-o 的虚拟地址空间,详见下面的解释
  9. std::shared_ptr<VirtualMemoryV2> virtualMemory;
  10. };

memory->virtualMemory (VirtualMemoryV2) 是基于 unicorn 划定的一个 12GB 虚拟地址空间 (4GB PAGEZERO + 8GB Heap/Stack),也就是从 0x100000000 ~ 0x300000000 的区域,根据 load commands 逐段映射进 unicorn 虚拟地址空间。

一般而言,用户都会新建一个 unicorn 实例进行扫描,因此需要将 Memory 已加载的内容同步到新的 uc 实例,在这种情况下,你可以调用 copyToUCEngine 来同步 Memory 模块加载的虚拟地址空间,但需要注意的是,这里并不是真正的完整内存拷贝,而是按照同样的规则将 mach-o 模块进行加载和 relocation,因此如果你修改了 Memory 模块的内容,他们是不会被同步的,所以要么使用 Memory 模块提供的 unicorn 实例(通过 virtualMemory->getEngine()),要么就在修改内存前提早创建好 uc 实例,通过 copyToUCEngine 拷贝初始内容,并且在接下来只修改你创建的实例

注意事项

Memory 模块主要扮演的角色是 Mach-O 内存初始化和查询者,如果你需要查询 Mach-O 的文件信息,可以通过 memory->fileMemory 或 macho->context->fileMemory,如果你想读写 Mach-O 虚拟地址空间,请使用 memory->virtualMemory 提供的 read / write API。