>

之前深入了解过。过去了一年多的时间。如今花些时间好好总结下,毕竟好记性不如烂笔头。

其次另一个目的,对于mach-o文件结构。关于动态载入信息那个数据区中,命令含义没有深刻掰扯清除,希望有同学能够指点下。

摘要:对于mach-o是Mac和iOS能够运行文件的格式。进程就是系统依据该格式将运行文件载入到内存后得到的结果。系统通过解析文件,建立依赖(动态库),初始化运行时环境,才干真正開始运行该App(进程)

Start from Hello World

通过分析以下这个最熟悉的可运行文件。来好好总结和了解下Mach-O这样的文件格式,而且也总结下系统在运行可运行文件几个过程:

+ 解析文件

+ 依赖建立

+ 初始化运行环境

+ 运行进程

代码1.0

#include <stdio.h>
int main( int argc, char *argv[])
{
printf( "Hello World!\n" );
return 0;
}

浏览可运行文件格式

小工具介绍下:烂苹果MachOView。通过改工具能够直接review mach-o可运行文件的几个基本的组成部分:

编译下main.c文件(使用gcc -g main.c)

简单看下可运行文件格式:

简单浏览mach-o可运行文件,详细能够分为几个部分

  • 文件头 mach64 Header
  • 载入命令 Load Commands
  • 文本段 __TEXT
  • 数据段 __TEXT
  • 动态库载入信息 Dynamic Loader Info
  • 入口函数 Function Starts
  • 符号表 Symbol Table
  • 动态库符号表 Dynamic Symbol Table
  • 字符串表 String Table

详细介绍下各个区域的作用。以及载入时系统是怎样使用该可运行文件。

Mach Header - 可运行文件文件头

使用下mac的otool工具

代码3.0

yingfang:mach-o文件结构-src fangying$ otool -h a.out
a.out:
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedfacf 16777223 3 0x80 2 15 1200 0x00200085

上面是mach-o标准的文件头格式。其相关的数据结构在

/*
* The 32-bit mach header appears at the very beginning of the object file for
* 32-bit architectures.
*/
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 */
}; /* Constant for the magic field of the mach_header (32-bit architectures) */
#define MH_MAGIC 0xfeedface /* the mach magic number */
#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */ /*
* The 64-bit mach header appears at the very beginning of object files for
* 64-bit architectures.
*/
struct mach_header_64 {
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 */
uint32_t reserved; /* reserved */
}; /* Constant for the magic field of the mach_header_64 (64-bit architectures) */
#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */

对比命令结果和详细的数据结构,下表介绍各个字段的详细意义:

字段 说明 举例
magic 魔数,系统载入器通过改字段高速,推断该文件是用于32位or64位。

32位-0xfeedface 64位-0xfeedfacf

demo中magic值为0xfeedfacf。表明该文件支持64位
cputype CPU类型以及子类型字段。该字段确保系统能够将适合的二进制文件在当前架构下运行 demo值为0x1000007, 依据#define CPU_TYPE_X86_64 (CPU_TYPE_X86
cpusubtype CPU指定子类型。对于inter。arm。powerpc等CPU架构,其都有各个阶段和等级的CPU芯片。该字段就是详细描写叙述其支持CPU子类型 对于Demo,能够查看
#define CPU_SUBTYPE_X86_ALL ((cpu_subtype_t)3)
#define CPU_SUBTYPE_X86_64_ALL ((cpu_subtype_t)3)
#define CPU_SUBTYPE_X86_ARCH1 ((cpu_subtype_t)4)
#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8)
filetype 说明该mach-o文件类型(可运行文件,库文件。核心转储文件。内核扩展,DYSM文件,动态库)。详细能够看 demo中该值为2,表示该文件为二进制文件
ncmds 说明载入命令条数 demo中表示该文件载入命令条数为15,通过machoview工具。看到也是15条载入命令
sizeofcmds 表示载入命令大小 demo表示该文件载入命令大小为1200字节
flags 标志位,该字段用位表示二进制文件支持的功能,主要是和系统载入,链接相关。详细能够看 demo中值为0x00200085,分别表示三个功能:
1. MH_PRELOAD
2. MH_TWOLEVEL 动态库载入二级名称空间
3. MH_PIE 对可运行文件类型启用地址空间随机布局化
reserved 保留字段

