1 otool

otool 命令行工具用来查看 Mach-O 文件的结构。

1.1 查看文件头

otool -h -v 文件路径

-h选项表明查看 Mach-O 文件头。

-v 选项表明将展示的内容进行"符号化"处理。

上面命令行输出的一个例子如下:

magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64 ARM64 ALL 0x00 EXECUTE 23 3752 NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE

从输出结果可以看出,完全符合 XNU 内核头文件loader.h中定义的struct mach_header_64的结构:

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 */
};

如果命令行没有加 -v选项,输出的结果会是这样:

 magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
0xfeedfacf 16777228 0 0x00 2 23 3752 0x00218085

可以看到,使用-v 选项输出结果会更让人易读。

如果一个 Mach-O 文件是 Universal 类型的,也就是包含多重架构(一般 .o 目标文件或者静态库会是 Universal 的,包含 ARM 和 X86_64 两种架构),使用-h选项只会输出其中一种架构的头信息。

想要将所有架构头信息都输出,需要使用-f选项:

otool -f -v 文件路径

上面命令行输出的一个例子是:

Fat headers
fat_magic FAT_MAGIC
nfat_arch 2
architecture x86_64
cputype CPU_TYPE_X86_64
cpusubtype CPU_SUBTYPE_X86_64_ALL
capabilities 0x0
offset 48
size 36752
align 2^3 (8)
architecture arm64
cputype CPU_TYPE_ARM64
cpusubtype CPU_SUBTYPE_ARM64_ALL
capabilities 0x0
offset 36800
size 37384
align 2^3 (8)

1.2 查看汇编代码

otool -t -v 文件路径

-t选项会展示 (__TEXT, __text) Section 的内容。

-v选项会反汇编展示的内容,展示汇编代码,前提是待展示的内容是代码指令。

上面命令行输出的一个例子是:

