代码之家  ›  专栏  ›  技术社区  ›  Andrew Sun

可执行页面中加载的.rodata节

  •  8
  • Andrew Sun  · 技术社区  · 8 年前

    gcc -m32 1.c ):

    int main(void)
    {
        // EB is the opcode for jmp rel/8
        // FE is hex for -2
        // So this is essentially an infinite loop
    
        ((void(*)(void))"\xEB\xFE")();
    }
    

    objdump -d a.out ),您可以看到呼叫…地址中的任何内容 0x8048480 :

    080483d6 <main>:
     ....
     80483e7:   b8 80 84 04 08          mov    $0x8048480,%eax
     80483ec:   ff d0                   call   *%eax
     ....
    

    objdump -s -j .rodata a.out 给予:

    Contents of section .rodata:
     8048478 03000000 01000200 ebfe00             ...........
                               ~~~~  
    

    .rodata 部分所以我跑了 readelf --sections a.out

    Section Headers:
      [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            00000000 000000 000000 00      0   0  0
      [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
      [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
      [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
      [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000020 04   A  5   0  4
      [ 5] .dynsym           DYNSYM          080481cc 0001cc 000040 10   A  6   1  4
      [ 6] .dynstr           STRTAB          0804820c 00020c 000045 00   A  0   0  1
      [ 7] .gnu.version      VERSYM          08048252 000252 000008 02   A  5   0  2
      [ 8] .gnu.version_r    VERNEED         0804825c 00025c 000020 00   A  6   1  4
      [ 9] .rel.dyn          REL             0804827c 00027c 000008 08   A  5   0  4
      [10] .rel.plt          REL             08048284 000284 000008 08  AI  5  23  4
      [11] .init             PROGBITS        0804828c 00028c 000023 00  AX  0   0  4
      [12] .plt              PROGBITS        080482b0 0002b0 000020 04  AX  0   0 16
      [13] .plt.got          PROGBITS        080482d0 0002d0 000008 00  AX  0   0  8
      [14] .text             PROGBITS        080482e0 0002e0 000182 00  AX  0   0 16
      [15] .fini             PROGBITS        08048464 000464 000014 00  AX  0   0  4
      [16] .rodata           PROGBITS        08048478 000478 00000b 00   A  0   0  4
      [17] .eh_frame_hdr     PROGBITS        08048484 000484 000034 00   A  0   0  4
      [18] .eh_frame         PROGBITS        080484b8 0004b8 0000e0 00   A  0   0  4
      [19] .init_array       INIT_ARRAY      08049f0c 000f0c 000004 04  WA  0   0  4
      [20] .fini_array       FINI_ARRAY      08049f10 000f10 000004 04  WA  0   0  4
      [21] .dynamic          DYNAMIC         08049f14 000f14 0000e8 08  WA  6   0  4
      [22] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   0  4
      [23] .got.plt          PROGBITS        0804a000 001000 000010 04  WA  0   0  4
      [24] .data             PROGBITS        0804a010 001010 000008 00  WA  0   0  4
      [25] .bss              NOBITS          0804a018 001018 000004 00  WA  0   0  1
      [26] .comment          PROGBITS        00000000 001018 00001a 01  MS  0   0  1
      [27] .symtab           SYMTAB          00000000 001034 0003f0 10     28  45  4
      [28] .strtab           STRTAB          00000000 001424 0001bd 00      0   0  1
      [29] .shstrtab         STRTAB          00000000 0015e1 000105 00      0   0  1
    

    因此,在ELF二进制文件中,该部分被标记为不可执行。但在内存中,页面是可执行的( cat /proc/xxx/maps

    08048000-08049000 r-xp 00000000 08:01 663551 /home/andrew/Desktop/a.out
    08049000-0804a000 r--p 00000000 08:01 663551 /home/andrew/Desktop/a.out
    0804a000-0804b000 rw-p 00001000 08:01 663551 /home/andrew/Desktop/a.out
    

    我最初的猜测是这些部分的间距太近(两者都有) AX A 中的部分 08048000-08049000 范围),因此Linux被迫为页面提供ELF权限位的并集( AX | A == AX .罗达 节(通过添加许多长字符串),包含 节仍然是可执行的。为什么会这样?

    1 回复  |  直到 8 年前
        1
  •  6
  •   Employed Russian    4 年前

    我最初的猜测是这些片段之间的距离太近了

    你应该 调用段段(ELF同时具有这两个段,并且它们 mean different things

    节仅在静态链接时起作用,并且可以完全删除(在运行时不需要)。只有 R-X RW- 权限。

    .rodata 节通常与合并 .text --rosegment 如果使用,则标记 gold 链接器( patch

    您可以在中看到段到段的映射 readelf -Wl a.out

    更新:

    有没有可能出现这样的情况。rodata需要是可执行的,或者是用于优化,还是其他什么?

    没有 便携式的 需要可执行。正如您在问题中所做的那样,可以构造一个需要它的不可移植程序。

    合并 文本 mmap 调用而不是三个(一个与 --玫瑰段 将有三个单独的 PT_LOAD 具有的段 , R-- R-W 保护),也减少了虚拟空间的碎片。此外,在Linux上,对总映射有一个系统范围的限制,因此如果将所有程序链接到 --玫瑰段

    更新2:

    最近的Linux发行版已停止合并 文本 .罗达 LOAD this answer .

    推荐文章