前言
Mach-O 、hopper analysis 分析Mach-O文件的过程
正文
hopper
- hopper analysis 一个dylib的过程
<!-- -->
Hopper is ready
Mach-O ARMv7 file loaded
Starting background analysis
Analysis segment __TEXT
> analysis section __text
> analysis section __picsymbolstub4
> analysis section __stub_helper
> analysis section __gcc_except_tab
> analysis section __objc_methname
> transform section __objc_methname to C strings
> analysis section __ustring
> analysis section __cstring
> transform section __cstring to C strings
> analysis section __objc_classname
> transform section __objc_classname to C strings
> analysis section __objc_methtype
> transform section __objc_methtype to C strings
Analysis segment __DATA
> analysis section __nl_symbol_ptr
> analysis section __la_symbol_ptr
> analysis section __mod_init_func
> analysis section __const
> analysis section __cfstring
> analysis section __objc_classlist
> analysis section __objc_protolist
> analysis section __objc_imageinfo
> analysis section __objc_const
> analysis section __objc_selrefs
> analysis section __objc_classrefs
> analysis section __objc_superrefs
> analysis section __objc_ivar
> analysis section __objc_data
> analysis section __data
> analysis section __bss
Analysis segment __LINKEDIT
Analysis segment External Symbols
> mark procedures
Analysis of segment __TEXT
> analysis of section __text
> disassemble section __text
> searching for additional procedures in section __text
> searching for additional procedures in section __text
> analysis of section __picsymbolstub4
> disassemble section __picsymbolstub4
> searching for additional procedures in section __picsymbolstub4
> searching for additional procedures in section __picsymbolstub4
> analysis of section __stub_helper
> disassemble section __stub_helper
> searching for additional procedures in section __stub_helper
> searching for additional procedures in section __stub_helper
> analysis of section __gcc_except_tab
> analysis of section __objc_methname
> analysis of section __ustring
> analysis of section __cstring
> analysis of section __objc_classname
> analysis of section __objc_methtype
Analysis of segment __DATA
> analysis of section __nl_symbol_ptr
> analysis of section __la_symbol_ptr
> analysis of section __mod_init_func
> analysis of section __const
> analysis of section __cfstring
> analysis of section __objc_classlist
> analysis of section __objc_protolist
> analysis of section __objc_imageinfo
> analysis of section __objc_const
> analysis of section __objc_selrefs
> analysis of section __objc_classrefs
> analysis of section __objc_superrefs
> analysis of section __objc_ivar
> analysis of section __objc_data
> analysis of section __data
> analysis of section __bss
Analysis of segment __LINKEDIT
Analysis of segment External Symbols
> dataflow analysis of procedures in segment __TEXT
> dataflow analysis of procedures in segment __DATA
> dataflow analysis of procedures in segment __LINKEDIT
> dataflow analysis of procedures in segment External Symbols
> searching for additional procedures in section __text
> searching for additional procedures in section __picsymbolstub4
> searching for additional procedures in section __stub_helper
> searching for additional procedures in section __gcc_except_tab
> searching for additional procedures in section __objc_methname
> searching for additional procedures in section __ustring
> searching for additional procedures in section __cstring
> searching for additional procedures in section __objc_classname
> searching for additional procedures in section __objc_methtype
> searching for additional procedures in section __nl_symbol_ptr
> searching for additional procedures in section __la_symbol_ptr
> searching for additional procedures in section __mod_init_func
> searching for additional procedures in section __const
> searching for additional procedures in section __cfstring
> searching for additional procedures in section __objc_classlist
> searching for additional procedures in section __objc_protolist
> searching for additional procedures in section __objc_imageinfo
> searching for additional procedures in section __objc_const
> searching for additional procedures in section __objc_selrefs
> searching for additional procedures in section __objc_classrefs
> searching for additional procedures in section __objc_superrefs
> searching for additional procedures in section __objc_ivar
> searching for additional procedures in section __objc_data
> searching for additional procedures in section __data
> searching for additional procedures in section __bss
> dataflow analysis of procedures in segment __TEXT
> dataflow analysis of procedures in segment __DATA
> dataflow analysis of procedures in segment __LINKEDIT
> dataflow analysis of procedures in segment External Symbols
Background analysis ended in 10308ms
xcrun
- 查看section段: 有些 segment 中有多个 section
<!-- devzkndeMacBook-Pro:~ devzkn$ xcrun size -x -l -m tmp -->
tmp (for architecture armv7):
Segment __TEXT: 0x44000 (vmaddr 0x0 fileoff 0)
Section __text: 0x37ea4 (addr 0x4160 offset 16736)
Section __picsymbolstub4: 0x4c0 (addr 0x3c004 offset 245764)
Section __stub_helper: 0x3b4 (addr 0x3c4c4 offset 246980)
Section __gcc_except_tab: 0x38 (addr 0x3c878 offset 247928)
Section __objc_methname: 0x2fba (addr 0x3c8b0 offset 247984)
Section __ustring: 0x1b58 (addr 0x3f86a offset 260202)
Section __cstring: 0x1e4b (addr 0x413c2 offset 267202)
Section __objc_classname: 0x32f (addr 0x4320d offset 274957)
Section __objc_methtype: 0xac2 (addr 0x4353c offset 275772)
total 0x3fe9e
Segment __DATA: 0x8000 (vmaddr 0x44000 fileoff 278528)
Section __nl_symbol_ptr: 0x1c8 (addr 0x44000 offset 278528)
Section __la_symbol_ptr: 0x130 (addr 0x441c8 offset 278984)
Section __mod_init_func: 0x8 (addr 0x442f8 offset 279288)
Section __const: 0x538 (addr 0x44300 offset 279296)
Section __cfstring: 0x1ec0 (addr 0x44838 offset 280632)
Section __objc_classlist: 0x94 (addr 0x466f8 offset 288504)
Section __objc_protolist: 0x18 (addr 0x4678c offset 288652)
Section __objc_imageinfo: 0x8 (addr 0x467a4 offset 288676)
Section __objc_const: 0x3a40 (addr 0x467ac offset 288684)
Section __objc_selrefs: 0x714 (addr 0x4a1ec offset 303596)
Section __objc_classrefs: 0x130 (addr 0x4a900 offset 305408)
Section __objc_superrefs: 0x84 (addr 0x4aa30 offset 305712)
Section __objc_ivar: 0x24c (addr 0x4aab4 offset 305844)
Section __objc_data: 0x5c8 (addr 0x4ad00 offset 306432)
Section __data: 0x13c (addr 0x4b2c8 offset 307912)
Section __bss: 0x48 (addr 0x4b404 offset 0)
total 0x744c
Segment __LINKEDIT: 0x28000 (vmaddr 0x4c000 fileoff 311296)
total 0x74000
tmp (for architecture arm64):
Segment __TEXT: 0x40000 (vmaddr 0x0 fileoff 0)
Section __text: 0x30c7c (addr 0x6e80 offset 28288)
Section __stubs: 0x360 (addr 0x37afc offset 228092)
Section __stub_helper: 0x378 (addr 0x37e5c offset 228956)
Section __gcc_except_tab: 0x8c (addr 0x381d4 offset 229844)
Section __objc_methname: 0x2fba (addr 0x38260 offset 229984)
Section __ustring: 0x1b58 (addr 0x3b21a offset 242202)
Section __cstring: 0x1e51 (addr 0x3cd72 offset 249202)
Section __objc_classname: 0x32f (addr 0x3ebc3 offset 256963)
Section __objc_methtype: 0xb3b (addr 0x3eef2 offset 257778)
Section __const: 0xc8 (addr 0x3fa30 offset 260656)
Section __unwind_info: 0x508 (addr 0x3faf8 offset 260856)
total 0x3917d
Segment __DATA: 0x10000 (vmaddr 0x40000 fileoff 262144)
Section __got: 0x378 (addr 0x40000 offset 262144)
Section __la_symbol_ptr: 0x240 (addr 0x40378 offset 263032)
Section __mod_init_func: 0x10 (addr 0x405b8 offset 263608)
Section __const: 0x880 (addr 0x405d0 offset 263632)
Section __cfstring: 0x3d80 (addr 0x40e50 offset 265808)
Section __objc_classlist: 0x128 (addr 0x44bd0 offset 281552)
Section __objc_protolist: 0x30 (addr 0x44cf8 offset 281848)
Section __objc_imageinfo: 0x8 (addr 0x44d28 offset 281896)
Section __objc_const: 0x6a28 (addr 0x44d30 offset 281904)
Section __objc_selrefs: 0xe28 (addr 0x4b758 offset 309080)
Section __objc_classrefs: 0x260 (addr 0x4c580 offset 312704)
Section __objc_superrefs: 0x108 (addr 0x4c7e0 offset 313312)
Section __objc_ivar: 0x24c (addr 0x4c8e8 offset 313576)
Section __objc_data: 0xb90 (addr 0x4cb38 offset 314168)
Section __data: 0x248 (addr 0x4d6c8 offset 317128)
Section __bss: 0x90 (addr 0x4d910 offset 0)
total 0xd994
Segment __LINKEDIT: 0x2c000 (vmaddr 0x50000 fileoff 327680)
total 0x7c000
<!-- 在 segment中,一般都会有多个 section。 -->
它们包含了可执行文件的不同部分。
1、在 __TEXT segment 中,__text section 包含了编译所得到的机器码。
__stubs 和 __stub_helper 是给动态链接器 (dyld) 使用的。通过这两个 section,在动态链接代码中,可以允许延迟链接。
__const (在我们的代码中没有) 是常量,不可变的,就像 __cstring (包含了可执行文件中的字符串常量 – 在源码中被双引号包含的字符串) 常量一样。
2、__DATA segment 中包含了可读写数据
__nl_symbol_ptr 和 __la_symbol_ptr,它们分别是 non-lazy 和 lazy 符号指针
__const,在这里面会包含一些需要重定向的常量数据
__bss section 没有被初始化的静态变量
<!-- devzkndeMacBook-Pro:~ devzkn$ otool -t tmp -->
tmp (architecture armv7):
Contents of (__TEXT,__text) section
<!-- devzkndeMacBook-Pro:~ devzkn$ otool -s __TEXT __text tmp -->
tmp (architecture armv7):
Contents of (__TEXT,__text) section
由此可以看出 -t 参数在otool 中是 -s __TEXT __tex的简写
除了hopper ,还有一个工具很强大otool
- 使用otool 查看反汇编代码 -tv
devzkndeMacBook-Pro:~ devzkn$ otool -tv tmp
tmp (architecture armv7):
(__TEXT,__text) section
-[ initWithTimeOut:::]:
00004160 b0 b5 push {r4, r5, r7, lr}
- __cstring 包含了可执行文件中的字符串常量 – 在源码中被双引号包含的字符串- 方法名
devzkndeMacBook-Pro:~ devzkn$ xcrun otool -v -s __TEXT __cstring tmp
tmp (architecture armv7):
Contents of (__TEXT,__cstring) section
000413c2 [switch ip] %@!
000413d9 [switch ip] %@!
<!-- devzkndeMacBook-Pro:~ devzkn$ xcrun otool -v -s __TEXT __const tmp -->
- 查看某段中某节的命令为: otool -s __TEXT __text 可执行文件。
Mach-O
- Apple 系统上(包括 MacOS 以及 iOS)的可执行文件格式
<!-- Mach-O 是 Mach object 文件格式的缩写 -->
1、这种文件格式由文件头(Header)、加载命令(Load Commands)以及具体数据(Segment&Section)三部分组成
2、一种用于记录可执行文件、对象代码、共享库、动态加载代码和内存转储的文件格式。作为 a.out 格式的替代品,Mach-O 提供了更好的扩展性,并提升了符号表中信息的访问速度。
Header
使系统能够快速定位其运行环境以及文件类型
- struct
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 */
};
- otool -h
devzkndeMacBook-Pro:~ devzkn$ otool -h tmp
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedface 12 9 0x00 6 33 3640 0x00100085
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedfacf 16777228 0 0x00 6 33 4200 0x00100085
devzkndeMacBook-Pro:~ devzkn$ otool -hv tmp
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC ARM V7 0x00 DYLIB 33 3640 NOUNDEFS DYLDLINK TWOLEVEL NO_REEXPORTED_DYLIBS
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 ARM64 ALL 0x00 DYLIB 33 4200 NOUNDEFS DYLDLINK TWOLEVEL NO_REEXPORTED_DYLIBS
filetype 以及 flags 只列举了几个比较常见的定义,还有其他的详见 EXTERNAL_HEADERS/mach-o/x86_64/loader.h。
/Users/devzkn/Downloads/kevinsoftware/ios-Reverse_Engineering/mac-headers-master/usr/include/mach-o/loader.h
Load Commands
- Load Commands 是跟在 Header 后面的加载命令区.
<!-- 所有 commands 的大小总和即为 Header->sizeofcmds 字段,共有 Header->ncmds 条加载命令。 -->
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedface 12 9 0x00 6 33 3640 0x00100085
- otool -l
<!-- 看加载命令区 -->
devzkndeMacBook-Pro:~ devzkn$ otool -l tmp
tmp (architecture armv7):
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedface 12 9 0x00 6 33 3640 0x00100085
<!--LC_SEGMENT_64 将对应的段中的数据加载并映射到进程的内存空间去 -->
Load command 0
cmd LC_SEGMENT
cmdsize 668
segname __TEXT
vmaddr 0x00000000
vmsize 0x00044000
Load command 1
cmd LC_SEGMENT
cmdsize 1144
segname __DATA
Load command 2
cmd LC_SEGMENT
cmdsize 56
segname __LINKEDIT
vmaddr 0x0004c000
vmsize 0x00028000
fileoff 311296
filesize 154080
maxprot 0x00000001
initprot 0x00000001
nsects 0
flags 0x0
Load command 3
cmd LC_ID_DYLIB
cmdsize 84
name /Library/MobileSubstrate/DynamicLibraries/.dylib (offset 24)
time stamp 1 Thu Jan 1 08:00:01 1970
current version 1.0.0
compatibility version 1.0.0
Load command 4
cmd LC_DYLD_INFO_ONLY
cmdsize 48
rebase_off 311296
<!-- 符号表信息 -->
Load command 5
cmd LC_SYMTAB
cmdsize 24
symoff 323260
nsyms 4023
stroff 372600
strsize 76988
<!-- LC_DYSYMTAB符号表 动态符号表信息
-->
Load command 6
cmd LC_DYSYMTAB
cmdsize 80
ilocalsym 0
<!-- 唯一的 UUID,标示该二进制文件,128bit -->
Load command 7
cmd LC_UUID
cmdsize 24
uuid 5A3F7C11---ADC9-
<!-- 要求的最低系统版本(Xcode中的Deployment Target) -->
Load command 8
cmd LC_VERSION_MIN_IPHONEOS
cmdsize 16
version 9.1
sdk 10.3
Load command 9
cmd LC_SOURCE_VERSION
cmdsize 16
version 0.0
<!-- 加密信息 grep cryptid 可以查看是否加密。 -->
Load command 10
cmd LC_ENCRYPTION_INFO
cmdsize 20
cryptoff 16384
cryptsize 262144
cryptid 0
<!-- 加载的动态库,包括动态库地址、名称、版本号等 -->
Load command 11
cmd LC_LOAD_DYLIB
cmdsize 96
name /System/Library/PrivateFrameworks/StoreServices.framework/StoreServices (offset 24) 名称
time stamp 2 Thu Jan 1 08:00:02 1970
current version 1440.12.0 版本号
compatibility version 1.0.0
Load command 27
cmd LC_RPATH
cmdsize 32
path @executable_path (offset 12)
Load command 28
cmd LC_RPATH
cmdsize 56
path /Library/MobileSubstrate/DynamicLibraries (offset 12)
Load command 29
cmd LC_RPATH
cmdsize 36
path /var/mobile/frameworks/ (offset 12)
<!-- 函数地址起始表 -->
Load command 30
cmd LC_FUNCTION_STARTS
cmdsize 16
dataoff 322000
datasize 852
Load command 31
cmd LC_DATA_IN_CODE
cmdsize 16
dataoff 322852
datasize 408
<!-- 代码签名信息 -->
Load command 32
cmd LC_CODE_SIGNATURE
cmdsize 16
dataoff 449600
datasize 15776
Segment
Mach-O 文件有多个段(Segment),每个段有不同的功能。然后每个段又分为很多小的 Section。 LC_SEGMENT 意味着这部分文件需要映射到进程的地址空间去
- 段名
__PAGEZERO: 空指针陷阱段,映射到虚拟内存空间的第一页,用于捕捉对 NULL 指针的引用。
__TEXT: 包含了执行代码以及其他只读数据。该段数据可以 VM_PROT_READ(读)、VM_PROT_EXECUTE(执行),不能被修改。
__DATA: 程序数据,该段可写 VM_PROT_WRITE/READ/EXECUTE。
__LINKEDIT: 链接器使用的符号以及其他表。
LC_DYSYMTAB符号表
LC_DYSYMTAB符号表有非常大的作用,捕获到线上 Crash 或者 卡顿 堆栈的地址信息时,需要进行符号还原,进而确认卡顿、崩溃的具体位置,这个使用就要使用到LC_DYSYMTAB符号表;
- 结构
struct symtab_command {
uint32_t cmd; /* LC_SYMTAB */
uint32_t cmdsize; /* sizeof(struct symtab_command) */
uint32_t symoff; /* symbol table offset */
uint32_t nsyms; /* number of symbol table entries */
uint32_t stroff; /* string table offset */
uint32_t strsize; /* string table size in bytes */
};
<!-- 符号表在 Mach-O目标文件中的地址可以通过LC_SYMTAB加载命令指定的 symoff找到,对应的符号名称在stroff,总共有nsyms条符号信息 -->
Section
它的结构体跟随在 LC_SEGMENT 结构体之后,LC_SEGMENT 又在 Load Commands 中, segment 的数据内容是跟在 Load Commands 之后的。 /Users/devzkn/Downloads/kevinsoftware/ios-Reverse_Engineering/mac-headers-master/usr/include/mach-o/loader.h
- 各节的作用
Section | 作用 |
---|---|
__text: 主程序代码 | |
__stub_helper: 用于动态链接的存根 | |
__symbolstub1: 用于动态链接的存根 | |
__objc_methname: Objective-C 的方法名 | |
__objc_classname: Objective-C 的类名 | |
__cstring: 硬编码的字符串 |
__lazy_symbol: 懒加载,延迟加载节,通过 dyld_stub_binder 辅助链接 |
_got: 存储引用符号的实际地址,类似于动态符号表 |
__nl_symbol_ptr: 非延迟加载节 |
__mod_init_func: 初始化的全局函数地址,在 main 之前被调用 |
__mod_term_func: 结束函数地址 |
__cfstring: Core Foundation 用到的字符串(OC字符串) |
__objc_clsslist: Objective-C 的类列表 |
__objc_nlclslist: Objective-C 的 +load 函数列表,比 __mod_init_func 更早执行 |
__objc_const: Objective-C 的常量 |
__data: 初始化的可变的变量 |
__bss: 未初始化的静态变量 |
- Section 是具体有用的数据存放的地方
Section | 作用 |
---|---|
TEXT.text | 只有可执行的机器码 |
TEXT.cstring | 去重后的C字符串(不含中文字符) |
TEXT.const | 初始化过的常量 |
TEXT.stubs | 符号桩。本质上是一小段会直接跳入lazybinding的表对应项指针指向的地址的代码。 |
TEXT.stub_helper | 辅助函数。上述提到的lazybinding的表中对应项的指针在没有找到真正的符号地址的时候,都指向这。 |
TEXT.unwind_info | 用于存储处理异常情况信息 |
TEXT.eh_frame | 调试辅助信息 |
DATA.data | 初始化过的可变的(静态/全局)数据 |
DATA.nl_symbol_ptr | 非lazy-binding的指针表,每个表项中的指针都指向一个在装载过程中,被动态链机器搜索完成的符号 |
DATA.la_symbol_ptr | lazy-binding的指针表,每个表项中的指针一开始指向stub_helper |
DATA.const | 没有初始化过的常量 |
DATA.mod_init_func | 初始化函数,在main之前调用 |
DATA.mod_term_func | 终止函数,在main返回之后调用 |
DATA.bss | 没有初始化的(静态/全局)变量 |
DATA.common | 没有初始化过的符号声明 |
TEXT.ustring | utf-8编码后的中文字符串 |
TEXT.objc_methname | OC方法名(不含c方法,所有的方法都在TEXT.text中) |
DATA.cfstring | 用OC方法创建的字符串,对TEXT段中字符串的引用 |
DATA.__objc _classlist节 | 这个节列出了所有的class(metaclass自身也是一种class)。 |
DATA.__objc _catlist | 代表的就是程序里面有哪些Category |
DATA.__objc_protolist | 代表的就是程序里面有哪些Protocol |
DATA.__objc_classrefs | 该节是为了标记这个类究竟有没有被引用 |
DATA.__objc_selrefs | 告诉你究竟有哪些SEL对应的字符串被引用了 |
DATA.__objc_superrefs | 在编译期指定方法对应的current_class,以方便后续的superclass方法列表查找 |
DATA.__objc_const | 存放的是一些需要在类加载过程中用到的readonly data |
see also
<!-- http://www.aosabook.org/en/llvm.html -->
Chris Lattner 生于 1978 年,2005年加入苹果,将苹果使用的 GCC 全面转为 LLVM。2010年开始主导开发 Swift 语言。
<!-- Clang 是 LLVM 的子项目,是 C,C++ 和 Objective-C 编译器 http://clang.llvm.org/docs/ -->
其中的 clang static analyzer 主要是进行语法分析,语义分析和生成中间代码,当然这个过程会对代码进行检查,出错的和需要警告的会标注出来。
<!-- lld 是 Clang / LLVM 的内置链接器,clang 必须调用链接器来产生可执行文件。 -->
<!--1、 先通过-E查看clang在预编译处理这步做了什么: 包括宏的替换,头文件的导入 -->
clang -E main.m
<!-- 2、预处理完成后就会进行词法分析,这里会把代码切成一个个 Token,比如大小括号,等于号还有字符串等 -->
<!-- 3、然后是语法分析,验证语法是否正确,然后将所有节点组成抽象语法树 AST 。 -->
<!-- 4、IR中间代码的生成:CodeGen 会负责将语法树自顶向下遍历逐步翻译成 LLVM IR,IR 是编译过程的前端的输出后端的输入 -->
1、Pass 教程: http://llvm.org/docs/WritingAnLLVMPass.html
2、如果开启了 bitcode 苹果会做进一步的优化,有新的后端架构还是可以用这份优化过的 bitcode 去生成。
clang -emit-llvm -c main.m -o main.bc
<!-- 5、生成汇编 -->
clang -S -fobjc-arc main.m -o main.s
<!--6、 生成目标文件 -->
clang -fmodules -c main.m -o main.o
<!--7、生成可执行文件-->
clang main.o -o main
<!-- 二、完整步骤: -->
1)编译信息写入辅助文件,创建文件架构 .app 文件
2)处理文件打包信息
3)执行 CocoaPod 编译前脚本,checkPods Manifest.lock
4)编译.m文件,使用 CompileC 和 clang 命令
5)链接需要的 Framework
6)编译 xib
7)拷贝 xib ,资源文件
8)编译 ImageAssets
9)处理 info.plist
10)执行 CocoaPod 脚本
11)拷贝标准库
12)创建 .app 文件和签名
<!-- 三、clang 命令参数 -->
-x 编译语言比如objective-c
-arch 编译的架构,比如arm7
-f 以-f开头的。
-W 以-W开头的,可以通过这些定制编译警告
-D 以-D开头的,指的是预编译宏,通过这些宏可以实现条件编译
-iPhoneSimulator10.1.sdk 编译采用的iOS SDK版本
-I 把编译信息写入指定的辅助文件
-F 需要的Framework
-c 标识符指明需要运行预处理器,语法分析,类型检查,LLVM生成优化以及汇编代码生成.o文件
-o 编译结果
<!-- Build Phases:构建可执行文件的规则 -->
1)指定 target 的依赖项目,在 target build 之前需要先 build 的依赖。在 Compile Source 中指定所有必须编译的文件,
2)在 Link Binary With Libraries 里会列出所有的静态库和动态库,它们会和编译生成的目标文件进行链接。
3)build phase 还会把静态资源拷贝到 bundle 里。
4)可以通过在 build phases 里添加自定义脚本来做些事情,比如像 CocoaPods 所做的那样。
<!-- Build Rules: 指定不同文件类型如何编译 -->
<!-- Build Settings : 在 build 的过程中各个阶段的选项的设置。-->
<!-- 四、Clang Static Analyzer静态代码分析: https://code.woboq.org/llvm/clang/ -->
静态分析前会对源代码分词成 Token,这个过程称为词法分析(Lexical Analysis)
编译的概念(词法->语法->语义->IR->优化->CodeGen) 在 clang static analyzer 里到处可见。
<!-- Token 可以分为以下几类 -->
关键字:语法中的关键字,if else while for 等。
标识符:变量名
字面量:值,数字,字符串
特殊符号:加减乘除等符号
<!-- 语法分析(Semantic Analysis)将 token 先按照语法组合成语义生成 VarDecl 节点,然后将这些节点按照层级关系构成抽象语法树 Abstract Syntax Tree (AST)。 -->
<!-- 五、CodeGen 生成 IR 代码 -->
1)各种类,方法,成员变量等的结构体的生成,并将其放到对应的Mach-O的section中。
2)Non-Fragile ABI 合成 OBJCIVAR$_ 偏移值常量。
3)ObjCMessageExpr 翻译成相应版本的 objc_msgSend,super 翻译成 objc_msgSendSuper。
4)strong,weak,copy,atomic 合成 @property 自动实现 setter 和 getter。
5)@synthesize 的处理。
6)生成 block_layout 数据结构
7)block 和 weak
8)_block_invoke
9)ARC 处理,插入 objc_storeStrong 和 objc_storeWeak 等 ARC 代码。ObjCAutoreleasePoolStmt 转 objc_autorealeasePoolPush / Pop。自动添加 [super dealloc]。给每个 ivar 的类合成 .cxx_destructor 方法自动释放类的成员变量。
<!-- 六、IR 结构 -->
LLVM IR 有三种表示格式,第一种是 bitcode 这样的存储格式,以 .bc 做后缀,第二种是可读的以 .ll,第三种是用于开发时操作 LLVM IR 的内存格式
llc 编译器是专门编译 LLVM IR 的编译器用来生成汇编文件。
<!-- Driver -->
Driver 是 Clang 面对用户的接口,用来解析 Option 设置,判断决定调用的工具链,最终完成整个编译过程。
<!-- Translate:Translate 就是把相关的参数对应到不同平台上不同的工具。-->
<!-- 每次编译后生成的 dSYM 文件 -->
dSYM 文件里存储了函数地址映射,这样调用栈里的地址可以通过 dSYM 这个映射表能够获得具体函数的位置。一般都会用来处理 crash 时获取到的调用栈 .crash 文件将其符号化
https://zhangkn.github.io/2018/03/symbolicatecrash/
<!-- -->
<!-- Xcode 中编译器默认选择使用 clang -->
<!-- 编译器处理过程 -->
1、预处理
符号化 (Tokenization)
宏定义的展开
#include 的展开
语法和语义分析
2、将符号化后的内容转化为一棵解析树 (parse tree)
解析树做语义分析
输出一棵抽象语法树(Abstract Syntax Tree* (AST))
生成代码和优化
3、将 AST 转换为更低级的中间码 (LLVM IR)
对生成的中间码做优化
生成特定目标代码
输出汇编代码
4、汇编器
将汇编代码转换为目标对象文件。
5、链接器
将多个目标对象文件合并为一个可执行文件 (或者一个动态库)
<!-- devzkndeMacBook-Pro:~ devzkn$ xcrun size -x -l -m tmp -->
当虚拟内存系统进行映射时,segment 和 section 会以不同的参数和权限被映射。
__TEXT segment 包含了被执行的代码。它被以只读和可执行的方式映射
Segment __DATA: 0x8000 (vmaddr 0x44000 fileoff 278528)
Section __nl_symbol_ptr: 0x1c8 (addr 0x44000 offset 278528)
Section __la_symbol_ptr: 0x130 (addr 0x441c8 offset 278984)
__DATA segment 以可读写和不可执行的方式映射。它包含了将会被更改的数据。
__nl_symbol_ptr 和 __la_symbol_ptr,它们分别是 non-lazy 和 lazy 符号指针。
延迟符号指针用于可执行文件中调用未定义的函数,例如不包含在可执行文件中的函数,它们将会延迟加载。而针对非延迟符号指针,当可执行文件被加载同时,也会被加载。
<!-- 2.1:静态分析防护 -->
1.对抗hopper和ida的分析可以修改macho文件的某些偏移量, 让hopper和ida无法分析造成闪退
2.对抗class-dump 和工具分析可以方法名类名混淆,混淆方案大致三种
1.编译前用脚本批量做宏定义替换
2.LLVM混淆
3.对Mach-O__objc_classnamehe __objc_methname
3.逻辑混淆(花指令)
<!-- 2.2:动态分析防护 -->
1.ptrace ,syscall sysctl,dlsym等
<!-- 2.3:动态注入防护 -->
1.__RESTRICT关联main函数: 用getsectiondata关联__RESTRICT
2.dladdr查看函数的内存空间信息, 验证函数的指针来自程序, 还是苹果的库, 还是未知.
<!-- 2.6:重签名防护 -->
1.拿到当前的签名文件的签名信息和编译前的签名信息比对
在操作过程或者文章有问题的话欢迎在 原文 里提问或指正。