(__TEXT,__text) section
0000000100004000 sub sp, sp, #0x30
0000000100004004 stp x20, x19, [sp, #0x10]
0000000100004008 stp x29, x30, [sp, #0x20]
000000010000400c add x29, sp, #0x20
0000000100004010 adrp x8, 12 ; 0x100010000
0000000100004014 ldr x9, [x8]
0000000100004018 add x9, x9, #0x1
000000010000401c str x9, [x8]
0000000100004020 add x19, x3, x2
0000000100004024 str x19, [sp]
0000000100004028 adrp x0, 8 ; 0x10000c000
000000010000402c add x0, x0, #0x1f0 ; Objc cfstring ref: @"bad cfstring ref"
0000000100004030 bl 0x100007c68 ; symbol stub for: _NSLog
0000000100004034 mov x0, x19
0000000100004038 ldp x29, x30, [sp, #0x20]
000000010000403c ldp x20, x19, [sp, #0x10]
0000000100004040 add sp, sp, #0x30
0000000100004044 ret

上面汇编代码最左边的列是指令的地址。

上面命令行会将 (__TEXT, __text) Section 全部反汇编,如果内容较长不容易查看,因此最好结合more命令:

otool -t -v 文件路径 | more

如果想展示汇编代码的同时,展示汇编指令的编码以及指令的偏移量,可以结合-j-function_offsets选项:

otool -t -v -j -function_offsets 文件路径

-j选项展示汇编指令的编码。

-function_offsets选项展示指令的偏移量。

上面命令行输出的一个例子是:

(__TEXT,__text) section
+0 0000000100004000 d100c3ff sub sp, sp, #0x30
+4 0000000100004004 a9014ff4 stp x20, x19, [sp, #0x10]
+8 0000000100004008 a9027bfd stp x29, x30, [sp, #0x20]
+12 000000010000400c 910083fd add x29, sp, #0x20
+16 0000000100004010 90000068 adrp x8, 12 ; 0x100010000
+20 0000000100004014 f9400109 ldr x9, [x8]
+24 0000000100004018 91000529 add x9, x9, #0x1
+28 000000010000401c f9000109 str x9, [x8]
+32 0000000100004020 8b020073 add x19, x3, x2
+36 0000000100004024 f90003f3 str x19, [sp]
+40 0000000100004028 90000040 adrp x0, 8 ; 0x10000c000
+44 000000010000402c 9107c000 add x0, x0, #0x1f0 ; Objc cfstring ref: @"bad cfstring ref"
+48 0000000100004030 94000f0e bl 0x100007c68 ; symbol stub for: _NSLog
+52 0000000100004034 aa1303e0 mov x0, x19
+56 0000000100004038 a9427bfd ldp x29, x30, [sp, #0x20]
+60 000000010000403c a9414ff4 ldp x20, x19, [sp, #0x10]
+64 0000000100004040 9100c3ff add sp, sp, #0x30
+68 0000000100004044 d65f03c0 ret

上面输出从左起第 1 列是汇编指令偏移量,第 2 列是指令地址,第 3 列是指令的编码。

1.3 查看不同架构的汇编代码

对于 Universal 类型的 Mach-O 文件,可以使用-arch选项查看指定架构的汇编代码,命令如下:

otool -t -v -arch arm64 文件路径
otool -t -v -arch x86_x64 文件路径

-arch选项指定架构,arm64 表示 64bit 的 ARM CPU 架构,x86_64 表示 64bit 的 Intel x86_64 CPU 架构。

-arch选项的值除了可以是 arm64 和 x86_64,其他的值可以通过下面命令行的输出查看:

man 3 arch

上面命令行输出的一部分结果如下所示:

The currently known architectures are:

     Name          CPU Type              CPU Subtype                 Description
x86_64 CPU_TYPE_X86_64 CPU_SUBTYPE_X86_64_ALL Intel x86-64
i386 CPU_TYPE_I386 CPU_SUBTYPE_I386_ALL Intel 80x86
arm CPU_TYPE_ARM CPU_SUBTYPE_ARM_ALL ARM
arm64 CPU_TYPE_ARM64 CPU_SUBTYPE_ARM64_ALL ARM64
arm64e CPU_TYPE_ARM64 CPU_SUBTYPE_ARM64E ARM64E
arm64_32 CPU_TYPE_ARM64_32 CPU_SUBTYPE_ARM64_32_V8 ARM64_32
ppc CPU_TYPE_POWERPC CPU_SUBTYPE_POWERPC_ALL PowerPC

1.4 按符号查看汇编代码

如果 Mach-O 文件是 DEBUG 类型,或者虽然是 Relese 类型但是没有设置 Xcode 的如下 Build Setting:



那么就可以使用-p选项使用符号查看汇编代码。

otool -t -v -p "-[X addi:d:]" 文件路径

上面命令行会从符号-[X addi:d:]开始进行反汇编,一直展示到 (__TEXT, __text) Section 末尾,输出内容如下:

(__TEXT,__text) section
-[X addi:d:]:
0000000100004134 sub sp, sp, #0x30
0000000100004138 str x0, [sp, #0x28]
000000010000413c str x1, [sp, #0x20]
0000000100004140 str x2, [sp, #0x18]
0000000100004144 str d0, [sp, #0x10]
0000000100004148 adrp x9, 12 ; 0x100010000
000000010000414c ldr x8, [x9, #0x18]
0000000100004150 add x8, x8, #0x1
0000000100004154 str x8, [x9, #0x18]
0000000100004158 ldr d0, [sp, #0x18]
000000010000415c scvtf d0, d0
0000000100004160 ldr d1, [sp, #0x10]
0000000100004164 fadd d0, d0, d1
0000000100004168 str d0, [sp, #0x8]
000000010000416c ldr d0, [sp, #0x8]
0000000100004170 add sp, sp, #0x30
0000000100004174 ret

1.5 查看指定 Section

otool 可以通过-s选项查看指定的 Section,-s选项的值形式为-s segmentName sectionName:

otool -v -s __TEXT __text 文件路径

上面命令行查看 (__TEXT, __text) Section 的内容

otool -s __DATA __data 文件路径

上面命令行查看 (__DATA, __data) Section 的内容。

1.6 查看间接符号表

间接符号表是程序加载是动态连接器 dyld 会使用到符号表,动态链接器使用这个符号表来完成符号的绑定。otool 可以使用-I选项来查看间接符号表:

otool -I -v 文件路径

-I选项表明查看间接符号表。

-v选项会让展示的结果更详细,更易读。

上面命令行输出的一个例子是:

Indirect symbols for (__TEXT,__stubs) 50 entries
address index name
0x0000000100007c68 4 _NSLog
0x0000000100007c74 5 _NSStringFromClass
0x0000000100007c80 13 _UIApplicationMain
0x0000000100007c8c 15 ___error
0x0000000100007c98 16 ___stack_chk_fail
0x0000000100007ca4 20 _atexit
0x0000000100007cb0 21 _atoi

上面输出从左起address代表符号的地址,index代表该符号在符号表里的索引(符号表里有所有符号),name是符号名。

1.7 查看 Load Commands

otool 可以使用-l选项查看 Mach-O 中的 Load Commands:

otool -l 文件路径

1.8 查看依赖的动态库

otool 可以使用-L选项查看当前 Mach-O 依赖的动态库:

otool -L 文件路径

一个输出例子如下:

/System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 2048.1.101)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.0.0)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 2048.1.101)
/System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 7082.1.111)

更多 otool 功能可以参考man otool的输出内容。

2 objdump

由于历史原因,苹果使用曾经使用 objdump 展示 Mach-O 信息,因此 objdump 与 otool 许多功能类似。

2.1 查看文件头

objdump -m --private-header 文件路径

-m选项表明是查看 Mach-O 文件。

--private-header表明查看 Mach-O 文件头。

这个命令类似 otool 的otool -h -v

如果想要查看 Univeral 类型 Mach-O 的文件头,可以使用:

objdump -m --universal-headers 文件路径

-m选项表明是查看 Mach-O 文件。

--universal-headers表明显示 Mach-O 文件中所有架构的文件头。

这个命令类似 otool 的otool -f -v

2.2 查看汇编代码

objdump 支持按照指定的地址范围显示汇编代码,这个功能在实际中很有用处:

objdump -d --start-address=起始地址 --stop-address=结束地址 文件路径

-d选项表明要执行反汇编。

--start-address选项是反汇编的起始地址。

--stop-address选项是反汇编的结束地址,需要注意的是,反汇编内容不包含 --stop-address 指定的地址,也就是说反汇编的范围是[--start-address, --stop-address)。

上面命令行输出的一个例子如下:

Disassembly of section __TEXT,__text:

0000000100004000 <__text>:
100004000: d100c3ff sub sp, sp, #48
100004004: a9014ff4 stp x20, x19, [sp, #16]
100004008: a9027bfd stp x29, x30, [sp, #32]
10000400c: 910083fd add x29, sp, #32
100004010: 90000068 adrp x8, 0x100010000 <__text+0x40>
100004014: f9400109 ldr x9, [x8]
100004018: 91000529 add x9, x9, #1
10000401c: f9000109 str x9, [x8]

上面输出从左起第 1 列是汇编指令的地址,第 2 类是指令的编码。和 otool 不同,objdump 默认就显示汇编指令的编码。如果不想显示汇编指令编码,加入--no-show-raw-insn选项即可。

objdump 不支持展示汇编代码时,显示偏移量。

如果反汇编时只有-d选项,那么 objdump 会反汇编所有可执行的代码。

2.3 查看不同结构的汇编代码

objdump 可以使用--arch选项,选择不同的架构进行反汇编:

objdump -d --arch=arm64 文件路径
objdump -d --arch=x86_64 文件路径

--arch选项指明 CPU 架构,架构名和 otool 一样,可以使用man 3 arch查看。

2.4 按符号查看汇编代码

和 otool 类似,objdump 支持按照符号进行反汇编:

objdump --disassemble-symbols="符号1","符号2"... 文件路径

--disassemble-symbols选项可以有多个符号,符号之间使用逗号间隔。

2.5 反汇编时加入源码行号信息

如果有 DSYM 文件,那么使用 objdump 进行反汇编时,可以显示源码行号信息:

objdump -l --dsym=DSYM文件路径 文件路径

-l选项表明反汇编时展示源码行号信息。

--dsym选项指定 DSYM 文件路径。需要注意的是,需要在 DSYM 文件上右键'Show Package Contents',然后依次进入 Contents->Resources->DWARF 目录,然后给目录里面的文件添加.app后缀,否则会报如下错误:

上面命令行输出的一个例子如下图所示:

2.6 查看指定的 Section

objdump 通过-j选项查看指定的 Section:

objdump -m -j segmentName,sectionName 文件路径

-m选项表明查看 Mach-O 文件。

-j选项指定要查看的 Section,比如 __TEXT,__text __DATA,__data。

这个命令类似 otool 的otool -s

2.7 查看间接符号表

objdump 可以查看间接符号表:

objdump -m --indirect-symbols 文件路径

-m选项表明查看 Mach-O 文件

--indirect-symbols选项表明查看间接符号表。

这个命令类似 otool 的otool -Iv,输出的格式也类似:

Indirect symbols for (__TEXT,__stubs) 50 entries
address index name
0x0000000100007c68 4 _NSLog
0x0000000100007c74 5 _NSStringFromClass
0x0000000100007c80 13 _UIApplicationMain
0x0000000100007c8c 15 ___error
0x0000000100007c98 16 ___stack_chk_fail
0x0000000100007ca4 20 _atexit

2.8 查看符号表

objdump 可以直接查看整个符号表:

objdump -t 文件路径

其输出格式如下:

SYMBOL TABLE:
0000000005614542 d *UND* .hidden radr://5614542
000000010000d878 w O __DATA,__data ___llvm_profile_filename
000000010000d880 w O __DATA,__data ___llvm_profile_raw_version
0000000100000000 g F __TEXT,__text __mh_execute_header
0000000000000000 *UND* _NSLog
0000000000000000 *UND* _NSStringFromClass
0000000000000000 *UND* _OBJC_CLASS_$_NSObject
0000000000000000 *UND* _OBJC_CLASS_$_UIResponder
0000000000000000 w *UND* _OBJC_CLASS_$_UISceneConfiguration
0000000000000000 *UND* _OBJC_CLASS_$_UIViewController
0000000000000000 *UND* _OBJC_METACLASS_$_NSObject
0000000000000000 *UND* _OBJC_METACLASS_$_UIResponder
0000000000000000 *UND* _OBJC_METACLASS_$_UIViewController
0000000000000000 *UND* _UIApplicationMain
0000000000000000 *UND* ___CFConstantStringClassReference
0000000000000000 *UND* ___error
0000000000000000 *UND* ___stack_chk_fail
0000000000000000 *UND* ___stack_chk_guard
0000000000000000 *UND* ___stderrp
0000000000000000 *UND* __objc_empty_cache
0000000000000000 *UND* _atexit
0000000000000000 *UND* _atoi

从输出上可以看出来,按照间接符号表的index列可以对应到符号表里。比如 __NSLog在间接符号表的index 为 5,符号表的第 5 项(符号表索引以 0 开始),正好是__NSLog

2.9 查看 Load Commands

objdump 可以查看 Load Commands:

objdump -m -x 文件路径

-m表明要查看 Mach-O 文件。

-x表明展示 Load Commands。

这个命令类似 otool 的otool -l

2.10 查看依赖的动态库

objdump 可以查看依赖的动态:

objdump -m --dylibs-used 文件路径

-m选项表明要查看 Mach-O 文件。

--dylibs-used选项表明查看依赖的动态库。

这个命令类似 otool 的otool -L

2.11 Demangle Symbol

源代码中的符号在编译之后,会被编译器混淆:

objdump 支持将混淆的符号还原:

objdump -C 文件路径

-C选项表明要还原混淆的符号。

上图中混淆的符号还原之后:

3 od

od 命令可以用来查看二进制的内容,可以用它来查看 Mach-O 文件的原始字节。

3.1 指定展示格式

od -A x -t x 文件路径

-A选项表明地址是用 10(d) 进制、8(o) 进制、16(x) 进制展示,默认使用 8 进制展示。

-t选项表明用哪种进制展示内容,可以是 10(d) 进制、8(o) 进制、16(x) 进制,默认是 8 进制。

上面命令行输出的一个例子是:

上图从左边起第 1 列就是地址或者说字节的偏移量更准确,其他列都是 Mach-O 文件的内容,可以看到第 2 列第 1 行 feedfacf 正式 Mach-O 里面的魔数。

选项-t 值后面还可以接一个 10 进制数,表示按多少个字节一组展示内容,比如-t x1就表示一个字节一个字节的展示文件内容:

od -A x -t x1 文件路径

上面命令行输出的例子如下:

从上图红框可以看到,Mach-O 文件是小端在前(Little-Endian)字节序。

3.2 跳过部分字节

od 支持跳过指定的字节数然后展示:

od -A x -t x -j 0x4000 文件路径

-j选项表明跳过多少字节,上面例子中要跳过 0x4000 个字节。

4 dwarfdump

dwarfdump 用来查看 DWARF 文件内容。

4.1 查看 UUID

dwarfdump 可以查看任何一个 Mach-O 文件的 UUID,这在分析崩溃堆栈时十分有用:

dwarfdump --uuid 文件路径

4.2 查找地址对应的符号信息

dwarfdump 可以查找地址对应的符号信息:

dwarfdump --lookup=地址 文件路径

--lookup选项后面是要查找的符号地址。

上面命令行一个输出的例子为:

当在分析崩溃信息时,可以使用这个方法找到地址对应的函数名。

4.3 查找符号名对应的信息

dwarfdump 可以查找符号名对应的详细信息:

dwarfdump -f 符号名 文件路径

-f选项后面是要查询的符号名,比如:

dwarfdump -f "-[X add:j:]" 文件路径

输出的结果如下:

当在分析崩溃信息时,可以用这个方法反查崩溃函数的地址,然后使用 objdump 工具查看崩溃地址的具体汇编代码。

Mach-O Inside: 命令行工具集 otool objdump od 与 dwarfdump的更多相关文章

  1. 从零开始打造个人专属命令行工具集——yargs完全指南

    前言 使用命令行程序对程序员来说很常见,就算是前端工程师或者开发gui的,也需要使用命令行来编译程序或者打包程序 熟练使用命令行工具能极大的提高开发效率,linux自带的命令行工具都非常的有用,但是这 ...

  2. 基于node和npm的命令行工具——tive-cli

    前端开发过程中经常会用到各种各样的脚手架工具.npm全局工具包等命令行工具,如:Vue脚手架@vue/cli.React脚手架create-react-app.node进程守卫工具pm2.本地静态服务 ...

  3. 命令行工具解析Crash文件,dSYM文件进行符号化

    备份   文/爱掏蜂窝的熊(简书作者)原文链接:http://www.jianshu.com/p/0b6f5148dab8著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 序 在日常开发 ...

  4. 转:windows下命令行工具

    转自: http://www.cnblogs.com/haochuang/p/5593411.html Windows下CMD不好用,远没有Linux,或者一些SSH工具用起来方便.其实Windows ...

  5. JVM性能监控与故障处理命令行工具

    JDK命令行工具 Sun公司作为”礼物“赠送给JDK使用者的工具: 这些命令行工具大多是jdk/lib/tools.jar类库的一层薄包装,主要功能代码是在tools类库(不属于java的标准API) ...

  6. 10款Windows命令行工具

    Windows下CMD不好用,远没有Linux,或者一些SSH工具用起来方便.其实Windows下,也有一些不错的工具替代CMD: 0.powercmd经过比较,我最终选择了这款,这里补充一下截图:

  7. 微软开放技术发布针对 Mac 和 Linux 的更新版 Azure Node.JS SDK 和命令行工具

    发布于 2013-12-04 作者 Eduard Koller 这次为我们使用Linux 的朋友带来了更多关于部署云上虚拟机的消息.今天,微软开放技术有限公司 (MS Open Tech),想与大家分 ...

  8. 显示器 Linux 性能 18 (一个命令行工具传递)

    对于系统和网络管理员来说每天监控和调试Linux系统的性能问题是一项繁重的工作.在IT领域作为一名Linux系统的管理员工作5年后,我逐渐认识到监控和保持系统启动并执行是多么的不easy.基于此原因. ...

  9. 探索Windows命令行系列(2):命令行工具入门

    1.理论基础 1.1.命令行的前世今生 1.2.命令执行规则 1.3.使用命令历史 2.使用入门 2.1.启动和关闭命令行 2.2.执行简单的命令 2.3.命令行执行程序使用技巧 3.总结 1.理论基 ...

  10. Windows 编程,程序编译使用的命令行工具。

    Windows 编程,程序编译使用的命令行工具. 1.cl.exe文件是Visual C\C++的编译器,它将程序源代码文件编译为obj文件. 2.rc.exe文件是资源编译器.工程项目中的.rc文件 ...

随机推荐

  1. 简单认识Promise

    什么是Promise Promise是异步编程的一个解决方案:从语法上讲它是一个对象,可以获取到异步操作的消息,从本意上讲,它是一个承诺,承诺过一段时间后它会给你一个结果.Promise有三种状态:p ...

  2. CF371D Vessels题解

    思路: 定义一个权值并查集,权值保存这个集合还可以存下多少水. 如果这个集合可以存放的水已经小于要装入的水,就将这个集合与下一个集合合并. 否则,直接把这个集合可以存放的水减去要装入的水的体积. 代码 ...

  3. MAUI+MASA Blazor 兼容性测试报告及分析

    目录 1. 背景 2. 目的 3. 测试目标 4. 预期结果 5. 测试策略及范围 6. 测试结果与分析 7. 附加内容 8. 结尾 1. 背景 MASA Blazor组件是一款基于Material ...

  4. linux文本编辑YCM报错

    linux文本编辑YCM报错 刚从github安装了vimplus,可是发现存在不少的问题.索性给直接记录一下. The ycmd server SHUT DOWN (restart with ':Y ...

  5. excel:if语句

    IF语法格式: IF(logical_test,value_if_true,value_if_false) 释义:判断一个条件是否满足,如果满足返回一个值,如果不满足则返回另一个值. logical_ ...

  6. vlunhub笔记(二)earth

    (一)信息收集 开始扫描目标机ip,目标机ip:192.168.241.135 arp-scan -l 直接访问目标  ip 192.168.241.135   发现400报错 只能先去考虑扫一下信息 ...

  7. PB从入坑到放弃(六)动态SQL应用

    写在前面 动态 SQL 语句是部分或者整个 SQL 语句在运行时才能确定,可以更好的与用户进行交互,大大提高了SQL的灵活性 一.执行SQL语句 1.1 执行无入参SQL ① 语法 EXECUTE I ...

  8. 利用pytorch准备数据集、构建与训练、保存与加载CNN模型

    本文的主要内容是利用pytorch框架与torchvision工具箱,进行准备数据集.构建CNN网络模型.训练模型.保存和加载自定义模型等工作.本文若有疏漏.需更正.改进的地方,望读者予以指正,如果本 ...

  9. Unity的UnityStats: 属性详解与实用案例

    UnityStats 属性详解 UnityStats 是 Unity 引擎提供的一个用于监测游戏性能的工具,它提供了一系列的属性值,可以帮助开发者解游戏的运行情况,从而进行优化.本文将详细介绍 Uni ...

  10. 推荐一款免费好用的远程桌面:Getscreen

    因为平时有多台设备要用,所以远程桌面是我经常要使用的工具. 最近,正好看到一款不错的远程桌面软件,马上拿出来推荐给大家,如果有需要的可以看看. 今天要推荐的远程桌面软件就是这款叫Getscreen的软 ...