使用 readelf 分析 so 文件:ELF 结构解析全攻略

版权归作者所有,如有转发,请注明文章出处:cyrus-studio.github.io/blog/

readelf 介绍

readelf 是 GNU Binutils 提供的一个命令行工具,专门用于读取 ELF(Executable and Linkable Format)文件的结构信息。

readelf 文档:man7.org/linux/man-p...

GNU Binutils

GNU Binutils(GNU Binary Utilities)是一套由 GNU 项目维护的二进制文件处理工具集,主要用于编译、链接、反汇编、调试等场景。

它是 GCC(GNU Compiler Collection)的重要配套组件之一,处理从编译生成的目标文件到最终可执行文件的各个阶段。

主要工具:

工具 作用
as GNU 汇编器(GNU Assembler),把 .s 汇编代码编译成 .o 目标文件
ld GNU 链接器(GNU Linker),把多个 .o 文件和库打包成可执行文件或共享库
ar 归档工具(创建/修改 .a 静态库)
nm 显示符号表(Symbol Table)
objdump 显示目标文件内容(反汇编、节表、符号、重定位等)
objcopy 复制并转换目标文件格式(可用于提取或删除节)
readelf 专门查看 ELF 文件结构(文件头、节表、符号等)
strip 删除二进制文件中的符号信息(瘦身/混淆)
strings 搜索二进制文件中的可打印字符串
size 显示目标文件中各段的大小(text/data/bss)
ranlib 为 .a 静态库生成索引(方便快速链接)

Windows 下使用 readelf

虽然 readelf 工具本身是为 Unix-like 操作系统设计的,在 Windows 上通过 WSL 使用它。WSL 允许你在 Windows 上运行 Linux 发行版,并且可以在其中使用 readelf 工具。

打开 PowerShell 以管理员身份运行,并执行以下命令启用 WSL 并安装 Ubuntu 系统

css 复制代码
wsl --install -d Ubuntu

然后设置用户账户和密码。

通过 wsl 命令进入 Ubuntu 系统。

bash 复制代码
(base) PS E:\> wsl
wsl: Unknown key 'wsl2.memory' in /etc/wsl.conf:5
wsl: Unknown key 'wsl2.swap' in /etc/wsl.conf:6
wsl: 检测到 localhost 代理配置,但未镜像到 WSL。NAT 模式下的 WSL 不支持 localhost 代理。
wsl: Processing /etc/fstab with mount -a failed.
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.153.1-microsoft-standard-WSL2 x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage


This message is shown once a day. To disable it please create the
/home/cyrus/.hushlogin file.
cyrus@*:/mnt/e$ cd /mnt/d/Python/anti-app

在 wsl 中 /mnt/d 对应的就是 windows 下的 D 盘,其他同理。

使用 readelf 分析 so 文件

调用 readelf -a 一次性查看文件中的所有信息,包括文件头、程序头、节头、符号表、动态节等。

css 复制代码
readelf -a libGameVMP.so

输出如下:

csharp 复制代码
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00   # ELF 魔数(前 4 个字节 0x7f 'E' 'L' 'F' 表示 ELF 文件格式),后面是 class/endianness/version 等
  Class:                             ELF64                   # 文件是 64 位 ELF
  Data:                              2's complement, little endian  # 使用小端字节序
  Version:                           1 (current)              # ELF 格式版本
  OS/ABI:                            UNIX - System V          # 目标 ABI 是 System V
  ABI Version:                       0                        # ABI 版本号
  Type:                              DYN (Shared object file)  # 文件类型是 DYN(共享库 .so)
  Machine:                           AArch64                   # 目标架构是 AArch64 (ARM 64-bit)
  Version:                           0x1                       # 再次确认 ELF 版本
  Entry point address:               0x2650                    # 程序入口点虚拟地址(so 通常不是 main,而是初始化代码)
  Start of program headers:          64 (bytes into file)      # 程序头表在文件中的偏移
  Start of section headers:          130160 (bytes into file)  # 节区头表的文件偏移
  Flags:                             0x0                       # 架构相关标志
  Size of this header:               64 (bytes)                # ELF Header 本身大小
  Size of program headers:           56 (bytes)                # 每个 program header 的大小
  Number of program headers:         7                         # program header 数量
  Size of section headers:           64 (bytes)                # 每个 section header 的大小
  Number of section headers:         7                         # Section Header 条目数
  Section header string table index: 1                         # 存储 section 名称的字符串表索引

