随着iOS职位的火热,越来越多的人都想成为一名优秀的iOS开发工程师,那么在竞争激烈的时代,应该如何成为一名iOS开发工程师呢?今天让大家了解一下iOS逆向基础Mach-O文件
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这是一个我的iOS交流群:687528266,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!
在学习iOS逆向的过程中,发现在解密可执行文件dumpdecrypted砸壳原理时需要用到Mach-O相关知识,在动态库注入过程中也需要理解Mach-O可执行文件的文件结构,那么有必要系统学习记录Mach-O文件的组成结构。
Mach-O,是Mach object文件格式的缩写,是一种可执行文件、目标代码、共享程序库、动态加载代码和核心dump。是a.out格式的一种替代。Mach-O提供更多的可扩展性和更快的符号表信息存取。Mach-O应用在基于Mach核心的系统上,目前NeXTSTEP、Darwin、Mac OS X(iPhone)都是使用这种可执行文件格式。熟悉Mach-O文件格式,有助于了解苹果底层软件运行机制,更好的掌握dyld加载Mach-O的步骤,为自己动手开发Mach-O相关的加解密工具注入工具打下基础。
Mach-O 没有类似于 XML、YAML、JSON 等诸如此类的特殊格式,它只是一个二进制字节流,被划分为了有意义的数据块。这些块包含元信息,比如,字节顺序、cpu 类型、块的大小,等等,简单期间这里我们仅讨论单架构模型。
典型的 Mach-O 文件包含三个区域:
1.头部 (Header): Mach-O文件的架构 比如Mac的 PPC, PPC64, IA-32, x86-64,ios的arm系列.
2.加载命令(Load commands)描述了文件中数据的具体组织结构,不同的数据类型使用不同的加载命令表示。
3.*原始段数据(Raw segment data):可以拥有多个段(segment),每个段可以拥有零个或多个区域(section).每一个段(segment)都拥有一段虚拟地址映射到进程的地址空间。
注:Mach-O 没有类似于 XML、YAML、JSON 等诸如此类的特殊格式,它只是一个二进制字节流,被划分为了有意义的数据块。这些块包含元信息,比如,字节顺序、cpu 类型、块的大小,等等,简单期间这里我们仅讨论单架构模型。
一.Mach-O头部
与Mach-O文件格式有关的结构体,都可以直接或间接的在”mach-o/loader.h“文件中找到。
针对32位与64位架构的cpu,分别使用了mach_header与mach_header_64结构体来描述Mach-O头部。
mach_header结构体的定义如下:
struct mach_header {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
};
magic字段就是我们常说的魔数(例如通常判断png文件格式,还有快速求平方根的0x5f3759df),加载器通过这个魔数值来判断这是什么样的文件,胖二进制文件的魔数值是0xcafebabe;
cputype:与cpusubtype字段与fat_header结构体中的含义完全相同。
filetype:字段表示Mach-O的具体文件类型。这里主要关注MH_EXECUTE、MH_DYLIB与MH_DYLIB这3个文件格式。
nfat_arch字段是指当前的胖二进制文件包含了多少个不同架构的Mach-O文件;
fat_header后会跟着fat_arch,有多少个不同架构的Mach-O文件,就有多少个
fat_arch,用于说明对应Mach-O文件大小、支持的CPU架构、偏移地址等;
sizeofcmds字段指明了Mach-O文件加载命令(load commands)所占的总字节大小。
flags字段表示文件标志,它是一个含有一组位标志的整数,指明了Mach-O文件的一些标志信息。
我们通过xrun新建一个helloworld文件,构建成可执行文件,通过Mac系统的otool工具(或者MachOView)即可查看mach_header信息,如下图:
二.Load commands 结构
Load commands紧跟在头部之后,这些加载指令清晰地告诉加载器如何处理二进制数据,有些命令是由内核处理的,有些是由动态链接器处理的。在源码中有明显的注释来说明这些是动态连接器处理的。
struct load_command {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */};
struct segment_command { /* for 32-bit architectures */
uint32_t cmd; /* LC_SEGMENT */
uint32_t cmdsize; /* includes sizeof section structs */
char segname[16]; /* segment name */
uint32_t vmaddr; /* memory address of this segment */
uint32_t vmsize; /* memory size of this segment */
uint32_t fileoff; /* file offset of this segment */
uint32_t filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
};
1.cmd 是load command的类型,本文中值=1就是LC_SEGMENT,,LC_SEGMENT的含义是(将文件中的段映射到进程地址空间)
structload_command{
uint32_tcmd;/* type of load command */
uint32_tcmdsize;/* total size of command in bytes */};
2.cmdsize 代表load command的大小(0×58个字节)。
3.segname 16字节的段名字,当前是__PAGEZERO。
4.vmaddr 段的虚拟内存起始地址
5.vmsize 段的虚拟内存大小
6.fileoff 段在文件中的偏移量
7.filesize 段在文件中的大小
8.maxprot 段页面所需要的最高内存保护(4=r,2=w,1=x)
9.initprot 段页面初始的内存保护
10.nsects 段中包含section的数量
11.flags 其他杂项标志位
otool工具即可查看Load command信息,如下图:
三.Segment & Section
这里有个命名的问题,如下图所示,__TEXT代表的是Segment,小写的__text代表 Section
Section的数据结构
当一个段包含多个节区时,节区信息会以数组形式紧随着存储在段加载命令后面。节区使用结构体section表示(64位使用section_64表示),定义如下:
struct section { /* for 32-bit architectures */
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
uint32_t addr; /* memory address of this section */
uint32_t size; /* size in bytes of this section */
uint32_t offset; /* file offset of this section */
uint32_t align; /* section alignment (power of 2) */
uint32_t reloff; /* file offset of relocation entries */
uint32_t nreloc; /* number of relocation entries */
uint32_t flags; /* flags (section type and attributes)*/
uint32_t reserved1; /* reserved (for offset or index) */
uint32_t reserved2; /* reserved (for count or sizeof) */
};
sectname:比如_text、stubs 第一个是__text ,就是主程序代码
segname :该section所属的 segment名,第一个是__TEXT
addr : 该section在内存的起始位置,0xa588
size: 该section的大小,0x84a
offset: 该section的文件偏移
align :字节大小对齐 4
reloff :重定位入口的文件偏移 0
nreloc: 需要重定位的入口数量 0
flags:包含section的type和attributes,S_REGULAR—This section has no particular type. The standard tools create a __TEXT,__text section of this type.
iOS逆向基础Mach-O文件(1)https://www.jianshu.com/p/9ea897aeea7c
iOS逆向基础砸壳原理(2)https://www.jianshu.com/p/f79567470330
iOS逆向基础动态库注入实现过程(3)https://www.jianshu.com/p/98a226226c70
iOS逆向基础Hopper+LLDB调试(4)https://www.jianshu.com/p/ab66c140662b
写有不足的地方,可以联系晓雯的微信。请各位大佬多多指教!!!作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这是一个我的iOS交流群:687528266,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!
网友评论