我们知道Windows下的文件都是PE文件,同样在OS X和iOS中可执行文件是Mach-o
格式的。
所以我们如果要进行逆向分析,首先要熟悉Mach-o
文件结构。
Mach-o
包含三个基本区域:
- 头部(header structure)
- 加载命令(load command)
- 段(segment)。可以拥有多个`段(segment),每个段可以拥有零个或多个区域(section)。每一个段(segment)都拥有一段虚拟地址映射到进程的地址空间。
- 链接信息。一个完整的用户级Mach-o文件的末端是链接信息。其中包含了动态加载器用来链接可执行文件或者依赖库所需使用的符号表,字符串表等等。
你也可以在这里找到Mach-o的官方资料。
一、我们先使用otool工具来查看Mach-o的头部,看看都包含哪些信息。
头部的的结构如下(32位):
struct mach_header {
uint32_t magic ;
cpu_type_t cputype ;
cpu_subtype_t cpusubtype ;
uint32_t filetype ;
uint32_t ncmds ;
uint32_t sizeofcmds ;
uint32_t flags ;
}
-
magic
,是mach-o文件的魔数,0xfeedface代表的是32位,0xfeedfacf代表64位 -
cputype
和cupsubtype
代表的是cpu的类型和其子类型,例子中分别是c和9,定义如下:
#define CPU_TYPE_ARM((cpu_type_t) 12)
#define CPU_SUBTYPE_ARM_V7((cpu_subtype_t) 9
即为:armv7
-
filetype
,2,代表可执行的文件
#defineMH_EXECUTE 0×2
-
ncmds
指的是加载命令(load commands)的数量,例子中一共23个,编号0-22 -
sizeofcmds
表示23个load commands的总字节大小, load commands区域是紧接着header区域的。 -
flags
,例子中是0×00200085,可以按文档分析之。
当然不用工具,直接使用UE看也是一样的。按照定义的结构来就行了。
二、头部之后就是加载命令。加载命令的数目以及总的大小在header
中已经给出。
-
cmd
是load command
的类型,本文中值=1就是LC_SEGMENT
,,LC_SEGMENT
的含义是(将文件中的段映射到进程地址空间) -
cmdsize
代表load command的大小(0×58个字节)。 -
segname
16字节的段名字,当前是__PAGEZERO。 -
vmaddr
段的虚拟内存起始地址 -
vmsize
段的虚拟内存大小 -
fileoff
段在文件中的偏移量 -
filesize
段在文件中的大小 -
maxprot
段页面所需要的最高内存保护(4=r,2=w,1=x) -
initprot
段页面初始的内存保护 -
nsects
段中包含section的数量 -
flags
其他杂项标志位
三、接下来就是 section了:
结构如下:
struct section {
char sectname [ 16 ] ;
char segname [ 16 ] ;
uint32_t addr ;
uint32_t size ;
uint32_t offset ;
uint32_t align ;
uint32_t reloff ;
uint32_t nreloc ;
uint32_t flags ;
uint32_t reserved1 ;
uint32_t reserved2 ;
} ;
-
sectname
第一个是__text ,就是主程序代码 -
segname
该section所属的 segment名,第一个是__TEXT -
addr
该section在内存的启始位置,0xa588。 -
size
该section的大小,0x84a -
offset
该section的文件偏移,28116 0x6dd4 -
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.
结构中的最后2项保留用。
段的命名规则是两个下划线紧跟着大写字母(如__TEXT
),而section的命名则是两个下划线紧跟着小写字母(__text
)。
下面列出段中可能包含的section:
__TEXT段:
__text, __cstring, __picsymbol_stub, __symbol_stub, __const, __litera14, __litera18;
__DATA段
__data, __la_symbol_ptr, __nl_symbol_ptr, __dyld, __const, __mod_init_func, __mod_term_func, __bss, __commom;
__IMPORT段
__jump_table, __pointers;
其中__TEXT
段中的__text
是实际上的代码部分;__DATA
段的__data
是实际的初始数据。
绝大多数mach-o包括以下三个段(支持用户自定义Segment,但是很少使用):
-
__TEXT
代码段,只读,包括函数,和只读的字符串__TEXT
,__text
的都是代码段 -
__DATA
数据段,读写,包括可读写的全局变量等,__DATA
,__data
都是数据段 -
__LINKEDIT
__LINKEDIT
包含了方法和变量的元数据(位置,偏移量),以及代码签名等信息。
可以通过otool –s
查看某segment
的某个section
。
可以通过otool –t
直接查看代码段(__TEXT
)的反汇编代码:
其它的大家参考官方文档就行了。
相关文章
网友评论