Section Headers:   # 描述 ELF 文件的各个节(section)
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000   # 节 0 永远是 NULL,表示无效
       0000000000000000  0000000000000000           0     0     0
  [ 1] .shstrtab         STRTAB           000000000001fe30  0001fe30   # 节区名称字符串表
       0000000000000035  0000000000000000           0     0     0
  [ 2] .dynsym           DYNSYM           0000000000000518  00000518   # 动态符号表
       0000000000000048  0000000000000018   A       3     1     4
  [ 3] .dynstr           STRTAB           0000000000000ec0  00000ec0   # 动态符号表对应的字符串表
       0000000000000342  0000000000000000   A       0     0     0
  [ 4] .symtab           SYMTAB           000000000001fe65  0001fe65   # 静态符号表
       0000000000000048  0000000000000018   A       5     1     4
  [ 5] .strtab           STRTAB           000000000001fead  0001fead   # 静态符号表的字符串表
       000000000000002b  0000000000000000   A       0     0     1
  [ 6] .dynamic          DYNAMIC          000000000006eae8  0001dae8   # 动态段信息(动态链接器使用)
       0000000000000240  0000000000000008  AX       3     0     4
Key to Flags:  # 节的标志解释
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

There are no section groups in this file.  # 文件中没有 section group

Program Headers:   # 描述运行时内存布局(segment)
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000  # 第一个 LOAD 段(代码段等只读执行数据)
                 0x000000000001cba4 0x000000000001cba4  R E    0x10000
  LOAD           0x000000000001d9e8 0x000000000006e9e8 0x000000000006e9e8  # 第二个 LOAD 段(可读可写数据段)
                 0x00000000000021de 0x0000000000002418  RW     0x1000
  DYNAMIC        0x000000000001dae8 0x000000000006eae8 0x000000000006eae8  # 动态链接信息段
                 0x0000000000000240 0x0000000000000240  RW     0x8
  NOTE           0x00000000000001c8 0x00000000000001c8 0x00000000000001c8  # NOTE 段(如 Build ID)
                 0x0000000000000024 0x0000000000000024  R      0x4
  GNU_EH_FRAME   0x0000000000015634 0x0000000000056634 0x0000000000056634  # 异常处理帧(C++ 异常/栈展开信息)
                 0x0000000000001afc 0x0000000000001afc  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000  # 栈段(权限信息)
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x000000000001d9e8 0x000000000006e9e8 0x000000000006e9e8  # 只读段(防止 GOT 改写)
                 0x0000000000000618 0x0000000000000618  R      0x1

 Section to Segment mapping:  # 每个段包含的 section
  Segment Sections...
   00     .dynsym .dynstr 
   01     .dynamic 
   02     .dynamic 
   03     
   04     
   05     
   06     .dynamic 

