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 抱怨架构