可执行文件中全局const变量的偏移[英] Offset of global const variable in executable

本文是小编为大家收集整理的关于可执行文件中全局const变量的偏移的处理方法,想解了可执行文件中全局const变量的偏移的问题怎么解决?可执行文件中全局const变量的偏移问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

希望通过修改自己的全球常数来使其可执行文件保存状态.只是为了拥有完全独立的可执行文件.

想到的一些解决方案/黑客:

  1. 使用libelf并让程序解析以找到偏移.
  2. 添加一个特定的标记,只需在可执行文件中搜索它即可.我想这甚至可能有点跨平台?
  3. 使用对象转储utils确定可执行文件中的地址.这可能总是作为项目构建的后处理.

让链接器提供此信息是很整洁的.

是否可以让链接器提供可执行文件中只读部分的偏移?

谢谢

推荐答案

您实际上是在谈论二进制重写.不利于编译过程的一种方法是将虚拟地址映射到物理地址,然后对其进行修补.有趣的是,这是我在我的 prose of的内容中硕士论文.以下图像和文本是从该文档中提取的:

 http://localhostr.com/file/file/hb1ifuil0nv/loading_binary.binary.jpg

请注意,我原始项目背后的概念是假设无法修改编译过程,以其他二进制文件重写代码.如果您的要求和假设不同,这可能不是最简单,最佳的方法.

这里最重要的想法是,将磁盘表示中的一节映射到内存中时,将保留(不拆分).这意味着在将磁盘表示中的一定偏移偏移的数据将被加载到内存后的相同数量.

.

在libelf中,与libbfd类似,可执行文件包含一组部分,代码和数据都可以驻留.当操作系统将可执行文件加载到内存中时,每个部分都基于某些基础地址.我们可以将其逆转以将虚拟内存地址映射到物理文件偏移量.如果可以找到物理文件偏移量,则可以将字节修补为常规文件.

  • 首先,使用libelf对可执行文件的部分标题进行解析. 这使我们能够获得一组部分,最重要的是 每个部分libelf可以告诉我们三件事:
    1. 截面大小本节的大小.
    2. 部分基础地址该部分将基于将磁盘上的可执行文件加载到内存中的地址.
    3. 部分磁盘偏移本节的磁盘偏移.
  • 通过在上一步中提取的部分信息中迭代,可以找出包含任意虚拟内存地址的部分.在修补过程中,我们感兴趣的内存地址是代码的地址绕道要写.虚拟内存地址的偏移可以通过(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;
}

这是对偏移量进行修补可执行文件的代码:

/*
 * 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;
}

可以在报告本身中找到更详细的信息,该信息可公开可用在这里.

其他推荐答案

您想做的是棘手和无法携带的.

但是,您可以研究gnu emacs unexec功能,例如在 src/unex.c (对于Linux;其他OS具有类似的文件).

您也可以玩链接器技巧,例如使用您自己的ld脚本.

注意这些技巧可以是处理器,编译器 - ,内核 - 和libc-版本.

也许您想要应用程序检查点.特别是, blcr 可能对您有用.

其他推荐答案

这是不可能的,因为编译器通常会在可能的情况下替换全局和静态常数作为即时的值.例如:

const int x=3;

int main()
{
 return x;
}

为main()(OSX/GCC -O3)生成此代码:

_main:
Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    movl    $3, %eax // <= immediate constant!
    popq    %rbp
    ret

本文地址:https://www.itbaoku.cn/post/359207.html