系统解释,先解释文件头,获得文件支持位数(64位 or 32位),获得CPU类型。获得文件类型。获得载入命令条数和大小,获得文件标识。

Load Commands - 载入命令

Mach-O文件包括非常详细的载入指令,这些指令非常清晰地指示载入器怎样设置而且载入二进制数据。Load Commands紧紧跟着二进制文件头。

先使用工具review demo中二进制文件Load Commands

也能够使用otool命令读取二进制文件载入命令:(之前分析bitcode是否支持,也是通过otool -l进行分析的)

代码4.0

yingfang:mach-o文件结构-src fangying$ otool -l a.out
a.out:
Load command 0
cmd LC_SEGMENT_64
cmdsize 72
segname __PAGEZERO
vmaddr 0x0000000000000000
vmsize 0x0000000100000000
fileoff 0
filesize 0
maxprot 0x00000000
initprot 0x00000000
nsects 0
flags 0x0
Load command 1
cmd LC_SEGMENT_64
cmdsize 472
segname __TEXT
vmaddr 0x0000000100000000
vmsize 0x0000000000001000
fileoff 0
filesize 4096
maxprot 0x00000007
initprot 0x00000005
nsects 5
flags 0x0
Section
sectname __text
segname __TEXT
addr 0x0000000100000f50
size 0x0000000000000034
offset 3920
align 2^4 (16)
reloff 0
nreloc 0
flags 0x80000400
reserved1 0
reserved2 0
Section
sectname __stubs
segname __TEXT
addr 0x0000000100000f84
size 0x0000000000000006
offset 3972
align 2^1 (2)
reloff 0
nreloc 0
flags 0x80000408
reserved1 0 (index into indirect symbol table)
reserved2 6 (size of stubs)
Section
sectname __stub_helper
segname __TEXT
addr 0x0000000100000f8c
size 0x000000000000001a
offset 3980
align 2^2 (4)
reloff 0
nreloc 0
flags 0x80000400
reserved1 0
reserved2 0
Section
sectname __cstring
segname __TEXT
addr 0x0000000100000fa6
size 0x000000000000000e
offset 4006
align 2^0 (1)
reloff 0
nreloc 0
flags 0x00000002
reserved1 0
reserved2 0
Section
sectname __unwind_info
segname __TEXT
addr 0x0000000100000fb4
size 0x0000000000000048
offset 4020
align 2^2 (4)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
Load command 2
cmd LC_SEGMENT_64
cmdsize 232
segname __DATA
vmaddr 0x0000000100001000
vmsize 0x0000000000001000
fileoff 4096
filesize 4096
maxprot 0x00000007
initprot 0x00000003
nsects 2
flags 0x0
Section
sectname __nl_symbol_ptr
segname __DATA
addr 0x0000000100001000
size 0x0000000000000010
offset 4096
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000006
reserved1 1 (index into indirect symbol table)
reserved2 0
Section
sectname __la_symbol_ptr
segname __DATA
addr 0x0000000100001010
size 0x0000000000000008
offset 4112
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000007
reserved1 3 (index into indirect symbol table)
reserved2 0
Load command 3
cmd LC_SEGMENT_64
cmdsize 72
segname __LINKEDIT
vmaddr 0x0000000100002000
vmsize 0x0000000000001000
fileoff 8192
filesize 552
maxprot 0x00000007
initprot 0x00000001
nsects 0
flags 0x0
Load command 4
cmd LC_DYLD_INFO_ONLY
cmdsize 48
rebase_off 8192
rebase_size 8
bind_off 8200
bind_size 24
weak_bind_off 0
weak_bind_size 0
lazy_bind_off 8224
lazy_bind_size 16
export_off 8240
export_size 48
Load command 5
cmd LC_SYMTAB
cmdsize 24
symoff 8296
nsyms 12
stroff 8504
strsize 240
Load command 6
cmd LC_DYSYMTAB
cmdsize 80
ilocalsym 0
nlocalsym 8
iextdefsym 8
nextdefsym 2
iundefsym 10
nundefsym 2
tocoff 0
ntoc 0
modtaboff 0
nmodtab 0
extrefsymoff 0
nextrefsyms 0
indirectsymoff 8488
nindirectsyms 4
extreloff 0
nextrel 0
locreloff 0
nlocrel 0
Load command 7
cmd LC_LOAD_DYLINKER
cmdsize 32
name /usr/lib/dyld (offset 12)
Load command 8
cmd LC_UUID
cmdsize 24
uuid A36ECE81-1426-3D1F-928C-62F6CC590A5D
Load command 9
cmd LC_VERSION_MIN_MACOSX
cmdsize 16
version 10.11
sdk 10.11
Load command 10
cmd LC_SOURCE_VERSION
cmdsize 16
version 0.0
Load command 11
cmd LC_MAIN
cmdsize 24
entryoff 3920
stacksize 0
Load command 12
cmd LC_LOAD_DYLIB
cmdsize 56
name /usr/lib/libSystem.B.dylib (offset 24)
time stamp 2 Thu Jan 1 08:00:02 1970
current version 1225.1.1
compatibility version 1.0.0
Load command 13
cmd LC_FUNCTION_STARTS
cmdsize 16
dataoff 8288
datasize 8
Load command 14
cmd LC_DATA_IN_CODE
cmdsize 16
dataoff 8296
datasize 0

