美文网首页
初识Mach-O文件

初识Mach-O文件

作者: wuyukobe | 来源:发表于2022-10-10 21:40 被阅读0次

    前言:本文旨在介绍iOS中的Mach-O文件。

    一、介绍

    Mach-O是一种文件的格式(可执行文件的格式,比如图片的格式是png,可执行文件的格式是Mach-O),是iOS/Mac OS上存储程序以及库的标准格式。

    二、基本结构

    Mach-O文件的基本结构:
    • Header:头部,包含可以执行的CPU架构,比如x86,arm64。
    • Load commands:加载命令,也就是告诉系统如何去处理不同的加载信息。包含文件的组织架构和在虚拟内存中的布局方式。
    • Data:数据,包含Load commands中需要的各个段(segment)的数据,每个Segment的大小都是Page的整数倍。
    Mach-O文件的基本结构

    三、Load Commands

    Load Commands

    从上图可知 Load Commands 主要包含了有多个 Segment 段,每个 Segment 中又包含了多个 Section 段。每一部分都是系统执行指令。可以看到主要包含了以下几个Segment段:

    • __TEXT段:主要包含程序代码和只读的常量,这个段的内容如果是系统动态库的内容,那么所有进程公用。只读可执行。
    • __DATA段:主要包含全局变量和静态变量,这个段的内容每个进程单独进行维护。可读写。
    • __LINKEDIT:主要包含链接器使用的符号和其他的表(比如函数名称、地址等)这个段的内容也是可以多进程公用。只读。

    四、常见的Mach-O文件类型

    1、MH_OBJECT
    • 目标文件(.o)
    • 静态库文件(.a),静态库其实就是N个.o合并在一起
    2、MH_EXECUTE:可执行文件
    • .app/xx
    3、MH_DYLIB:动态库文件
    • .dylib
    • .framework/xx
    4、MH_DYLINKER:动态链接编辑器
    • /usr/lib/dyld
    5、MH_DSYM:存储着二进制文件符号信息的文件
    • .dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩溃信息)

    五、可以查看Mach-O文件的工具

    1、MachOView工具

    MachOView工具可以在Mac平台中查看MachO文件格式信息。

    1.1、MachOView工具下载
    MachOView
    1.2、MachOView工具使用
    • 直接启动MachOView,在状态栏中点击file,打开对应的MachO文件即可。如下图:


    • 打开后效果如下图,可以查看文件中的信息:


    2、Hopper Disassmbler工具

    Hopper Disassmbler 可以加载Mach-O文件,显示汇编代码和OC伪代码。

    2.1、工具下载
    Hopper Disassmbler工具

    Hopper Disassmbler下载地址:https://www.hopperapp.com/download.html?

    2.2、工具使用
    • 直接启动Hopper Disassmbler,在状态栏中点击file,打开对应的MachO文件即可。如下图:


    • 打开后效果如下图,可以查看文件中的信息:


    3、ottol命令可查询Mach-O文件内容

    otool可查询需要的内容:

    比如输入:otool
        -f print the fat headers
        -a print the archive header
        -h print the mach header
        -l print the load commands
        -L print shared libraries used
    

    终端输入:

    otool -h Example
    

    终端输出:

    Example:
    Mach header
          magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
     0xfeedfacf 16777223          3  0x00           2    79       8640 0x00218085
    

    4、size命令可查询Mach-O文件的内存分布

    终端输入:

    size -l -m -x ZUX
    

    终端输出:

    Segment __PAGEZERO: 0x100000000 (zero fill)  (vmaddr 0x0 fileoff 0)
    Segment __TEXT: 0x5c8000 (vmaddr 0x100000000 fileoff 0)
        Section __text: 0x522010 (addr 0x100002cc0 offset 11456)
        Section __stubs: 0xca8 (addr 0x100524cd0 offset 5393616)
        Section __stub_helper: 0x1514 (addr 0x100525978 offset 5396856)
        Section __const: 0x84b8 (addr 0x100526e90 offset 5402256)
        Section __cstring: 0x28aed (addr 0x10052f350 offset 5436240)
        Section __objc_methname: 0x479c3 (addr 0x100557e3d offset 5602877)
        Section __ustring: 0xfc8e (addr 0x10059f800 offset 5896192)
        Section __objc_classname: 0x5ac7 (addr 0x1005af48e offset 5960846)
        Section __objc_methtype: 0x9b08 (addr 0x1005b4f55 offset 5984085)
        Section __gcc_except_tab: 0x6630 (addr 0x1005bea60 offset 6023776)
        Section __entitlements: 0x16e (addr 0x1005c5090 offset 6049936)
        Section __unwind_info: 0x2da8 (addr 0x1005c5200 offset 6050304)
        Section __eh_frame: 0x58 (addr 0x1005c7fa8 offset 6061992)
        total 0x5c532f
    Segment __DATA: 0x134000 (vmaddr 0x1005c8000 fileoff 6062080)
        Section __nl_symbol_ptr: 0x8 (addr 0x1005c8000 offset 6062080)
        Section __got: 0x598 (addr 0x1005c8008 offset 6062088)
        Section __la_symbol_ptr: 0x10e0 (addr 0x1005c85a0 offset 6063520)
        Section __mod_init_func: 0x10 (addr 0x1005c9680 offset 6067840)
        Section __const: 0x7c50 (addr 0x1005c9690 offset 6067856)
        Section __cfstring: 0x22ce0 (addr 0x1005d12e0 offset 6099680)
        Section __objc_classlist: 0x1e90 (addr 0x1005f3fc0 offset 6242240)
        Section __objc_nlclslist: 0x40 (addr 0x1005f5e50 offset 6250064)
        Section __objc_catlist: 0x250 (addr 0x1005f5e90 offset 6250128)
        Section __objc_nlcatlist: 0x78 (addr 0x1005f60e0 offset 6250720)
        Section __objc_protolist: 0x3e0 (addr 0x1005f6158 offset 6250840)
        Section __objc_imageinfo: 0x8 (addr 0x1005f6538 offset 6251832)
        Section __objc_const: 0xc4dc8 (addr 0x1005f6540 offset 6251840)
        Section __objc_selrefs: 0xe008 (addr 0x1006bb308 offset 7058184)
        Section __objc_protorefs: 0xb0 (addr 0x1006c9310 offset 7115536)
        Section __objc_classrefs: 0x1ef0 (addr 0x1006c93c0 offset 7115712)
        Section __objc_superrefs: 0x13c8 (addr 0x1006cb2b0 offset 7123632)
        Section __objc_ivar: 0x5ce0 (addr 0x1006cc678 offset 7128696)
        Section __objc_data: 0x1f730 (addr 0x1006d2358 offset 7152472)
        Section __data: 0x4bf0 (addr 0x1006f1a90 offset 7281296)
        Section __bss: 0x24b8 (addr 0x1006f6680 zerofill)
        Section __common: 0x8d0 (addr 0x1006f8b40 zerofill)
        total 0x131400
    Segment __LINKEDIT: 0x474000 (vmaddr 0x1006fc000 fileoff 7307264)
    total 0x100b70000
    

    六、Dyld 动态链接器

    1、Dyld 动态链接器作用

    App开始启动后,系统首先加载可执行文件(Mach-O文件),然后加载动态链接器Dyld。Dyld是一个专门用来加载动态链接库的库。执行从Dyld开始,Dyld从可执行文件依赖的动态库开始,递归加载所有的依赖动态库链接库。

    2、Load Dylibs 加载动态库

    Dyld会首先读取Mach-O文件的Header和load commonds。然后就知道了这个可执行文件依赖的动态库。例如加载动态库A到内存,接着检查A所依赖的动态库,就这样的递归加载,直到所有的动态库加载完毕。通常一个App所依赖的动态库在100~400个左右,其中大多数都是系统的动态库,它们会被缓存到(共享缓存)dyld share cache,这样读取的效率会很高。

    查看Mach-O文件所依赖的动态库,可以通过MachOView的图形化界面(展开Load Command就能看到),也可以通过命令行otool。

    3、Dyld用于加载以下类型的Mach-O文件:
    • MH_EXECUTE(可执行文件)
    • MH_DYLIB(动态库)
    • MH_BUNDLE(bundle类型的mach-o文件)

    注意:APP的可执行文件、动态库都是由Dyld负责加载的。


    以上是有关Mach-O文件的介绍,欢迎补充和指正。

    相关文章

      网友评论

          本文标题:初识Mach-O文件

          本文链接:https://www.haomeiwen.com/subject/prboartx.html