美文网首页
iOS-逆向12-MachO文件

iOS-逆向12-MachO文件

作者: 一亩三分甜 | 来源:发表于2021-05-05 18:53 被阅读0次

《iOS底层原理文章汇总》
上一篇文章iOS-逆向11-代码注入得知,要想动态注入,必须要修改MachO文件,通过工具yololib使其中能增加一行自定义的动态库的路径,才能动态注入自己的代码,从而达到hook的目的,MachO文件的结构是什么样的呢?

图片.png
图片.png

1.MachO文件

Mach-O其实是Mach Object文件格式的缩写,是mac以及iOS上可执行文件的格式, 类似于windows上的PE格式 (Portable Executable ), linux上的elf格式 (Executable and Linking Format)

2.MachO文件格式

Mach-O为Mach object文件格式的缩写,它是一种用于可执行文件、目标代码、动态库的文件格式。作为a.out格式的替代,Mach-O提供了更强的扩展性。
属于MachO格式的常见文件
目标文件.o
库文件
.a
.dylib
Framework
可执行文件
dyld
.dsym
File指令
通过 $file 文件路径 查看文件类型

3.目标文件.o

I.单个c文件通过clang(llvm的前端)编译为.o文件

  • 打开Xcode->Cmd+N新建test.c文件,编写main函数


    图片.png
#include <stdio.h>
int main(){
    printf("test\n");
    return 0;
}
  • 通过clang -o test.c生成test.o文件,通过file指令查看test.o的文件结构属于Mach-O文件,架构为x86-64位处理器


    图片.png
  • 再次执行clang test.o将.o文件编译为可执行文a.out,是可执行文件executable,不再是object文件


    image
  • 也可以通过clang -o test2 test.c一次性将test.c编译生成可执行文件
    也可以通过clang -o test3 test.o将.o文件编译生成可执行文件
    a.out、test2、test3属于同一个文件,哈希值相等只是文件名不相同,改后缀名后哈希值仍然相等


    image

    源文件到可执行文件的中间产物是.o文件

II.项目中会存在多个.c文件,两个.c文件,test.c和test1.c文件,test.c中会调用test1.c中的方法

执行clang -o demo test1.c test.c
./demo输入
test
test1

//  test.c
#include <stdio.h>
void test1();
int main(){
    printf("test\n");
    test1();
    return 0;
}
//  test1.c
#include <stdio.h>
void test1(){
    printf("test1\n");
}
图片.png
执行clang -c test1.c test.c生成.o文件,执行clang -o demo1 test.o test1.o生成demo1可执行文件
但两次文件不一样,因为编译链接顺序发生变化,一次test1.c在前,一次test1.c在前,生成的可执行文件哈希值不相同
图片.png
通过objdump --macho -d demo2查看可执行文件顺序,发现demo2(和demo相同)与demo1的文件顺序不一致,准确的说是text段不一致,demo2中_main函数在前,_test1函数在后,demo中_main函数在后,_test1函数在前
image
demo2如下
image
demo如下
image
demo1如下
image
相当于Xcode工程Build Phases目录下的Compile Sources的文件顺序,文件顺序不一致,编译生成的二进制文件排列不一致
图片.png

4.库文件

I.以.a文件结尾的动态库静态库文件,查找.a文件,find /usr -name "*.a"

发现libpython3.9.a是动态库可执行文件


image

发现libx264.a、libSDL2.a、libfdk-aac.a是静态库可执行文件


image

II.以.dylib结尾的dylib也是MachO文件

图片.png

III.dyld动态链接器文件,系统内核触发dyld

image

IV.dsym文件,App打包时生成,edit schemes中修改为release模式下,build编译,App包统计目录下生成Demo.app.dSYM,若遇到崩溃根据堆栈信息,要用此符号文件进行排查分析拿到方法名称

图片.png
图片.png

Demo.app.dSYM也是一个包,右键显示包内容,有一个Demo的MachO文件


图片.png
image

5.MachO文件架构

MachO-Type类型,Build Settings中查看,生成的文件类型


图片.png

iOS11.0以上的系统只支持arm64架构,32位的架构在11.0的系统安装不了了,无法适配
若将DeploymentInfo改为支持iOS9.0以上,则会出现armv7和arm64架构


image
若要添加支持的系统架构,可在Build Settings中Architectures添加架构类型如armv7s,armv7s支持iPhone5和iPhone5c
image
图片.png