从otool展现的载入命令,我们能够分析基本的载入命令(段命令,区命令。段命令中会分为几个区命令)

详细能够看看bsd/kern/mach_loader.c

segname cmd 说明 举例
LC_SEGMENT_64 将文件里(32位或64位)的段映射到进程地址空间中
LC_DYLD_INFO_ONLY
LC_SYMTAB 符号表地址
LC_DYSYMTAB 动态符号表地址
LC_LOAD_DYLINKER 使用何种动态载入库 demo中表明使用/usr/lib/dyld
LC_UUID 文件的唯一标识,crash解析中也会有该仅仅。去确定dysm文件和crash文件是匹配的
LC_VERSION_MIN_MACOSX 二进制文件要求的最低操作系统版本号 demo二进制版本号。支持最低os版本号为10.11
LC_SOURCE_VERSION 构建该二进制文件使用的源码版本号
LC_MAIN 设置程序主线程的入口地址和栈大小 demo二进制的entryoff位OXF50,正式__TEXT段偏移地址,然后看看0XF50的汇编代码,正式熟悉的main函数调用地址。详细请看以下汇编代码
LC_LOAD_DYLIB 载入额外的动态库,细致看这个命令格式,动态库地址和名,当前版本号号,兼容版本号号。该设计比較合理。假设对于动态库有版本号管理能力
LC_FUNCTION_STARTS 函数起始地址表,怎样使用呢?
LC_DATA_IN_CODE /* table of non-instructions in __text */ 不是非常理解

代码4.1

yingfang:mach-o文件结构-src fangying$ otool -vt a.out
a.out:
(__TEXT,__text) section
_main:
0000000100000f50 pushq %rbp
0000000100000f51 movq %rsp, %rbp
0000000100000f54 subq $0x20, %rsp
0000000100000f58 leaq 0x47(%rip), %rax
0000000100000f5f movl $0x0, -0x4(%rbp)
0000000100000f66 movl %edi, -0x8(%rbp)
0000000100000f69 movq %rsi, -0x10(%rbp)
0000000100000f6d movq %rax, %rdi
0000000100000f70 movb $0x0, %al
0000000100000f72 callq 0x100000f84
0000000100000f77 xorl %ecx, %ecx
0000000100000f79 movl %eax, -0x14(%rbp)
0000000100000f7c movl %ecx, %eax
0000000100000f7e addq $0x20, %rsp
0000000100000f82 popq %rbp
0000000100000f83 retq
section cmd 说明 举例
__text 主程序代码
__stubs 用于动态库链接的桩
__stub_helper 用于动态库链接的桩
__cstring 常亮字符串符号表描写叙述信息,通过该区信息,能够获得常亮字符串符号表地址
__unwind_info 这里字段不是太理解啥意思。希望大家指点下

动态库连接器–动态库链接信息

总结了mach-o文件的两个最重要的部分,那么动态库依据载入命令怎样动态链接到内存中的呢?以下总结这个动态过程。

  • 系统通过载入命令。获得动态载入器的地址/usr/lib/dyly(其解决的问题是。把代码段__TEXT中和动态库相关内容进行关联,比方代码中怎样调用到哪个动态库的相关代码段的偏移地址)

    (dyly是用户态进程。这个是开源的,不属于kern内核的部分)感兴趣能够看看这里

