Sus*_*sch 9 c linker executable linker-scripts
希望有一个可执行文件通过修改自己的全局常量来保存其状态.只是为了拥有一个完全独立的可执行文件.
想到的一些解决方案/黑客:
让链接器提供此信息是很好的.
是否可以让链接器提供可执行文件中只读部分的偏移量?
谢谢
你想做的是棘手和不可移植.
但是你可以学习GNU emacs unexec函数,例如在src/unexelf.c中(对于Linux;其他操作系统有类似的文件).
您也可以使用自己的ld脚本播放链接器技巧.
请注意,这些技巧可能是特定于处理器,编译器,内核和libc的版本.
你本质上是在谈论二进制重写.在不摆弄编译过程的情况下实现此目的的一种方法是将虚拟地址映射到物理地址然后对其进行修补.有趣的是,这是我在硕士论文中所涉及的内容.从该文档中提取以下图像和文本:

请注意,我原始项目背后的概念是在其他二进制文件中重写代码,假设编译过程无法修改.如果您的要求和假设不同,这可能不是最简单和最好的方法.
这里最重要的想法是磁盘表示中的一个部分在映射到内存时被保留(不分割).这意味着在加载到内存中后,磁盘表示中某个部分偏移的数据将偏移相同的量.
在libelf,类似于libbfd,可执行文件包含了一组,其中两个代码和数据可以驻留部分.当操作系统将可执行文件加载到内存中时,每个部分都基于某个基址.我们可以将其反转以将虚拟内存地址映射到物理文件偏移量.如果可以找到物理文件偏移量,则可以将字节修补为常规文件.
libelf.这允许我们获得一组部分,最重要的是,每个部分libelf可以告诉我们三件事:
(virtual_memory_address - section_base_address).(section_disk_offset + (virtual_memory_address - section_base_address)).此过程允许将任意虚拟内存地址映射到其相应的磁盘文件偏移量.然后可以使用常规C文件IO函数(例如fopen/ fseek/ fwrite/)修补此偏移量fclose.
这是我使用上述步骤将虚拟地址映射到物理文件偏移的代码:
/*
* Returns the corresponding 32 bit executable file offset of a virtual memory
* address.
*/
uint32_t vaddr32_to_file_offset(char * filepath, uint32_t vaddr)
{
int fd = open(filepath, O_RDONLY);
Elf * e = elf_begin(fd, ELF_C_READ, NULL);
uint32_t offset = 0;
Elf_Scn * scn = NULL;
while((scn = elf_nextscn(e, scn)) != NULL) {
Elf32_Shdr * shdr = elf32_getshdr(scn);
if(vaddr >= shdr->sh_addr &&
(vaddr <= (shdr->sh_addr + shdr->sh_size))) {
offset = shdr->sh_offset + (vaddr - shdr->sh_addr);
break;
}
}
elf_end(e);
close(fd);
return offset;
}
/*
* Returns the corresponding 64 bit executable file offset of a virtual memory
* address.
*/
uint64_t vaddr64_to_file_offset(char * filepath, uint64_t vaddr)
{
int fd = open(filepath, O_RDONLY);
Elf * e = elf_begin(fd, ELF_C_READ, NULL);
uint64_t offset = 0;
Elf_Scn * scn = NULL;
while((scn = elf_nextscn(e, scn)) != NULL) {
Elf64_Shdr * shdr = elf64_getshdr(scn);
if(vaddr >= shdr->sh_addr &&
(vaddr <= (shdr->sh_addr + shdr->sh_size))) {
offset = shdr->sh_offset + (vaddr - shdr->sh_addr);
break;
}
}
elf_end(e);
close(fd);
return offset;
}
Run Code Online (Sandbox Code Playgroud)
这是在给定偏移量的情况下修补ELF可执行文件的代码:
/*
* Sets the bytes at an arbitrary offset of a file to the contents of buffer.
*/
static bool patch_file(char * filepath, uint64_t offset, void * buffer,
size_t size)
{
FILE * pFile = fopen(filepath, "r+");
if(pFile == NULL) {
return FALSE;
}
fseek(pFile, offset, SEEK_SET);
fwrite(buffer, 1, size, pFile);
fclose(pFile);
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
更详细的信息可以在报告中找到,这里可以公开获得.