Dynamic section at offset 0x1dae8 contains 32 entries:  # 动态段信息表
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [liblog.so]       # 依赖库
 0x0000000000000001 (NEEDED)             Shared library: [libandroid.so]
 0x0000000000000001 (NEEDED)             Shared library: [libz.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x000000000000000e (SONAME)             Library soname: [libGameVMP.so]   # 该库自己的 SONAME
 0x000000000000000c (INIT)               0x1bd68                           # 初始化函数地址
 0x0000000000000019 (INIT_ARRAY)         0x6e9e8                           # 初始化函数数组地址
 0x000000000000001b (INIT_ARRAYSZ)       216 (bytes)                       # 初始化函数数组大小
 0x000000000000001a (FINI_ARRAY)         0x6eac0                           # 析构函数数组地址
 0x000000000000001c (FINI_ARRAYSZ)       16 (bytes)                        # 析构函数数组大小
 0x0000000000000004 (HASH)               0x1f0                             # 哈希表地址
 0x0000000000000005 (STRTAB)             0xec0                             # 字符串表地址
 0x0000000000000006 (SYMTAB)             0x518                             # 符号表地址
 0x000000000000000a (STRSZ)              834 (bytes)                       # 字符串表大小
 0x000000000000000b (SYMENT)             24 (bytes)                        # 每个符号表项大小
 0x0000000000000003 (PLTGOT)             0x6ed28                           # PLT/GOT 表地址
 0x0000000000000002 (PLTRELSZ)           1488 (bytes)                      # PLT 重定位表大小
 0x0000000000000014 (PLTREL)             RELA                              # 重定位类型
 0x0000000000000017 (JMPREL)             0x1c78                            # 延迟绑定符号表地址
 0x0000000000000007 (RELA)               0x1330                            # 重定位表地址
 0x0000000000000008 (RELASZ)             2376 (bytes)                      # 重定位表大小
 0x0000000000000009 (RELAENT)            24 (bytes)                        # 每个重定位表项大小
 0x0000000000000018 (BIND_NOW)                                              # 表示启动时立即绑定
 0x000000006ffffffb (FLAGS_1)            Flags: NOW                        # 同上,立即解析
 0x000000006ffffffe (VERNEED)            0x12d0                            # 版本依赖表地址
 0x000000006fffffff (VERNEEDNUM)         3                                 # 版本依赖数量
 0x000000006ffffff0 (VERSYM)             0x1202                            # 版本符号表地址
 0x000000006ffffff9 (RELACOUNT)          76                                # RELA 表项数量
 0x0000000000000000 (NULL)               0x0                               # 表结束

There are no static relocations in this file.  # 没有静态重定位
To see the dynamic relocations add --use-dynamic to the command line.

The decoding of unwind sections for machine type AArch64 is not currently supported.  # 不支持 ARM64 的 unwind 解码

Symbol table '.dynsym' contains 3 entries:  # 动态符号表
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000002650     0 SECTION LOCAL  DEFAULT bad section index[ 10] 
     2: 000000000006ead0     0 SECTION LOCAL  DEFAULT bad section index[ 16] 

Symbol table '.symtab' contains 3 entries:  # 静态符号表
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail  # 未定义的外部函数
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __intel_security[...]

Histogram for bucket list length (total of 97 buckets):  # 哈希表桶分布(符号查找用)
 Length  Number     % of total  Coverage
      0  38         ( 39.2%)
      1  29         ( 29.9%)     29.0%
      2  20         ( 20.6%)     69.0%
      3  9          (  9.3%)     96.0%
      4  1          (  1.0%)    100.0%

No version information found in this file.  # 没有版本信息段

Displaying notes found at file offset 0x000001c8 with length 0x00000024:
  Owner                Data size Description
  GNU                  0x00000014NT_GNU_BUILD_ID (unique build ID bitstring)  # GNU build-id
    Build ID: 7e55cc28965ecb053c55055043d9f1ed3260a498

readelf 辅助脚本

新一个 soinfo.sh,编写一个简单的 Shell 脚本,调用 readelf -a 命令并将 ELF文件信息 输出到文件同名的 .txt 文件。

bash 复制代码
#!/bin/bash

# 检查是否提供了SO文件
if [ -z "$1" ]; then
  echo "Usage: $0 <path_to_so_file>"
  exit 1
fi

# 提取输入文件的文件名
so_file="$1"

# 检查文件是否存在
if [ ! -f "$so_file" ]; then
  echo "Error: File '$so_file' not found!"
  exit 1
fi

# 获取文件名(不含扩展名)
base_name=$(basename "$so_file" .so)

# 创建输出文件名(.txt文件)
output_file="${base_name}.txt"

# 调用 readelf -a 并将结果导出到输出文件
readelf -a "$so_file" > "$output_file"

# 提示用户操作成功
echo "Information exported to $output_file"

创建 scripts 目录,并把 soinfo.sh 放到该目录下。

执行 nano ~/.bashrc 命令,把 scripts 目录添加到环境变量

ruby 复制代码
export PATH=$PATH:/mnt/e/scripts

修改保存后,执行 source ~/.bashrc 使其生效。

之后就可以通过调用 soinfo.sh <so_path> 将 so 文件信息导出到 so 同名的 .txt 文件

ruby 复制代码
cyrus@*:/mnt/d/Python/anti-app/app/duapp$ soinfo.sh libGameVMP.so
readelf: Warning: local symbol 1 found at index >= .dynsym's sh_info value of 1
readelf: Warning: local symbol 2 found at index >= .dynsym's sh_info value of 1
Information exported to libGameVMP.txt

libGameVMP.txt

相关推荐
菠萝加点糖25 分钟前
Android 使用MediaMuxer+MediaCodec编码MP4视频
android·音视频·编码
2401_831501731 小时前
Linux之Docker虚拟化技术(一)
java·linux·docker
阳光阴郁大boy1 小时前
前端实现Linux查询平台:打造高效运维工作流
linux·运维·服务器
雨白1 小时前
手写 MaterialEditText:实现浮动标签(Floating Label)效果
android
博语小屋3 小时前
回车换行、缓冲区刷新、倒计时小程序
linux
幸运狗头3 小时前
Linux学习-TCP并发服务器构建
linux·服务器·学习
轻松Ai享生活3 小时前
udev 从入门到精通,3天学习计划
linux
林政硕(Cohen0415)4 小时前
使用docker搭建嵌入式Linux开发环境
linux·docker·sdk·嵌入式linux
The_Second_Coming4 小时前
最小化 CentOS 模板虚拟机安装与配置
linux·运维·服务器·学习·centos·云计算