总结下:在载入命令中。和动态库和链接相关命令有例如以下几个:

  • 段命令

    • LC_DYLD_INFO_ONLY
    • LC_LOAD_DYLIB
    • LC_LOAD_DYLINKER
    • LC_SYMTAB
    • LC_DYSYMTAB
  • 区命令
    • __stubs
    • __stubs_helper

在进行动态链接器工作前,要先解析相关工作环境參数

  • LC_LOAD_DYLINKER 获得动态载入器地址
  • LC_LOAD_DYLIB 二进制文件依赖动态库信息

    能够使用otool工具。读取该部分信息

代码5.0

yingfang:mach-o文件结构-src fangying$ otool -L a.out
a.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1225.1.1)
  • LC_DYLD_INFO_ONLY 动态库信息,依据该命令是真正动态库绑定,地址重定向重要的信息。

    结合之前otool -l的信息中的command 4命令,以下struct就是该命令相应的数据结构:

代码5.1

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;
uint32_t rebase_size;
uint32_t bind_off;
uint32_t bind_size;
uint32_t weak_bind_off;
uint32_t weak_bind_size;
uint32_t lazy_bind_off;
uint32_t lazy_bind_size;
uint32_t export_off;
uint32_t export_size;
};

依据该载入命令的字段偏移,系统能够得到压缩动态数据信息区(dymanic load info)。

依据上述数据,dymanic load info数据区,主要包括了5种数据:

(以下的一些内容,我的理解可能不是太正确。希望和大家一起讨论)dyld_info_command详细定义地址

dymanic load info 说明 举例
重定向数据 rebase demo中该段数据位 11 22 10 51 11: 高位0x10表示设置马上数类型,低位0x01表示马上数类型为指针
22: 表示REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB + 2 重定向到数据段2。

结合上面的信息。就是重定向到数据段2。该段数据信息为一个指针
结合数据段2的数据,获得一个重定向符号指针[0x100001010 -> _printf]

绑定数据 bind 在demo中进行动态绑定依赖的dyld的函数 U dyld_stub_binder
弱绑定数据 weak bind 用于弱绑定动态库,就像weak_framework一样
懒绑定数据 lazy bind 对于须要从动态库载入的函数符号 demo中有两个:
U _printf
U _scanf
export数据 用于对外开放的函数 demo中仅仅有两个
0000000100000000 T __mh_execute_header
0000000100000f50 T _main

对于相关的绑定函数查找。能够使用nm命令

代码5.2

yingfang:mach-o文件结构-src fangying$ nm a.out
0000000100000000 T __mh_execute_header
0000000100000f50 T _main
U _printf
U dyld_stub_binder

>

标注:dymanic load info数据是以命令码(命令码就是一个字节码)的形式,传递详细内容。

高四位表示真正命令名。低四位表示一个马上数。

00表示该类型命令结束

能够使用dylyinfo获得这部分信息读取

代码5.3

yingfang:mach-o文件结构-src fangying$ xcrun dyldinfo -opcodes a.out
rebase opcodes:
0x0000 REBASE_OPCODE_SET_TYPE_IMM(1)
0x0001 REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(2, 0x00000010)
0x0003 REBASE_OPCODE_DO_REBASE_IMM_TIMES(1)
0x0004 REBASE_OPCODE_DONE()
binding opcodes:
0x0000 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(1)
0x0001 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, dyld_stub_binder)
0x0013 BIND_OPCODE_SET_TYPE_IMM(1)
0x0014 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x02, 0x00000000)
0x0016 BIND_OPCODE_DO_BIND()
0x0017 BIND_OPCODE_DONE
no compressed weak binding info
lazy binding opcodes:
0x0000 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x02, 0x00000010)
0x0002 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(1)
0x0003 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, _printf)
0x000C BIND_OPCODE_DO_BIND()
0x000D BIND_OPCODE_DONE
0x000E BIND_OPCODE_DONE
0x000F BIND_OPCODE_DONE

动态库链接器运行结果

上面总结,动态链接器相关信息(载入命令信息,载入命令偏移地址相关信息)。

如今总结下动态链接器运行的结果是什么?怎样使用相关动态链接信息,完毕相关过程的?

