详解Mach-O(五)Mach-O LC_SYMTAB

Mach-O LC_SYMTAB 详解

LC_SYMTAB 是 Mach-O 文件中用于描述符号表(Symbol Table)的加载命令。符号表包含了程序中定义和引用的函数、变量等符号信息,是链接和调试过程中的关键数据结构。

LC_SYMTAB 结构

LC_SYMTAB 使用 symtab_command结构来描述符号表的信息:

c 复制代码
struct symtab_command {
    uint32_t    cmd;        /* LC_SYMTAB */
    uint32_t    cmdsize;    /* sizeof(struct symtab_command) */
    uint32_t    symoff;     /* 符号表在文件中的偏移 */
    uint32_t    nsyms;      /* 符号数量 */
    uint32_t    stroff;     /* 字符串表在文件中的偏移 */
    uint32_t    strsize;    /* 字符串表大小 */
};

字段详解

1. cmd 和 cmdsize

  • cmd:命令类型,值为 LC_SYMTAB
  • cmdsize:命令大小,固定为 sizeof(struct symtab_command)

2. symoff 和 nsyms

  • symoff:符号表在文件中的字节偏移量
  • nsyms:符号表中符号的数量

3. stroff 和 strsize

  • stroff:字符串表在文件中的字节偏移量
  • strsize:字符串表的大小(字节数)

符号表结构

符号表中的每个符号使用 nlist或 nlist_64结构表示:

32位 nlist 结构

c 复制代码
struct nlist {
    union {
        uint32_t  n_strx;   /* 字符串表索引 */
    } n_un;
    uint8_t  n_type;        /* 符号类型 */
    uint8_t  n_sect;        /* 符号所在节 */
    int16_t  n_desc;        /* 符号描述 */
    uint32_t n_value;       /* 符号值/地址 */
};

64位 nlist_64 结构

c 复制代码
struct nlist_64 {
    union {
        uint32_t  n_strx;   /* 字符串表索引 */
    } n_un;
    uint8_t  n_type;        /* 符号类型 */
    uint8_t  n_sect;        /* 符号所在节 */
    uint16_t n_desc;        /* 符号描述 */
    uint64_t n_value;       /* 符号值/地址 */
};

符号字段详解

1. n_strx(字符串索引)

指向字符串表中的索引,通过该索引可以找到符号的名称字符串。

2. n_type(符号类型)

符号的类型和属性信息,包括:

  • N_UNDF:未定义符号
  • N_ABS:绝对符号
  • N_SECT:节定义符号
  • N_PBUD:预绑定未定义符号
  • N_INDR:间接符号

通过位运算可以获取更多属性:

  • N_EXT:外部符号位
  • N_STAB:调试符号位

3. n_sect(节索引)

当符号类型为 N_SECT 时,该字段表示符号所在的节索引。值从1开始,NO_SECT(0)表示符号不在任何节中。

4. n_desc(符号描述)

符号的附加描述信息,包括:

  • 引用类型(reference type)
  • 库序号(library ordinal)
  • 符号属性(如弱引用、私有符号等)

5. n_value(符号值)

符号的值或地址,具体含义取决于符号类型:

  • 对于节定义符号,表示符号的地址
  • 对于未定义符号,通常为0
  • 对于调试符号,可能表示偏移量

字符串表

字符串表是一个连续的字符序列,存储所有符号的名称。每个字符串以null字符('\0')结尾。符号结构中的 n_strx 字段是字符串在字符串表中的索引。

例如,如果字符串表内容为:

复制代码
"\0_main\0_printf\0_hello\0"

那么:

  • 索引0:""(空字符串)
  • 索引1:"main"
  • 索引6:"printf"
  • 索引13:"hello"

工作原理

当链接器或调试器需要处理 Mach-O 文件时:

  1. 通过 LC_SYMTAB 命令找到符号表和字符串表在文件中的位置
  2. 读取符号表中的每个符号条目
  3. 通过符号条目中的 n_strx 索引在字符串表中查找符号名称
  4. 根据符号类型和值进行相应的处理

实际应用示例

使用 otool 查看符号表

bash 复制代码
# 查看符号表
otool -s __LINKEDIT [offset] executable_file

# 查看LC_SYMTAB信息
otool -l executable_file | grep -A 6 LC_SYMTAB

使用 nm 查看符号

bash 复制代码
# 列出所有符号
nm executable_file

# 列出详细符号信息
nm -a executable_file

示例输出:

复制代码
0000000100000f40 T _main
0000000100000f80 t _hello
                 U _printf

其中:

  • T:在文本(代码)节中的外部符号
  • t:在文本(代码)节中的本地符号
  • U:未定义的外部符号

与其他命令的关系

LC_SYMTAB vs LC_DYSYMTAB

  • LC_SYMTAB:描述基本的符号表信息
  • LC_DYSYMTAB:描述动态链接器使用的额外符号表信息,如间接符号表等

在 __LINKEDIT 段中

符号表和字符串表通常存储在 __LINKEDIT 段中,该段包含链接和调试所需的各种信息。

重要性

LC_SYMTAB 是 Mach-O 文件中非常重要的加载命令,它:

  1. 为静态链接器和动态链接器提供符号解析所需的信息
  2. 为调试器提供符号到源代码的映射
  3. 支持动态库的符号绑定过程
  4. 是程序运行时符号查找的基础

理解 LC_SYMTAB 对于进行逆向工程、安全分析、调试和开发底层系统工具非常重要。它是程序链接和调试机制的核心数据结构之一。

相关推荐
YJlio5 小时前
1.7 通过 Sysinternals Live 在线运行工具:不下载也能用的“云端工具箱”
c语言·网络·python·数码相机·ios·django·iphone
小白同学_C5 小时前
Lab4-Lab: traps && MIT6.1810操作系统工程【持续更新】 _
linux·c/c++·操作系统os
2501_9419820516 小时前
Go 开发实战:基于 RPA 接口的主动消息推送
ios·iphone
雪域迷影16 小时前
MacOS下源码安装SDL3并运行hello.c示例程序
c语言·开发语言·macos·sdl3
忆江南17 小时前
Swift 全面深入指南
ios
00后程序员张19 小时前
iOS 应用代码混淆,对已编译 IPA 进行类与方法混淆
android·ios·小程序·https·uni-app·iphone·webview
YJlio19 小时前
1.6 使用 Streams 工具移除下载文件的 ADS 信息:把“来自互联网”的小尾巴剪掉
c语言·网络·python·数码相机·ios·django·iphone
_OP_CHEN20 小时前
【算法基础篇】(六十)Nim 博弈超全解析:从基础原理到经典变种,玩转多堆取石子问题
算法·蓝桥杯·c/c++·博弈论·算法竞赛·acm、icpc·nim博弈
文件夹__iOS20 小时前
Swift 性能优化:Copy-on-Write(COW) 与懒加载核心技巧
开发语言·ios·swift