6.通用二进制文件(Universal binary)

苹果公司提出的一种程序代码。能同时适用多种架构的二进制文件
同一个程序包中同时为多种架构提供最理想的性能。
因为需要储存多种代码,通用二进制应用程序通常比单一平台二进制的程序要大。
但是 由于两种架构有共通的非执行资源(代码以外的),所以并不会达到单一版本的两倍之多。
而且由于执行中只调用一部分代码,运行起来也不需要额外的内存。

支持armv7s、armv7和arm64文件架构的二进制文件是通用二进制文件


图片.png

当用hopper打开Demo可执行文件时,会提示是Fat archive,表示是通用二进制文件,选择一种,hopper会分析选择的其中一种


image
图片.png
  • lipo命令
    使用lifo -info 可以查看MachO文件包含的架构
    lipo -info MachO文件 使用lifo –thin 拆分某种架构lipo MachO文件 –thin 架构 –output 输出文件路径
    使用lipo -create 合并多种架构
    $lipo -create MachO1 MachO2 -output 输出文件路径
image

7.MachO文件结构

image

Mach-O 的组成结构如图所示包括了
Header 包含该二进制文件的一般信息
字节顺序、架构类型、加载指令的数量等。
使得可以快速确认一些信息,比如当前文件用于32位还是64位,对应的处理器是什么、文件类型是什么
Load commands 一张包含很多内容的表
内容包括区域的位置、符号表、动态符号表等。
Data 通常是对象文件中最大的部分
包含Segement的具体数据

  • 通用二进制文件会有多个上述图中的结构,armv7一个,arm64一个,armv7s一个
  • 可通过otool查看MachO中的数据,otool指令如下