从字面上,之前我理解,链接器就是把文本段原来动态库函数相关地址,用真实的动态库地址替换。生成一个真实的完整的可运行文本。比方demo中printf是其他动态库的,可是其真实地址对于可运行文件是不知道,仅仅有这个运行文件运行时,通过动态链接器完好其原来文本段地址。

在总结之前两个问题前。先总结下__stubs(桩)的区概念:该区存放的是二进制文件里没有定义符号的占位符。编译器生成代码时会创建对符号桩区的调用。链接器在运行时解决对桩的这些调用。链接器解决方式是在被调用的地址处。放置一条JMP指令。JMP指令将控制权转交给真实的函数体。

回想下nm命令结果:U表示没有定义的符号

yingfang:mach-o文件结构-src fangying$ nm a.out
0000000100000000 T __mh_execute_header
0000000100000f50 T _main
U _printf
U dyld_stub_binder

看下demo中main函数汇编代码:

  • demo中真实的print函数调用,编译器,编译为callq 0x100000f84 ## symbol stub for: _printf
  • 汇编代码中。callq 0x100000f84 . 注意0x100000f84,这个地址是 __TEXT段的__stubs区的地址。换句话说,就是JMP到__stubs(桩区)– 段1 section位__stubs的起始地址
  • 0x100000f84地址。是一段汇编指令 0x100000f84: jmpq *0x86(%rip) # 0x100001010
  • 0x100001010地址,是指向(代码7.2)数据段__la_symbol_ptr区。因为这个数据都符号指针,查看下该地址指向的数据区域(代码7.3)
  • 0x100001010地址指针。指向地址为4294971292(数据段都在高位。所以相比__TEXT地址,这个地址是正常的)
  • 4294971292地址,运行汇编代码请看(代码7.4) 0x100000fa1: jmpq 0x100000f8c。请注意 0x100000f8c就是__TEXT段section __stub_helper区的起始地址。该地址是运行汇编代码详细请看(代码7.5)0x100000f95: jmpq *0x65(%rip) # 0x100001000
  • 0x100001000地址,恰好是__DATA段, __nl_symbol_ptr区的事实上地址,该地址指向的数据值位为 0x100001000: 0x0000000000000000 0x0000000000000000 (代码7.6)

>

总结:


+ __stubs区和__stub_helper区是帮助动态链接器找到指定数据段__nl_symbol_ptr区,二进制文件用0x0000000000000000进行占位,在运行时。系统依据dynamic loader info信息,把占位符换为调用dylib的dyld_stub_binder函数的汇编指令。


+ 当第一次调用完动态库中的符号后,动态链接器会依据dynamic loader info信息,把数据段__la_symbol_ptr指向正在的符号地址。而不是指向_nl_symbol_ptr区

代码7.0

yingfang:mach-o文件结构-src fangying$ otool -p _main -tV a1.out
a1.out:
(__TEXT,__text) section
_main:
0000000100000f50 pushq %rbp
0000000100000f51 movq %rsp, %rbp
0000000100000f54 subq $0x20, %rsp
0000000100000f58 leaq 0x47(%rip), %rax ## literal pool for: "Hello World!\n"
0000000100000f5f movl $0x0, -0x4(%rbp)
0000000100000f66 movl %edi, -0x8(%rbp)
0000000100000f69 movq %rsi, -0x10(%rbp)
0000000100000f6d movq %rax, %rdi
0000000100000f70 movb $0x0, %al
0000000100000f72 callq 0x100000f84 ## symbol stub for: _printf
0000000100000f77 xorl %ecx, %ecx
0000000100000f79 movl %eax, -0x14(%rbp)
0000000100000f7c movl %ecx, %eax
0000000100000f7e addq $0x20, %rsp
0000000100000f82 popq %rbp
0000000100000f83 retq

代码7.1

Section
sectname __stubs
segname __TEXT
addr 0x0000000100000f84
size 0x0000000000000006
offset 3972
align 2^1 (2)
reloff 0
nreloc 0
flags 0x80000408
reserved1 0 (index into indirect symbol table)
reserved2 6 (size of stubs)
Section
sectname __stub_helper
segname __TEXT
addr 0x0000000100000f8c
size 0x000000000000001a
offset 3980
align 2^2 (4)
reloff 0
nreloc 0
flags 0x80000400
reserved1 0
reserved2 0

