【问题标题】:Place .text section at the very end of ELF将 .text 部分放在 ELF 的最后
【发布时间】:2017-06-21 21:09:33
【问题描述】:

出于特定原因,我需要将.text 部分放在我的 ELF 文件的最后。

我试图以这种方式实现这一点:

我采用默认的大型链接器脚本并将.text 部分移动到SECTIONS { ... } 部分的最后。

$ readelf -S beronew

[ #] Name               Type            Address            Offset
     Size              Size.Ent         Flags     -     -  Alignment
[ 0]                   NULL             0000000000000000  00000000
     0000000000000000  0000000000000000           0     0     0
[ 1] .data             PROGBITS         00000000006000b0  000000b0
     000000000000003b  0000000000000000  WA       0     0     1
[ 2] .text             PROGBITS         0000000000a000f0  000000f0
     00000000000003e9  0000000000000000  AX       0     0     1
[ 3] .shstrtab         STRTAB           0000000000000000  000004d9
     0000000000000027  0000000000000000           0     0     1
[ 4] .symtab           SYMTAB           0000000000000000  00000680
     0000000000000438  0000000000000018           5    41     8
[ 5] .strtab           STRTAB           0000000000000000  00000ab8
     0000000000000258  0000000000000000           0     0     1

我看到ld 在我的“结束”部分之后添加了额外的部分。为了替换它们,我使用了-nostdlib -s 链接器选项(不使用stdlib(以防万一)并省略所有符号信息)。

再运行一次$ readelf -S beronew

[ #] Name               Type            Address            Offset
     Size              Size.Ent         Flags     -     -  Alignment
[ 0]                   NULL             0000000000000000  00000000
     0000000000000000  0000000000000000           0     0     0
[ 1] .data             PROGBITS         00000000006000b0  000000b0
     000000000000003b  0000000000000000  WA       0     0     1
[ 2] .text             PROGBITS         0000000000a000f0  000000f0
     00000000000003e9  0000000000000000  AX       0     0     1
[ 3] .shstrtab         STRTAB           0000000000000000  000004d9
     0000000000000017  0000000000000000           0     0     1

节头字符串表还在。我试过$strip -R .shstrtab beronew。没有效果,部分还在。

这部分只有 0x17 字节长,但我无法实现我的目标。然后我查看了我的文件的 hexdump:

$ hexdump beronew

...
00004d0 0060 c748 bfc6 6000 0000 732e 7368 7274
00004e0 6174 0062 642e 7461 0061 742e 7865 0074
00004f0 0000 0000 0000 0000 0000 0000 0000 0000
*
0000530 000b 0000 0001 0000 0003 0000 0000 0000
0000540 00b0 0060 0000 0000 00b0 0000 0000 0000
0000550 003b 0000 0000 0000 0000 0000 0000 0000
...

我看到的是在部分之后还有另一个代码。根据 ELF 结构,文件末尾是Section header table。所以即使我以某种方式删除了.shstrtab 部分,最后仍然会有这个标题。

所以我的问题是 如何将我的 .text 部分放在文件的最后? 我真的不需要删除所有部分和标题,所以如果你知道(更好) 方法来实现这一点,我们将不胜感激。

.

.

附:对于那些想知道我为什么需要这个的人:

此 ELF 文件 (beronew) 包含 rutime 库。它将用作另一个文件的“标题”,该文件生成带有操作码形式的一些逻辑的 asm 指令。这个操作码将被添加到beronew 的最后。然后我将在.text 的部分标题中修补sh_size 字段,以便能够运行我最近添加的“代码”。

(还有一个问题:如果“文本”部分是文件中的最后一个部分,我需要修补这些吗?)

附言我知道这是一个糟糕的架构,但它是我的课程项目 - 将在 Win32 中以这种方式构建的应用程序移植到 Linux64,现在我被困在合并运行时库“头”文件和“逻辑”的地方部分原因是我不能将 .text 部分放在 ELF 的末尾。

再次感谢!

.

更新:

根据 fuz 的评论,我尝试将 PHDRS 添加到简单的链接器脚本中,如下所示:

PHDRS
{
   headers PT_PHDR PHDRS ;
   data PT_LOAD ;
   bss PT_LOAD ;
   text PT_LOAD ;
}

SECTIONS 
{ 
    . = 0x200000;
    .data : { *(.data) *(COMMON) }  :data
    .bss  : { *(.bss) }  :bss
    .text : { *(.text) } :text
} 

但它现在似乎不起作用。

【问题讨论】:

  • 请注意,加载器不关心节,它只关心程序头,因此修补sh_size 是无效的。为你的程序添加一个额外的(空的)程序头可能会更容易修补?
  • @fuz 也许我没听懂你的意思,你的意思是我应该修补程序标题(我没有看到任何对我有用的或与部分相关的字段)而不是部分标题?或添加额外的程序头(从未听说过第二个头)?
  • 一个 ELF 二进制文件包含许多程序头文件,这些头文件告诉程序加载器(在内核中)在哪里加载二进制文件的哪些部分。这是加载程序唯一关心的部分,它忽略了所有其他标题。如果你想在 ELF 二进制文件中添加额外的东西,你可以通过只操作程序头来轻松地做到这一点。请参阅here 了解如何执行此操作。
  • ELF格式有两个视图,对应ELF感兴趣的两个东西:链接器视图和加载器视图。开头的单个 ELF 标头是两个视图唯一共享的部分;链接器对段进行操作,加载程序对段进行操作。 ELF 文件中的任何给定字节都可以属于一个节、一个段,或者两者都不属于。只有可分配段中的字节才会加载到内存中。您提出的 hack 将生成属于最后一个类别的文件并将其附加到文件中:不在任何部分(包括 .text)中,也不在任何段中。你不能只是追加并希望它会起作用!
  • GNU 链接器只提供了一种排序方式将部分加载到内存中的方式。它没有提供一种方法来排序事物在可执行文件本身中的实际布局方式。您需要编写自己的程序来生成或修改 ELF 可执行文件。由于.shstrtab 部分用于存储部分本身的名称,并且正如上面 cmets 解释的那样,在加载和运行可执行文件时实际上并未使用这些部分,因此解决方案可能涉及编写一个删除部分表的程序和.shstrtab 从可执行文件中引用的部分。

标签: linux gcc assembly ld elf


【解决方案1】:

对于那些想知道我到底是如何成功完成这项工作的人来说,有一个答案:

  1. 我制作了一个链接描述文件,将文本部分放在数据部分之后 (here is the script)。但是文件末尾有一些调试部分,如 Shstrtab 部分等(下图)。所以我把这个文件逐字节转换成字符串。

  2. 在这之后我在下面的图片上得到了一个精灵

以字节串的形式。然后我刚刚阅读了一些标题并找出了代码部分的结束位置(就在 Shstrtab 部分之前),所以我可以将这个字符串分成两部分。第一个包含加载程序的数据。第二个 - 用于链接器。

  1. 然后我将我的“额外”代码转换为操作码形式,它也是一个字节数组(字符串),并将其连接到原始的.text 部分。接下来,我将结尾部分连接到它。所以我有一个文件,里面有我的额外代码。

  2. 为了让这个工作我编辑了下图中的值:

第一列是需要编辑的字段名(对应elf结构图)。

第二列是从文件开头到字段开头的偏移量。让函数s(xxx) 成为size_of(some_header_structure)injSize 是我注入的额外代码的大小。而像0x18, 0x20, 0x28 这样的值是它们结构中字段的偏移量(section_headers、program_headers、elf_headers)。

第三个代表应该替换原来那个的值。

*注意,表示的elf是ELF64,所以某些字段的宽度与ELF32的不同。

完成所有这些后,我设法运行了这个新的 Elf 文件,它运行良好!也许(肯定)这不是最好的解决方案,但它确实有效,而且它对我的研究工作来说是一个很好的材料。

【讨论】:

    猜你喜欢
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 2018-10-23
    • 2019-08-31
    • 1970-01-01
    • 1970-01-01
    • 2012-02-06
    相关资源
    最近更新 更多