Objcopy --writable-text 不使精灵二进制文本部分可写?

Posted

技术标签:

【中文标题】Objcopy --writable-text 不使精灵二进制文本部分可写?【英文标题】:Objcopy --writable-text not making elf binary text section writable? 【发布时间】:2014-02-07 22:22:14 【问题描述】:

我试图使用objcopy --writable-text executable_name 使elf 二进制文件的.text 部分可写。该命令正常执行,没有任何错误。

通过readelf查看部分权限我可以看到文本部分仍然只有读取和执行权限。

在浏览此特定选项的objcopy 手册页时,提到该选项对所有二进制格式都没有意义。 (这就是我不能这样做的原因吗?)。

谁能指出我在这里遗漏了什么。

谢谢

(Ubuntu x86_64 位机器,GNU objcopy(适用于 Ubuntu 的 GNU Binutils)2.22.90.20120924)

【问题讨论】:

【参考方案1】:

在浏览此特定选项的 objcopy 手册页时,提到该选项对所有二进制格式都没有意义。 (这是我不能这样做的原因吗?)。

是的。

在这个rather detailed description of special sections of the ELF format,您会看到.text 具有SHF_ALLOC + SHF_EXECINSTR 属性(为其分配了空间并且该空间中包含可执行代码),但没有SHF_WRITE(可以写入空间)。您要求 objcopy 做的事情对 ELF .text 部分无效。

【讨论】:

【参考方案2】:

在 Debian 上,我可以只用 -N 链接,然后生成一个带有可写 .text 的可执行文件

so: ld -N obj.o

【讨论】:

【参考方案3】:

首先完成这个: objcopy --writable-text --set-section-flags .text=CONTENTS,ALLOC,LOAD,CODE

然后 objdump -x 或 readelf -a 查看加载节表,通常在程序头之后。请参阅 ELF 的手册页。以 32 位可执行文件为例:

使用 hexedit 打开二进制文件并查看文件偏移量 0x1C(通常为 0x34)处的值,然后遍历 0x20 字节结构(文件偏移量 0x2a 处列出的大小),直到找到您在上一次转储中确定的那个包含 .text 部分。倒数第二个长值将是 00000005 (05 00 00 00) 并且需要添加写入,从而变为 00000007 (07 00 00 00)。现在它将按预期工作,没有任何限制,例如 -Wl,--omagic 的共享库问题。有点技术性,但需要几秒钟。

不管怎样,这一位标志已经引起了无数的问题,没有任何解释可以澄清这个让它可以完美工作的小点。

可以使用 GCC 轻松编译代码解决方案以进行更改,如果定期进行更改,这可能更容易且更好:

#include <stdlib.h>
#include <stdio.h>
#include <elf.h>

int main(int argc, char** argv)

    if (argc <= 1) return -1;
    FILE* fp = fopen(argv[1], "r+");
    Elf64_Ehdr teh;
    fread(&teh, sizeof(teh), 1, fp);
    fseek(fp, 0, SEEK_SET);
    if (teh.e_ident[EI_CLASS] == ELFCLASS64) 
        Elf64_Ehdr eh;
        fread(&eh, sizeof(eh), 1, fp);
        Elf64_Phdr* ph = malloc(eh.e_phnum * eh.e_phentsize);
        Elf64_Shdr* sh = malloc(eh.e_shnum * eh.e_shentsize);
        fseek(fp, eh.e_phoff, SEEK_SET);
        fread(ph, eh.e_phentsize, eh.e_phnum, fp);
        fseek(fp, eh.e_shoff, SEEK_SET);
        fread(sh, eh.e_shentsize, eh.e_shnum, fp);
        for (int i = 0; i < eh.e_phnum; i++) 
            if (ph[i].p_vaddr <= eh.e_entry && ph[i].p_vaddr + ph[i].p_memsz > eh.e_entry) 
            fseek(fp, eh.e_phoff + i * eh.e_phentsize + (unsigned int)&((Elf64_Phdr*)0)->p_flags, SEEK_SET);
            ph[i].p_flags |= PF_W;
            fwrite(&ph[i].p_flags, sizeof(ph[i].p_flags), 1, fp);
            
        
        for (int i = 0; i < eh.e_shnum; i++) 
            if (sh[i].sh_addr <= eh.e_entry && sh[i].sh_addr + sh[i].sh_size > eh.e_entry) 
            fseek(fp, eh.e_shoff + i * eh.e_shentsize + (unsigned int)&((Elf64_Shdr*)0)->sh_flags, SEEK_SET);
            sh[i].sh_flags |= SHF_WRITE;
            fwrite(&sh[i].sh_flags, sizeof(sh[i].sh_flags), 1, fp);
                   
        
        free(ph);
        free(sh);
     else 
        Elf32_Ehdr eh;
        fread(&eh, sizeof(eh), 1, fp);
        Elf32_Phdr* ph = malloc(eh.e_phnum * eh.e_phentsize);
        Elf32_Shdr* sh = malloc(eh.e_shnum * eh.e_shentsize);
        fseek(fp, eh.e_phoff, SEEK_SET);
        fread(ph, eh.e_phentsize, eh.e_phnum, fp);
        fseek(fp, eh.e_shoff, SEEK_SET);
        fread(sh, eh.e_shentsize, eh.e_shnum, fp);
        for (int i = 0; i < eh.e_phnum; i++) 
            if (ph[i].p_vaddr <= eh.e_entry && ph[i].p_vaddr + ph[i].p_memsz > eh.e_entry) 
            fseek(fp, eh.e_phoff + i * eh.e_phentsize + (unsigned int)&((Elf32_Phdr*)0)->p_flags, SEEK_SET);
            ph[i].p_flags |= PF_W;
            fwrite(&ph[i].p_flags, sizeof(ph[i].p_flags), 1, fp);
            
        
        for (int i = 0; i < eh.e_shnum; i++) 
            if (sh[i].sh_addr <= eh.e_entry && sh[i].sh_addr + sh[i].sh_size > eh.e_entry) 
            fseek(fp, eh.e_shoff + i * eh.e_shentsize + (unsigned int)&((Elf32_Shdr*)0)->sh_flags, SEEK_SET);
            sh[i].sh_flags |= SHF_WRITE;
            fwrite(&sh[i].sh_flags, sizeof(sh[i].sh_flags), 1, fp);
                   
        
        free(ph);
        free(sh);
    
    fflush(fp);
    fclose(fp);
    return 0;

【讨论】:

这就像一个魅力。我不明白为什么我们不能用 objcopy 得到同样的结果。

以上是关于Objcopy --writable-text 不使精灵二进制文本部分可写?的主要内容,如果未能解决你的问题,请参考以下文章

binutils工具集之---objcopy,ranlib,size

使用 objcopy 将文本文件添加到二进制文件,但 objcopy 抱怨架构

如何在 cmake 中使用 self ld、objcopy 和 ar?

如何避免 objcopy 炸毁文件?

如何为 sde-objcopy 指定架构?

是否可以在命令 objcopy 的帮助下进行硬编码