代码7.2

yingfang:mach-o文件结构-src fangying$ xcrun dyldinfo -lazy_bind a1.out
lazy binding information (from lazy_bind part of dyld info):
segment section address index dylib symbol
__DATA __la_symbol_ptr 0x100001010 0x0000 libSystem _printf

代码7.3

(gdb) x/2g 0x100001010
0x100001010: 4294971292

代码7.4

(gdb) x/3i 4294971292
0x100000f9c: pushq $0x0
0x100000fa1: jmpq 0x100000f8c

代码7.5

(gdb) x/3i 0x100000f8c
0x100000f8c: lea 0x75(%rip),%r11 # 0x100001008
0x100000f93: push %r11
0x100000f95: jmpq *0x65(%rip) # 0x100001000

代码7.6

(gdb) x/3g 0x100001000
0x100001000: 0x0000000000000000 0x0000000000000000
0x100001010: 0x0000000100000f9c

可运行文件运行过程

依据上面总结。该段总结下可运行文件运行过程。

我总结例如以下:

  • 解析mach-o文件
  • 设置运行环境參数
    • 文本段VM映射參数
    • 载入命令
    • 动态库信息
    • 符号表地址信息
    • 动态符号表地址信息
    • 常亮字符串表地址信息
    • 动态库载入信息
    • 符号函数地址
    • 依赖动态库信息
    • 动态链接器地址信息
  • 依据动态库载入信息,把桩占位符,填写为指定调用_nl_symbol_ptr的汇编指令
  • 依据LC_MAIN的entry point调用指定entry offset偏移地址
  • 运行entry offset相关二进制(逻辑是依照汇编指令,进行运行)
  • 第一次运行到动态库函数时,进行一次懒载入动态绑定。而且动态链接器自己主动改动_la_symbol_ptr区的地址。指向动态库相应符号的地址
  • 第二次运行到动态库函数时,直接jmp到指定的符号地址

>

注意:系统非常多动态库都是共同拥有的,所以XOS做了共享库缓存优化,仅仅要有相关进程使用过相关动态库,在另一进程,动态链接器在填桩时。直接会把桩_la_symbol_ptr区的地址,指向动态库相应符号的地址。

详细看系统怎样载入文件。动态链接文件,以及进入入口函数,能够这里

parse_machfile(
struct vnode *vp,
vm_map_t map,
thread_t thread,
struct mach_header *header,
off_t file_offset,
off_t macho_size,
int depth,
int64_t aslr_offset,
int64_t dyld_aslr_offset,
load_result_t *result
)

mach-o格式和载入方式 – 能够做啥呢

基础非常重要。mach-o格式理解和载入运行逻辑总结。能够帮助我们正确认识到mac os和ios app可运行文件启动过程。

基于该内容。能够做的事情列一下

  • category冲突分析
  • 非OC函数switch
  • bitcode分析
  • 包支持架构分析
  • 常量字符串分析,比方资源为无使用情况分析
  • crash符号化
  • 符号模块查找
  • 学习经典的数据格式,对于设计相关数据协议,网络协议等等。也有非常好启示和參考价值

反过来:假设二进制包越来越大。进程启动速度也会越来越慢。因为读取。解析文件格式会比較慢。

通过对于mach-o文件的分析,对于__TEXT系统都是仅仅读区。程序代码逻辑都在该区。可是也发现因为为了保持代码栈形式的运行。系统对于动态库的函数,不是直接调用动态库的函数地址,而是先调用到数据段的_nl_symbol_ptr区。通过_nl_symbol_ptr的信息调用到__DATA段_la_symbol_ptr区,因为__DATA内存区。用户态能够去改动。因此我们能够利用该特性去替换相关函数调用。详细代码我也在基于fishhook代码总结中。

了解mach-o详细的格式和载入,动态链接过程原理。比方mac上使用DYLD_INSERT_LIBRARIES进行代码注入。或者使用fishhook进行c函数hook。都能非常easy理解。

