iOS逆向之五-MACH-O文件解析

  • Post author:
  • Post category:其他


MachO文件是苹果可执行二进制文件的格式

Load Commands

LC_SEGMENT_64

将可执行文件(64位)映射到进程地址空间

32位系统的是LC_SEGMENT

是加载的主要命令,负责指导内核来设置进程的内存空间

LC_DYLD_INFO_ONLY

动态链接相关信息

LC_SYMTAB

符号表地址

LC_DYSYMTAB

动态符号地址表

LC_LOAD_DYLINKER

加载一个动态链接器,路径“/usr/lib/dyld”

LC_UUID

二进制文件的标识ID,dSYM文件、crash中都存在这个值,确定两个文件是否匹配,分析出对应的崩溃位置

LC_VERSION_MIN_MACOSX

二进制文件要求的最低系统版本,和xcode中配置的target有关

LC_MAIN

设置程序的入口,编译型的语言需要指定入口地址,解释器语言对此没有邀请

LC_SOURCE_VERSION

构建二进制文件使用的源代码版本

LC_FUNCTION_STARTS

定义函数的起始地址表,使我们的调试器很容易看到地址

LC_DATA_IN_CODE

定义在代码段内的非指令数据

segment数据结构

#import <mach-o/loader.h>
 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 */
};
struct segment_command_64 { /* for 64-bit architectures */
	uint32_t	cmd;		/* LC_SEGMENT_64 */
	uint32_t	cmdsize;	/* includes sizeof section_64 structs */
	char		segname[16];	/* segment name */
	uint64_t	vmaddr;		/* memory address of this segment */
	uint64_t	vmsize;		/* memory size of this segment */
	uint64_t	fileoff;	/* file offset of this segment */
	uint64_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 */
};

** 段结构图(代码段__TEXT): ** 
段结构图

段(segment)和节(section)

"__TEXT"代表的是segment,  
“__text”代表的是section  

__PAGEZERO段

一个全用0填充的段,用户抓取空指针引用(非法内存访问)。通常不会占用物理内存

__TEXT段

代码段:只有可执行代码和其他只读数据

	__text		主程序的代码
	__stubs	动态库链接的桩
	__stub_helper	动态库链接的桩的辅助
	__cstring	字符串常量(代码中写固定的字符)立即数(代码中直接写的数字,成为模数)
			常量字符串表的描述信息,通过该信息,可以获取常量字符符号的表地址
	__unwind_info	用于异常处理

__DATA段

用于读取和写入数据的一个段

	__nl_symbol_ptr	非延时导入符号表指针
	_la_symbol_ptr		延时导入符号表指针

__LINKEDIT

包含给动态链接库链接器(ldyd)的原始数据段,包含符号表和字符串表,压缩动态链接信息,以及动态符号表

节的数据结构

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) */
};
struct section_64 { /* for 64-bit architectures */
	char		sectname[16];	/* name of this section */
	char		segname[16];	/* segment this section goes in */
	uint64_t	addr;		/* memory address of this section */
	uint64_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) */
	uint32_t	reserved3;	/* reserved */
};

节结构图(代码段):
节结构图

	char		sectname[16];	/* Section名字 */
	char		segname[16];	/* Section所在的segment的名字 */
	uint32_t	addr;		/* 内存中起始位置 */
	uint32_t	size;		/* Section大小 */
	uint32_t	offset;		/* Section的文件偏移 */
	uint32_t	align;		/* 对其   */
	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) */

__TEXT:__cstring 分析 源代码:

static int PI = 3.1415;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSString* hello = @"hello";
        NSLog(@"%@", hello);
        NSLog(@"Hello, World!!");
        NSLog(@"Hello Hello");
        NSLog(@"Hello Hello");
        NSLog(@"PI = %d", PI);
        int a = 100;
        int b = 200;
        int c = a + b;
        NSLog(@"c = %d", c);
    }
    return 0;
}

对应的_cstring 节内容如下:


cstring 节内容

可以看到所有的字符串保存在一张字符串表中,对应的内容是可以被修改的,运行的时候执行的结果也会变成修改之后的内容。

动态库链接信息

LC_DYLD_INFO_ONLY

数据结构:

struct dyld_info_command {
   uint32_t   cmd;		/* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */
   uint32_t   cmdsize;		/* sizeof(struct dyld_info_command) */

    uint32_t   rebase_off;	/* file offset to rebase info  */
    uint32_t   rebase_size;	/* size of rebase info   */
    
    uint32_t   bind_off;	/* file offset to binding info   */
    uint32_t   bind_size;	/* size of binding info  */
        
    uint32_t   weak_bind_off;	/* file offset to weak binding info   */
    uint32_t   weak_bind_size;  /* size of weak binding info  */
    
    uint32_t   lazy_bind_off;	/* file offset to lazy binding info */
    uint32_t   lazy_bind_size;  /* size of lazy binding infs */

    uint32_t   export_off;	/* file offset to lazy binding info */
    uint32_t   export_size;	/* size of lazy binding infs */
};

REBASE_INFO


REBASE_INFO

** 重定向数据rebase(命令码:高四位、低四位) ** 11:REBASE_OPCODE_SET_TYPE_IMM 高四位0x10表示设置立即数类型 低四0x01位表示立即数类型为指针

22:REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB + 2 重定向到数据段的第2个section


REBASE_INFO Action1

Action 为翻译出来的内容,指向的是数据段的第2个节(Load Commands中的所以) 
REBASE_INFO Action2
具体的内容


REBASE_INFO Action3

NSLog是库中的函数,所以需要重定向,其他的几个函数也是类似的。

Binding Info


Binding Info

绑定数据bind: 进行动态绑定的dyld的函数(dyld_stub_binder)

弱绑定数据 weak_bind

延时绑定 lazy_bind

对于需要从动态库加载的函数符号(_printf)

Export Info

可以使用nm工具查看二进制文件的导出符号 【 nm – display name list (symbol table)】

➜  Debug nm MachOTest 
                 U _NSLog
0000000100001100 d _PI
                 U ___CFConstantStringClassReference
0000000100000000 T __mh_execute_header
0000000100000e40 T _main
                 U _objc_autoreleasePoolPop
                 U _objc_autoreleasePoolPush
                 U _objc_retain
                 U _objc_storeStrong
                 U dyld_stub_binder


Export Info

使用工具查看可以看到导出符号有两个

动态链接库的运行方式

TODO


转载于:https://my.oschina.net/FEEDFACF/blog/1549310