如何在二进制文件中查找全局变量的值

本贴最后更新于 1994 天前,其中的信息可能已经物是人非

背景

从二进制文件中找出一个初始化了的全局变量的值。

原理

初始化的全局变量的值,一定是在可执行文件中的,就看怎么定位到这个地址了。

环境说明

可执行二进制文件为 linux 下 elf 文件格式。二进制文件的符号表没被删除,并且知道这个全局变量名。

方法

  1. 先在文件中找到这个变量的地址。

readelf -s prob |grep accessID

319: 0000000000cf2610    16 OBJECT  GLOBAL DEFAULT    9 main.accessID
4414: 00000000009ad660    17 OBJECT  GLOBAL DEFAULT    2 main.accessID.str

prob 为二进制文件名,accessID 就是我想知道的全局变量名,readelf -s 查看 prob 的符号表,找到 accessID 这个 变量。

从符号名上应该能看出第二条记录是 我们需要的:(实际应该从第一条记录去找,因为我知道这个变量是个字符串,所以这个变量的值 应该是个地址,而这个地址里的内容才是真正的 字符串值。 经验证,0xcf2610 这个地址的内容就是 0x9ad660)

  • 名称 -> main.accessID.str
  • 内存地址 -> 0x9ad660
  • size -> 17 字节

但是 0x9ad660 这个地址是 应用加载进内存之后,在内存中的地址,并不是在二进制文件中的地址。

  1. 找到变量在文件 中相对与文件头的偏移

readelf -S prob

There are 24 section headers, starting at offset 0x1c8:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000401000  00001000
       0000000000424f78  0000000000000000  AX       0     0     16
  [ 2] .rodata           PROGBITS         0000000000826000  00426000
       000000000019e7c4  0000000000000000   A       0     0     32
  [ 3] .shstrtab         STRTAB           0000000000000000  005c47e0
       0000000000000193  0000000000000000           0     0     1
  [ 4] .typelink         PROGBITS         00000000009c4980  005c4980
       0000000000004078  0000000000000000   A       0     0     32
  [ 5] .itablink         PROGBITS         00000000009c89f8  005c89f8
       0000000000000f88  0000000000000000   A       0     0     8
  [ 6] .gosymtab         PROGBITS         00000000009c9980  005c9980
       0000000000000000  0000000000000000   A       0     0     1
  [ 7] .gopclntab        PROGBITS         00000000009c9980  005c9980
       00000000002fa65b  0000000000000000   A       0     0     32
  [ 8] .noptrdata        PROGBITS         0000000000cc4000  008c4000
       000000000002da61  0000000000000000  WA       0     0     32
  [ 9] .data             PROGBITS         0000000000cf1a80  008f1a80
       000000000000cb50  0000000000000000  WA       0     0     32
  [10] .bss              NOBITS           0000000000cfe5e0  008fe5e0
       000000000001fe50  0000000000000000  WA       0     0     32

readelf -S 查看文件的 section 表, 可以看出我们要找的变量 0x9ad660 这个地址在.rodata 段(只读数据段, 字符串在这个段应该没错了), 这个段的信息:

  • 名称 -> .rodata
  • 内存起始地址 -> 0x826000
  • 相对于文件头的 偏移 -> 0x426000
  • size -> 0x19e7c4 字节

根据 0x826000 < 0x9ad660 < (0x826000+0x19e7c4),确定这个变量在这个段的。

设 该变量在文件中的偏移为 X,则,

0x9ad660 - X = 0x826000 - 0x426000, X = 0x9ad660 - 0x400000 = 0x5ad660

  1. 输出这个变量的内容

hexdump prob -C -s 0x5ad660 -n 17

005ad660  4c 54 41 49 62 42 67 6a  62 39 59 59 72 4d 4b 68  |LTAIbBgjb9YYrMKh|
005ad670  00                                                |.|

既然找到了偏移, 查看的方式有很多,其中**-C 是为了输出 ascii 值**,-s 起始地址-n 17 是之前 确认的 size 大小

结束

好多说不清楚,没办法再说下 elf 文件格式, 程序加载到内存变成进程的过程,以及 section 和 segment 的区别。这些都可以 在 《程序员的自我修养 》这本书上学到。

  • 二进制
    5 引用 • 6 回帖
  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    920 引用 • 931 回帖 • 2 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...