美文网首页
MachO文件

MachO文件

作者: superFool | 来源:发表于2021-06-08 08:55 被阅读0次

    MachO文件

    前言

    Mach-O(Mach Object):Mach-O 文件是Mach object文件格式的缩写,它是可执行文件、目标代码、动态库的文件格式

    主要包括:

    • 目标文件.o
    • 库文件
    • .a
    • .dylib
    • Framework
    • 可执行文件
    • dyld
    • .dsym

    可以通过file命令查看文件类型
    下面就来用file简单查看下这些文件

    1. .o 文件
      首先创建一个C文件通过Clang编译可以得到目标文件.o


      1622547092622.png
    1622547134411.png

    通过 clang -c demo.命令编译生成.o目标文件

    1622547224293.png

    通过file命令查看.o文件


    1622547331572.png

    说明.o文件是Mach-O文件类型的 64位(64-bit) object文件 x86_64架构
    使用clang demo.o生成a.out可执行文件

    1622547660467.png

    a.out 是一个可执行文件(executable)

    1. .a 文件 和 Framework
      使用 find ~/ -name "*.a" 命令可以找到家目录下的.a文件
      找到之后查看一下.a
      使用file命令查看.a文件
      1622548473914.png

    输出current ar archive random library这一坨不知道是什么鬼,有知道的大神可以帮忙解释一下

    1. .dylib文件
      使用file命令查看


      1622548728531.png

    4.dyld


    1622549080217.png

    dyld 是一个动态连接器(dynamic linker),包含多个架构的通用二进制文件(universal binary with 3 architectures)

    通用二进制文件

    通用二进制文件是苹果公司提出来的一种程序代码,能同时适用多种架构
    实现同一个程序包为多种架构提供最理想的性能
    因为存在针对多种架构的代码所以比单一架构的包体积大,又因为存在共同的非执行资源(代码以外的),所以比多个单一平台代码包的体积小
    由于每种架构只运行对应架构的代码,所以运行起来时不会占用额外的内存

    指令集
    Armv6、armv7、armv7s、arm64都是arm处理器的指令集,所有指令集原则上都是向下兼容的,如iPhone4S的CPU默认指令集为armv7指令集,但它同时也兼容armv6指令集,只是使用armv6指令集时无法充分发挥其性能,即无法使用armv7指令集中的新特性,同理,iPhone5的处理器标配armv7s指令集,同时也支持armv7指令集,只是无法进行相关的性能优化,从而导致程序的执行效率没那么高。

    需要注意的是iOS模拟器没有运行arm指令集,编译运行的是x86指令集,所以,只有在iOS设备上,才会执行设备对应的arm指令集。

    移动设备默认指令集

    • armv6 : iPhone, iPhone2, iPhone3G
    • armv7(32bit):iPhone3GS, iPhone4, iPhone4S
    • armv7S(32bit):iPhone4/iPhone4s (32位)
    • arm64(64bit):iPhone5s(5s+)
    • x86_64(64bit): 支持非M1Mac电脑的cpu架构(64位模拟器)
    • i386:32位架构模拟器

    iOS11(及以上)系统只支持64位的设备就是5s(及以上)的设备才能安装,Xcode所以选择iOS11及以上系统Archive时生成的包只包含arm64架构,选择iOS10及以下系统打出来的包才有可能包含多个架构
    在Xcode -> build Settings->search "mach"可以选择编译生成的产物


    1622552989804.png

    Mach-O Type

    • Executable:可执行文件
    • Dynamic Library:动态库
    • Static Library:静态库
    • Bundle:Bundle
    • Relocatable Object File:这个不知道是什么鬼

    使用Xcode编译 选择最低支撑iOS11.0系统


    1622553451512.png

    查看编译生成包中的可执行文件


    1622553521769.png

    可以看到编译生成包中的可执行文件只支持arm64架构

    再次选择最低支撑iOS10.0系统


    1622553668749.png

    可以看到编译生成包中的可执行文件变成了通用二进制文件支持arm64、和armv7两种架构

    Xcode中编译架构设置 Build Settings -> Search "architectures" 下的Architecture


    1622553897010.png

    默认最多只支持arm64、armv7,可以修改这个配置支持更多架构
    选择others加上armv7s然后再build


    1622555144857.png

    可以看到可执行文件多了armv7s架构

    Lipo工具

    1. 使用lipo -info 可以查看MachO文件包含的架构 lipo -info MachO名称

      1622555459535.png
    2. 使用lifo –thin 拆分某种架构 lipo MachO文件 –thin 架构 –output 输出文件路径

      1622555576836.png

    3.使用lipo -create 合并多种架构lipo -create MachO1 MachO2 -output 输出文件路径

    1622555764340.png

    MachO文件结构

    1622631734095.png

    如图所示MachO文件包含三个部分:
    1. Header
    header 是MachO的头,其中包含了该MachO文件的一些信息

    • 字节顺序、架构类型、加载指令数量等
    • 通过Header快速确认一些信息,比如32位还是64位,处理器架构,文件类型等

    2. Load commands
    Load commands是一张包含一堆加载指令表

    • 包含加载指令告诉dyld如何加载这个MachO

    3. Data
    Data是MachO中最大的部分

    • 包含Segement的具体数据

    首先用MachOView查看一下Header


    1622636950762.png

    在Xcode里command + shift + o 搜索Loader.h可以找到Header的定义


    1622637106397.png

    Header的具体内容及释义


    1622632746599.png

    使用MachOView查看MachO文件

    2D5CD41B-67A9-43AE-84A3-06B20B829279.jpeg

    其中Load commands各条加载指令的含义如下:

    1. LC_SEGMENT_64:将文件中(32位或者64位)的段映射到进程地址空间中
    2. LC_DYLD_INFO_ONLY:动态连接相关信息
    3. LC_SYMTAB:符号地址
    4. LC_DYSYMTAB:动态符号表地址
    5. LC_LOAD_DYLINKER:使用什么加载,iOS的App使用dyld加载
    6. LC_UUID:文件的UUID
    7. LC_VERSION_MIN_IPHONEOS:最低支持的操作系统版本
    8. LC_SOURCE_VERSION:源代码版本
    9. LC_MAIN:程序主线程的入口地址和栈大小
    10. LC_ENCRYPTION_INFO_64 加密信息
    11. LC_LOAD_DYLIB:依赖库的路径,包含三方库
    12. LC_RPATH:dyld维护一个称为运行路径列表的路径的当前堆栈。当遇到@rpath时,它会被替换为运行路径列表中的每个路径,直到找到可加载的dylib(此项释义是网上摘录的还没弄懂啥意思)
    13. LC_FUNCTION_STARTS:函数起始地址表
    14. LC_DATA_IN_CODE:定义在代码段内的非指令的表
    15. LC_CODE_SIGNATURE:代码签名

    接下来详细看下各个command的内容:
    LC_SEGMENT_64

    1622638513362.png
    • VM Address:运行时加载到内存(虚拟内存)的起始地址(要加上ALSR才是真正的内存地址)
    • VM Size:内存中占用大小
    • File Offset:在文件中的偏移地址
    • File Size:在文件中占用大小
      PS:可以看到_TEXT的File Offset是0,所以MachO文件是以代码段起始的

    LC_DYLD_INFO_ONLY

    1622638704330.png
    • Rebase Info Offset:重定向开始位置的偏移地址
    • Rebase Info Size:需要重定向的内容的大小
    • Binding Info Offset:绑定数据的偏移地址
    • Binding Info Size:绑定数据的大小
    • Weak Binding Info Offset:弱绑定
    • Weak Binding Info Size:
    • Lazy Binding Info Offset:懒绑定(用到的时候再绑定)
    • Lazy Binding Info Size:
    • Export Info Offset:对外开放的函数
    • Export Info Size:

    LC_SYMTAB符号相关(函数名称,函数地址)
    LC_MAIN 逆向找不到切入点的时候经常用到这个,当别人做了防护App启动就闪退时可以断住这个函数再做分析

    使用 otool工具可以查看MachO的信息

    Load commands的下面就是Data
    Data分为_TEXT段(代码段)和_DATA段(数据段)


    1622639877442.png

    其中Section64(__TEXT,__text)是主程序代码
    Section64(__TEXT,__stubs)Section64(__TEXT,__stub_helper)是做符号绑定的
    Section64(__TEXT,__objc_methname)是方法名称
    Section64(__TEXT,__objc_classname)是类名称
    Section64(__TEXT,__objc_methtype)是方法类型

    其他内容后面在用到的时候再补充

    相关文章

      网友评论

          本文标题:MachO文件

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