Mach-O文件格式和程序从载入到运行过程的更多相关文章

  1. 程序的载入和运行(五)——《x86汇编语言:从实模式到保护模式》读书笔记25

    程序的载入和运行(五)--<x86汇编语言:从实模式到保护模式>读书笔记25 前面几篇博文最终把代码分析完了.这篇就来说说代码的编译.运行和调试. 1.代码的编译及写入镜像文件 之前我们都 ...

  2. elf 文件格式探秘——程序运行背后的故事

    摘要:本文主要讲解elf文件格式,通过readelf命令结合底层的相关数据结构,讲解相关内容,分析程序运行的基本原理. 本文来源:elf 文件格式探秘——程序运行背后的故事 http://blog.c ...

  3. 基础知识《零》---Java程序运行机制及运行过程

    Java运行机制 Java虚拟机(Java Virtual Machine):Java虚拟机可以理解成一个以字节码为机器指令的CPU:对于不同的运行平台,有不同的虚拟机:Java虚拟机机制屏蔽了底层运 ...

  4. java 程序运行过程 简介

    这里的Java程序运行过程,是指我们编译好代码之后,在命令行开始执行java xxx命令,到java程序开始执行起来的这一过程,我们称其为运行时. 第一步,操作系统解析我们输入的java xxx命令, ...

  5. 如何让VS2012编写的程序在XP下运行

    Win32主程序需要以下设置 第一步:在工程属性General设置 第二步:在C/C++ Code Generation 设置 第三步:SubSystem 和  Minimum Required Ve ...

  6. C#程序以管理员权限运行

    原文:C#程序以管理员权限运行 C#程序以管理员权限运行 在Vista 和 Windows 7 及更新版本的操作系统,增加了 UAC(用户账户控制) 的安全机制,如果 UAC 被打开,用户即使以管理员 ...

  7. 小程序 web 端实时运行工具

    微信小程序 web 端实时运行工具 https://chemzqm.github.io/wept/

  8. 黄聪:使用srvany.exe将任何程序作为Windows服务运行

    srvany.exe是什么? srvany.exe是Microsoft Windows Resource Kits工具集的一个实用的小工具,用于将任何EXE程序作为Windows服务运行.也就是说sr ...

  9. [技巧.Dotnet]轻松实现“强制.net程序以管理员身份运行”。

    使用场景: 程序中不少操作都需要特殊权限,有时为了方便,直接让程序以管理员方式运行. (在商业软件中,其实应该尽量避免以管理员身份运行.在安装或配置时,提前授予将相应权限.) 做法: 以C#项目为例: ...

随机推荐

  1. caffe-安装anaconda后重新编译caffe报错

    ks@ks-go:~/caffe-master$ make -j16 CXX/LD -o .build_release/tools/convert_imageset.bin CXX/LD -o .bu ...

  2. 用python正则表达式提取网页的url

    import re import urllib url="http://www.itokit.com" s=urllib.urlopen(url).read() ss=s.repl ...

  3. 洛谷——P1748 H数

    P1748 H数 题目背景 无 题目描述 所谓H数,是指只含有2,3,5,7这些质因数的数,如630是H数,而22不是.现在要求输出第n个H数,为了方便起见将H[1]定为1.已知n不超过10000,最 ...

  4. Abp数据库迁移注意事项

    前记:昨天下载了一个Abp模板,然后尝试利用EF CodeFirst进行数据库生成操作,然后就是一直报错 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误.未找到或无法访问服务 ...

  5. 安卓android破解方法

    韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha  313134555@qq.com 如何给smali文件中的unicode字符串添加中文注释 如何注释掉smali文件中包含关键字 ...

  6. 【最大流/费用流】BZOJ1834-[ZJOI2010]network 网络扩容

    [题目大意] 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费 ...

  7. 输入sql语句,将结果写入到xml文件

    import java.io.FileOutputStream; import java.sql.Connection; import java.sql.DriverManager; import j ...

  8. [WikiOI "天梯"1281] Xn数列

    题目描述Description 给你6个数,m, a, c, x0, n, g Xn+1 = ( aXn + c ) mod m,求Xn m, a, c, x0, n, g<=10^18 输入描 ...

  9. codevs 1345 饥饿的奶牛

    1345 饥饿的奶牛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description John养了若干奶牛,每天晚上奶牛都要进食.由于条件比较 ...

  10. 8VC Venture Cup 2016 - Elimination Round G. Raffles 线段树

    G. Raffles 题目连接: http://www.codeforces.com/contest/626/problem/G Description Johnny is at a carnival ...