最早了解到fishhook是看了下面两篇文章之后,顿时让我觉得这是一个非常好的东西。总共210行代码,收获了1500+个star,神作啊。
- 使用fishhook拦截NSSetUncaughtExceptionHandler函数解决NSUncaughtExceptionHandler被修改的问题。
- 聊聊苹果的Bug - iOS 10 nano_free Crash,通过fishhook替换malloc相关的函数尝试解决crash。
OC的runtime非常强大,可以玩很多黑魔法。而操作系统也会提供一些基础设施,比如Solaris/Mac DTrace和Linux systemtap,通过编写脚本分析各种系统调用的情况。相比之下,C语言没有runtime,也玩不出什么花来。不过fishhook提供了一种很好的方式,让我们得以做一些有意义的工作。花了点时间研究一下fishhook的源代码,也能增加一下对Mach-O执行格式的理解。
_dyld_register_func_for_add_image
fishhook利用了_dyld_register_func_for_add_image
在动态库加载完成之后,做一次符号地址的替换,简化了遍历逻辑。当然fishhook也支持在App启动之后遍历所有的动态库做符号替换。
/*
* The following functions allow you to install callbacks which will be called
* by dyld whenever an image is loaded or unloaded. During a call to _dyld_register_func_for_add_image()
* the callback func is called for every existing image. Later, it is called as each new image
* is loaded and bound (but initializers not yet run). The callback registered with
* _dyld_register_func_for_remove_image() is called after any terminators in an image are run
* and before the image is un-memory-mapped.
*/
extern void _dyld_register_func_for_add_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide)) __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
我们App目前在用_dyld_register_func_for_add_image
将所有要加载的动态库都在控制台打印出来了。
Added: 0x101afe000 (0x8000) /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/libBacktraceRecording.dylib <0B27D656-0E24-3133-BAA2-3B3EC2409C04> time: 1488353483592
Added: 0x101b0c000 (0x8000) /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator10.2.sdk/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib <31AD1037-C99E-3141-AAD1-CF345BA42E72> time: 1488353483592
Mach-O
Mach-O的格式如下所示。每个segment里面包含了很多section。__DATA
segment的section尤其多,__la_symbol_ptr
是其中一个。
fishhook的原理是遍历__DATA
segment里面__nl_symbol_ptr
、__la_symbol_ptr
两个section里面的符号,通过Indirect Symbol Table、Symbol Table、String Table的配合,找到自己要替换的函数,然后做替换。整个过程如下所示。
MachOView
MachOView看Mach-O格式比较直观。
screenshot.pngotools && nm
通过otools和nm也可以对可执行程序做很多分析。
$ otool -l /Users/henshao/Library/Developer/Xcode/DerivedData/FishHookTest-elsztizpkmqzuedzxtjbslvzndzj/Build/Products/Debug-iphonesimulator/FishHookTest.app/FishHookTest
/Users/henshao/Library/Developer/Xcode/DerivedData/FishHookTest-elsztizpkmqzuedzxtjbslvzndzj/Build/Products/Debug-iphonesimulator/FishHookTest.app/FishHookTest:
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedfacf 16777223 3 0x00 2 20 2760 0x00200085
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 792
segname __TEXT
vmaddr 0x0000000100000000
vmsize 0x0000000000004000
fileoff 0
filesize 16384
maxprot 0x00000007
initprot 0x00000005
nsects 9
flags 0x0
Section
sectname __text
segname __TEXT
addr 0x00000001000018c0
size 0x0000000000000f7a
offset 6336
align 2^4 (16)
reloff 0
nreloc 0
flags 0x80000400
reserved1 0
reserved2 0
Section
sectname __stubs
segname __TEXT
addr 0x000000010000283a
size 0x0000000000000096
offset 10298
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 0x00000001000028d0
size 0x000000000000010a
offset 10448
align 2^2 (4)
reloff 0
nreloc 0
flags 0x80000400
reserved1 0
reserved2 0
Section
sectname __objc_methname
segname __TEXT
addr 0x00000001000029da
size 0x0000000000000a13
offset 10714
align 2^0 (1)
reloff 0
nreloc 0
flags 0x00000002
reserved1 0
reserved2 0
Section
sectname __objc_classname
segname __TEXT
addr 0x00000001000033ed
size 0x000000000000003c
offset 13293
align 2^0 (1)
reloff 0
nreloc 0
flags 0x00000002
reserved1 0
reserved2 0
Section
sectname __objc_methtype
segname __TEXT
addr 0x0000000100003429
size 0x000000000000082a
offset 13353
align 2^0 (1)
reloff 0
nreloc 0
flags 0x00000002
reserved1 0
reserved2 0
Section
sectname __cstring
segname __TEXT
addr 0x0000000100003c53
size 0x00000000000001cb
offset 15443
align 2^0 (1)
reloff 0
nreloc 0
flags 0x00000002
reserved1 0
reserved2 0
Section
sectname __entitlements
segname __TEXT
addr 0x0000000100003e1e
size 0x0000000000000190
offset 15902
align 2^0 (1)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
Section
sectname __unwind_info
segname __TEXT
addr 0x0000000100003fb0
size 0x0000000000000050
offset 16304
align 2^2 (4)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
Load command 2
cmd LC_SEGMENT_64
cmdsize 1192
segname __DATA
vmaddr 0x0000000100004000
vmsize 0x0000000000001000
fileoff 16384
filesize 4096
maxprot 0x00000007
initprot 0x00000003
nsects 14
flags 0x0
Section
sectname __nl_symbol_ptr
segname __DATA
addr 0x0000000100004000
size 0x0000000000000010
offset 16384
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000006
reserved1 25 (index into indirect symbol table)
reserved2 0
Section
sectname __got
segname __DATA
addr 0x0000000100004010
size 0x0000000000000008
offset 16400
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000006
reserved1 27 (index into indirect symbol table)
reserved2 0
Section
sectname __la_symbol_ptr
segname __DATA
addr 0x0000000100004018
size 0x00000000000000c8 //0xc8 = 200,200/8=25。
offset 16408
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000007
reserved1 28 (index into indirect symbol table)
reserved2 0
Section
sectname __objc_classlist
segname __DATA
addr 0x00000001000040e0
size 0x0000000000000010
offset 16608
align 2^3 (8)
reloff 0
nreloc 0
flags 0x10000000
reserved1 0
reserved2 0
Section
sectname __objc_protolist
segname __DATA
addr 0x00000001000040f0
size 0x0000000000000010
offset 16624
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
Section
sectname __objc_imageinfo
segname __DATA
addr 0x0000000100004100
size 0x0000000000000008
offset 16640
align 2^2 (4)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
Section
sectname __objc_const
segname __DATA
addr 0x0000000100004108
size 0x0000000000000be0
offset 16648
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
Section
sectname __objc_selrefs
segname __DATA
addr 0x0000000100004ce8
size 0x0000000000000018
offset 19688
align 2^3 (8)
reloff 0
nreloc 0
flags 0x10000005
reserved1 0
reserved2 0
Section
sectname __objc_classrefs
segname __DATA
addr 0x0000000100004d00
size 0x0000000000000008
offset 19712
align 2^3 (8)
reloff 0
nreloc 0
flags 0x10000000
reserved1 0
reserved2 0
Section
sectname __objc_superrefs
segname __DATA
addr 0x0000000100004d08
size 0x0000000000000008
offset 19720
align 2^3 (8)
reloff 0
nreloc 0
flags 0x10000000
reserved1 0
reserved2 0
Section
sectname __objc_ivar
segname __DATA
addr 0x0000000100004d10
size 0x0000000000000008
offset 19728
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
Section
sectname __objc_data
segname __DATA
addr 0x0000000100004d18
size 0x00000000000000a0
offset 19736
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
Section
sectname __data
segname __DATA
addr 0x0000000100004db8
size 0x00000000000000c0
offset 19896
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
Section
sectname __bss
segname __DATA
addr 0x0000000100004e78
size 0x0000000000000018
offset 0
align 2^3 (8)
reloff 0
nreloc 0
flags 0x00000001
reserved1 0
reserved2 0
Load command 3
cmd LC_SEGMENT_64
cmdsize 72
segname __LINKEDIT
vmaddr 0x0000000100005000
vmsize 0x0000000000005000
fileoff 20480
filesize 17040
maxprot 0x00000007
initprot 0x00000001
nsects 0
flags 0x0
Load command 4
cmd LC_DYLD_INFO_ONLY
cmdsize 48
rebase_off 20480
rebase_size 200
bind_off 20680
bind_size 296
weak_bind_off 0
weak_bind_size 0
lazy_bind_off 20976
lazy_bind_size 568
export_off 21544
export_size 200
Load command 5
cmd LC_SYMTAB
cmdsize 24
symoff 21776
nsyms 162
stroff 24580
strsize 3152
Load command 6
cmd LC_DYSYMTAB
cmdsize 80
ilocalsym 0
nlocalsym 121
iextdefsym 121
nextdefsym 8
iundefsym 129
nundefsym 33
tocoff 0
ntoc 0
modtaboff 0
nmodtab 0
extrefsymoff 0
nextrefsyms 0
indirectsymoff 24368
nindirectsyms 53
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 0F497FE2-E79F-3376-BCFE-3E51F2AB6112
Load command 9
cmd LC_VERSION_MIN_IPHONEOS
cmdsize 16
version 10.2
sdk 10.2
Load command 10
cmd LC_SOURCE_VERSION
cmdsize 16
version 0.0
Load command 11
cmd LC_MAIN
cmdsize 24
entryoff 9920
stacksize 0
Load command 12
cmd LC_LOAD_DYLIB
cmdsize 88
name /System/Library/Frameworks/Foundation.framework/Foundation (offset 24)
time stamp 2 Thu Jan 1 08:00:02 1970
current version 1349.13.0
compatibility version 300.0.0
Load command 13
cmd LC_LOAD_DYLIB
cmdsize 56
name /usr/lib/libobjc.A.dylib (offset 24)
time stamp 2 Thu Jan 1 08:00:02 1970
current version 228.0.0
compatibility version 1.0.0
Load command 14
cmd LC_LOAD_DYLIB
cmdsize 56
name /usr/lib/libSystem.dylib (offset 24)
time stamp 2 Thu Jan 1 08:00:02 1970
current version 1238.0.0
compatibility version 1.0.0
Load command 15
cmd LC_LOAD_DYLIB
cmdsize 80
name /System/Library/Frameworks/UIKit.framework/UIKit (offset 24)
time stamp 2 Thu Jan 1 08:00:02 1970
current version 3600.6.21
compatibility version 1.0.0
Load command 16
cmd LC_RPATH
cmdsize 40
path @executable_path/Frameworks (offset 12)
Load command 17
cmd LC_FUNCTION_STARTS
cmdsize 16
dataoff 21744
datasize 32
Load command 18
cmd LC_DATA_IN_CODE
cmdsize 16
dataoff 21776
datasize 0
Load command 19
cmd LC_CODE_SIGNATURE
cmdsize 16
dataoff 27744
datasize 9776
#这里面_OBJC_CLASS_xxx都是外部符号。还有些依赖的函数不在__la_symbol_ptr里面,比如___stack_chk_guard和dyld_stub_binder。
$ nm -um /Users/henshao/Library/Developer/Xcode/DerivedData/FishHookTest-elsztizpkmqzuedzxtjbslvzndzj/Build/Products/Debug-iphonesimulator/FishHookTest.app/FishHookTest
(undefined) external _NSStringFromClass (from Foundation)
(undefined) external _OBJC_CLASS_$_UIResponder (from UIKit)
(undefined) external _OBJC_CLASS_$_UIViewController (from UIKit)
(undefined) external _OBJC_METACLASS_$_NSObject (from libobjc)
(undefined) external _OBJC_METACLASS_$_UIResponder (from UIKit)
(undefined) external _OBJC_METACLASS_$_UIViewController (from UIKit)
(undefined) external _UIApplicationMain (from UIKit)
(undefined) external ___memcpy_chk (from libSystem)
(undefined) external ___stack_chk_fail (from libSystem)
(undefined) external ___stack_chk_guard (from libSystem)
(undefined) external __dyld_get_image_header (from libSystem)
(undefined) external __dyld_get_image_vmaddr_slide (from libSystem)
(undefined) external __dyld_image_count (from libSystem)
(undefined) external __dyld_register_func_for_add_image (from libSystem)
(undefined) external __objc_empty_cache (from libobjc)
(undefined) external _close (from libSystem)
(undefined) external _dladdr (from libSystem)
(undefined) external _free (from libSystem)
(undefined) external _malloc (from libSystem)
(undefined) external _memset (from libSystem)
(undefined) external _objc_autoreleasePoolPop (from libobjc)
(undefined) external _objc_autoreleasePoolPush (from libobjc)
(undefined) external _objc_msgSend (from libobjc)
(undefined) external _objc_msgSendSuper2 (from libobjc)
(undefined) external _objc_release (from libobjc)
(undefined) external _objc_retainAutoreleasedReturnValue (from libobjc)
(undefined) external _objc_storeStrong (from libobjc)
(undefined) external _open (from libSystem)
(undefined) external _printf (from libSystem)
(undefined) external _read (from libSystem)
(undefined) external _strcmp (from libSystem)
(undefined) external _strnlen (from libSystem)
(undefined) external dyld_stub_binder (from libSystem)
一点点注释
#import "fishhook.h"
#import <stdio.h>
#import <dlfcn.h>
#import <stdlib.h>
#import <string.h>
#import <sys/types.h>
#import <mach-o/dyld.h>
#import <mach-o/loader.h>
#import <mach-o/nlist.h>
#ifdef __LP64__
typedef struct mach_header_64 mach_header_t;
typedef struct segment_command_64 segment_command_t;
typedef struct section_64 section_t;
typedef struct nlist_64 nlist_t;
#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64
#else
typedef struct mach_header mach_header_t;
typedef struct segment_command segment_command_t;
typedef struct section section_t;
typedef struct nlist nlist_t;
#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT
#endif
#ifndef SEG_DATA_CONST
#define SEG_DATA_CONST "__DATA_CONST"
#endif
struct rebindings_entry {
struct rebinding *rebindings;
size_t rebindings_nel;
struct rebindings_entry *next;
};
static struct rebindings_entry *_rebindings_head;
static int prepend_rebindings(struct rebindings_entry **rebindings_head,
struct rebinding rebindings[],
size_t nel) {
struct rebindings_entry *new_entry = malloc(sizeof(struct rebindings_entry));
if (!new_entry) {
return -1;
}
new_entry->rebindings = malloc(sizeof(struct rebinding) * nel);
if (!new_entry->rebindings) {
free(new_entry);
return -1;
}
memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel);
new_entry->rebindings_nel = nel;
new_entry->next = *rebindings_head;
*rebindings_head = new_entry;
return 0;
}
static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
section_t *section,
intptr_t slide,
nlist_t *symtab,
char *strtab,
uint32_t *indirect_symtab) {
printf("size: %llu\n", section->size);
uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
//slide+section->addr 就是符号地址的数组
void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
//遍历section里面的每一个符号
for (uint i = 0; i < section->size / sizeof(void *); i++) {
//找到符号在Indrect Symbol Table表中的值
uint32_t symtab_index = indirect_symbol_indices[i];
if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL ||
symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) {
continue;
}
//接着去symbol table里面找到符号的值,进一步获取到符号在String Table的名字。
uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;
char *symbol_name = strtab + strtab_offset;
if (strnlen(symbol_name, 2) < 2) {
continue;
}
printf("symbol_name: %s\n", symbol_name);
struct rebindings_entry *cur = rebindings;
while (cur) {
for (uint j = 0; j < cur->rebindings_nel; j++) {
if (strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) {
if (cur->rebindings[j].replaced != NULL &&
indirect_symbol_bindings[i] != cur->rebindings[j].replacement) {
//把函数原来的地址保存起来
*(cur->rebindings[j].replaced) = indirect_symbol_bindings[i];
}
//将新函数的地址设置上
indirect_symbol_bindings[i] = cur->rebindings[j].replacement;
goto symbol_loop;
}
}
cur = cur->next;
}
symbol_loop:;
}
}
static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
const struct mach_header *header,
intptr_t slide) {
Dl_info info;
if (dladdr(header, &info) == 0) {
return;
}
segment_command_t *cur_seg_cmd;
segment_command_t *linkedit_segment = NULL;
struct symtab_command* symtab_cmd = NULL;
struct dysymtab_command* dysymtab_cmd = NULL;
//遍历Mach-O的segment非常有意思,要通过Load Command来遍历。
//从下面的代码来看,SEG_LINKEDIT这个segment非常重要,Indirect Symbol Table、Symbol Table、String Table的地址都要基于它获取。
uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t);
for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
cur_seg_cmd = (segment_command_t *)cur;
if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) {
linkedit_segment = cur_seg_cmd;
}
} else if (cur_seg_cmd->cmd == LC_SYMTAB) {
symtab_cmd = (struct symtab_command*)cur_seg_cmd;
} else if (cur_seg_cmd->cmd == LC_DYSYMTAB) {
dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd;
}
}
if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment ||
!dysymtab_cmd->nindirectsyms) {
return;
}
// Find base symbol/string table addresses
uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
//linkedit_base+symtab_cmd->symoff是Symbol Table的位置
nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
//linkedit_base+symtab_cmd->stroff是String Table的位置
char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
// Get indirect symbol table (array of uint32_t indices into symbol table)
uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);
cur = (uintptr_t)header + sizeof(mach_header_t);
for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
cur_seg_cmd = (segment_command_t *)cur;
if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
//找到DATA和DATA_CONST segment
if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 &&
strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) {
continue;
}
for (uint j = 0; j < cur_seg_cmd->nsects; j++) {
//找到__nl_symbol_ptr和__la_symbol_ptr这两个section
section_t *sect =
(section_t *)(cur + sizeof(segment_command_t)) + j;
if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {
perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
}
if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) {
perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
}
}
}
}
}
//完成动态库的binding之后,会回调这个函数。其中slide跟ALSR(Address space layout randomization)有关系,是一个随机的加载地址。
static void _rebind_symbols_for_image(const struct mach_header *header,
intptr_t slide) {
Dl_info image_info;
int result = dladdr(header, &image_info);
if (result == 0) {
printf("Could not print info for mach_header: %p\n\n", header);
return;
}
printf("added dylib: %s\n", image_info.dli_fname);
rebind_symbols_for_image(_rebindings_head, header, slide);
}
int rebind_symbols_image(void *header,
intptr_t slide,
struct rebinding rebindings[],
size_t rebindings_nel) {
struct rebindings_entry *rebindings_head = NULL;
int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
rebind_symbols_for_image(rebindings_head, header, slide);
free(rebindings_head);
return retval;
}
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {
int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel);
if (retval < 0) {
return retval;
}
// If this was the first call, register callback for image additions (which is also invoked for
// existing images, otherwise, just run on existing images
if (!_rebindings_head->next) {
//启动的时候做函数替换
_dyld_register_func_for_add_image(_rebind_symbols_for_image);
} else {
uint32_t c = _dyld_image_count();
for (uint32_t i = 0; i < c; i++) {
//启动之后也可以做函数替换,非常强大。
_rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
}
}
return retval;
}
通过日志可以看出,主程序和所有动态库的open和close都被替换掉了。
dylib: /Users/henshao/Library/Developer/CoreSimulator/Devices/BFC573F8-E181-4C9F-92CC-87F5E06F5B3C/data/Containers/Bundle/Application/C1226A56-043D-4029-B034-2B8D85C1D3CE/FishHookTest.app/FishHookTest
sectname: __nl_symbol_ptr, segname: __DATA
size: 16
symbol_name: dyld_stub_binder
sectname: __got, segname: __DATA
size: 8
symbol_name: ___stack_chk_guard
sectname: __la_symbol_ptr, segname: __DATA
size: 200
symbol_name: _NSStringFromClass
symbol_name: _objc_autoreleasePoolPop
symbol_name: _objc_autoreleasePoolPush
symbol_name: _objc_msgSend
symbol_name: _objc_msgSendSuper2
symbol_name: _objc_release
symbol_name: _objc_retainAutoreleasedReturnValue
symbol_name: _objc_storeStrong
symbol_name: ___memcpy_chk
symbol_name: ___stack_chk_fail
symbol_name: __dyld_get_image_header
symbol_name: __dyld_get_image_vmaddr_slide
symbol_name: __dyld_image_count
symbol_name: __dyld_register_func_for_add_image
symbol_name: _close
symbol_name: _dladdr
symbol_name: _free
symbol_name: _malloc
symbol_name: _memset
symbol_name: _open
symbol_name: _printf
symbol_name: _read
symbol_name: _strcmp
symbol_name: _strnlen
symbol_name: _UIApplicationMain
网友评论