Usage: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/otool [-arch arch_type] [-fahlLDtdorSTMRIHGvVcXmqQjCP] [-mcpu=arg] [--version] <object file> ...
    -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
    -D print shared library id name
    -t print the text section (disassemble with -v)
    -x print all text sections (disassemble with -v)
    -p <routine name>  start dissassemble from routine name
    -s <segname> <sectname> print contents of section
    -d print the data section
    -o print the Objective-C segment
    -r print the relocation entries
    -S print the table of contents of a library (obsolete)
    -T print the table of contents of a dynamic shared library (obsolete)
    -M print the module table of a dynamic shared library (obsolete)
    -R print the reference table of a dynamic shared library (obsolete)
    -I print the indirect symbol table
    -H print the two-level hints table (obsolete)
    -G print the data in code table
    -v print verbosely (symbolically) when possible
    -V print disassembled operands symbolically
    -c print argument strings of a core file
    -X print no leading addresses or headers
    -m don't use archive(member) syntax
    -B force Thumb disassembly (ARM objects only)
    -q use llvm's disassembler (the default)
    -Q use otool(1)'s disassembler
    -mcpu=arg use `arg' as the cpu for disassembly
    -j print opcode bytes
    -P print the info plist section as strings
    -C print linker optimization hints
    --version print the version of /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/otool
image

otool -f Demo,查看MachO文件头信息,Demo是通用二进制文件支持三种架构


image

8.MachOView查看MachO文件

Fat Binary中有三种不同的架构armv7,armv7s,arm64
首先是Fat Header,cputype=12表示ARM架构CPU_TYPE_ARM,
cpusubtype=9(小端模式00000009)表示CPU_SUBTYPE_ARM_V7
cpusubtype=11(小端模式0000000B)表示CPU_SUBTYPE_ARM_V7S
cpusubtype=0(小端模式00000000)表示CPU_SUBTYPE_ARM64_ALL


image
image

每种架构的偏移地址Offset和Size相加后会有间隔,是因为分页的原因,iOS中每页的大小为16k,MacOS中每页大小为4K


图片.png
从Load Commands开始一直到底都是DATA数据段
DATA数据段中Section分为两部分,TEXT和DATA
image
类名和方法名会有联系,工具classdump会dump出类的名称和方法的列表
image
Load Commands中能看到加载哪些库
图片.png

64位环境中PAGEZERO占用4G的空间0xffffffff,后面的所有指令都从0xffffffff00000001开始,目的是和32位指令隔开,插入PAGEZERO后和32位指令不会有重叠,这是PAGEZERO的目的,64位和32位做区分,在内存中执行时和32位完全隔离,是一个空区域分割区,让内存地址加上0xffffffff=4294967296,所有的数据往后移,和32位架构的指令不重复,如果有数据指向PAGEZERO为空,里面是不放数据的
早期的架构armv7和armv7s的PAGEZERO为16384

64位大小的地址
0x12345678a2345678
32位大小的地址
0x12345678
0xffffffff=4G 
image

9.MachO Header

  • Header的数据结构,可在loader.h文件中查看


    图片.png
    image

    filetype文件类型


    图片.png
    image

10.Load Commands

image

DATA部分由三部分组成,SECTION TEXT代码段,SECTION DATA数据段,LINKEDIT,指明起始位置,偏移位置


image

ASLR,操作系统为每一个进程分配随机的ASLR,
应用程序加载进内存中时,实际地址=ASLR+Rebase Info Size,在MachO指定后,方便应用程序
加载进内存后调用,编译时期生成的是偏移地址Rebase Info
Offset,表示在整个MachO文件中偏移多少,程序在第一次加载进内存中时根据ASLR+Rebase Info Offset


image

汇编跳转bl,在编译时期生成的是偏移地址,在文件中偏移多少,运行时期的地址每次都变化,重定向改变的是汇编代码


image
image

重定向改变的是汇编代码,地址前的0x1表示PAGEZERO


image
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对外开放的函数
图片.png
image

每一段数据以页为单位


图片.png
Load Commands和Section之间会有空间,之前动态注入修改成功是因为有空间,才能插入一条
图片.png
Size of load Commands + 2720 = 0002E734和S
ection64 Text段的地址00032374中间有一段地址隔开,故动态注入时能插入一条新的内容在Load Commands的最底部,若没有空间则无法插入
image
图片.png
image
上篇文章动态注入时,我们看到WeChat可执行文件自己的动态库andromedo的路径@rpath/andromeda.framework/andromeda,@rpath路径在Load Command中已经指明为@executable_path/Frameworks,才能找到动态库andromedo
image
image
image

11.DATA数据段

Load Commands中已经指明了DATA数据段包括三部分内容


image

TEXT段可以通过工具objdump --macho -d Demo查看到


image
图片.png
0x1000065a0都指向开头
图片.png
image

Symbol Stubs和Assembly结合起来做符号绑定


image
外部符号表:调用外部函数,只有在运行那一刻,才能找到
启动时刻就绑定了,应用程序一启动,外部函数和符号表进行绑定
Lazy Symbol Pointers中的函数做绑定时会调用Non-Lazy Symbol Pointers的dyld_stub_binder做绑定,绑定符号的目的,将外部函数的真实地址告诉MachO文件,方便调用,先绑定专门用来绑定的函数,之后用此函数去绑定所有的函数
图片.png
调用Non-Lazy Symbol Pointers中的dyld_stub_binder去绑定
image
image

相关文章

  • iOS-逆向12-MachO文件

    《iOS底层原理文章汇总》[https://www.jianshu.com/p/15af435341ce]上一篇文...

  • 12-MachO文件

    前言 本篇文章主要分析MachO文件(也称作二进制可执行文件),相信大家在平时开发中都会碰到MachO文件这个概念...

  • ssm

    工程目录结构 mybatis逆向工程 逆向工程配置文件 generatorConfig.xml文件 逆向工程代码 ...

  • iOS-逆向

    一.常识 白苹果:越狱失败的产物,再开机的时候会一直停留在白色的开机界面 iOS系统有两个用户:一个root,一个...

  • ssm

    mybatis逆向工程 逆向工程配置文件 generatorConfig.xml文件 逆向工程代码 测试类(可以在...

  • iOS逆向学习

    参考文章:iOS逆向开发记录:iOS逆向之手机越狱iOS逆向之介绍iOS逆向之文件系统结构iOS逆向之文件权限及类...

  • RN 更新目录,报错

    解决方法: 将 ios-> build -> ModuleCache.noindex 目录下的文件删除

  • iOS开发--.PCH文件创建

    .pch文件 创建.pch文件方便定义全局的宏和头文件导入 1.Command+N,打开新建文件窗口:iOS->O...

  • iOS 添加pch文件的步聚

    1:创建新文件 ios->other->PCH file,创建一个pch文件:“工程名-Prefix.pch”: ...

  • 增加PCH

    1,Command+N,打开新建文件窗口:ios->other->PCH file,创建一个pch文件:“工程名-...

网友评论

      本文标题:iOS-逆向12-MachO文件

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