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

相关推荐
ZacJi5 小时前
当苹果将系统 API 划归 @MainActor:一次跨 SDK 版本的 Swift 并发踩坑与破局实战
ios·swift
mardelan5 小时前
2026年iOS短视频总结工具测评强识别提效率 整理清晰更省心
ios·音视频
ZZH_AI项目交付8 小时前
638 处旧名称残留——Swift/ObjC 混编项目安全重命名完整指南
ios·objective-c·swift
ZZH_AI项目交付8 小时前
Apple Silicon 模拟器遇到旧版 MLKit:一次完整的依赖排查
ios·app·编译器
kango8 小时前
iOS 项目工程化构成与 Xcode 架构详解
ios·程序员
2501_9159184110 小时前
iOS 怎么抓包?抓包鹰系统级 网卡 应用层三种方式对比,不越狱抓 iPhone 流量
网络协议·计算机网络·网络安全·ios·adb·https·udp
ZZH_AI项目交付12 小时前
一个 33,623 字节的 ViewController——拆开它我用了四步
ios·app·apple
2501_9160088912 小时前
移动安全之 APP 加固,保障移动应用安全的重要手段
安全·macos·ios·小程序·uni-app·iphone·xcode
鹤卿12312 小时前
「iOS」天气预报仿写总结
ui·ios·objective-c
2501_9151063217 小时前
Python爬虫从零开始:七天掌握HTTP协议、数据解析与反爬策略
android·ios·小程序·https·uni-app·iphone·webview