想有一个可执行通过修改其自身的全局常量保存其状态。 只是对于具有完全独立的可执行文件的踢。
一些解决方案/浮现在脑海黑客:
- 使用了libelf并有计划解析本身找到抵消。
- 添加特定的标记,只是寻找它的可执行文件。 我想这甚至有可能有些跨平台?
- 使用对象倾销utils的确定可执行文件的地址。 这可能需要一个后处理项目建设要始终做到..
这将是整齐有连接器提供了这个信息。
是否有可能有连接器提供可执行文件只读段的偏移?
谢谢
想有一个可执行通过修改其自身的全局常量保存其状态。 只是对于具有完全独立的可执行文件的踢。
一些解决方案/浮现在脑海黑客:
这将是整齐有连接器提供了这个信息。
是否有可能有连接器提供可执行文件只读段的偏移?
谢谢
你基本上是在谈论二进制重写。 实现这一而不与编译过程摆弄的一种方法是将虚拟地址映射到物理之一,然后打补丁。 有趣的是,这是我在我所覆盖的硕士论文 。 下面的图片和文字是从文档拉:
需要注意的是背着我最初的项目设计理念是要重写其他二进制文件假定编译过程无法修改代码。 如果您的要求和假设是不同的,这很可能不是最简单有效的方法。
这里最重要的想法是,在磁盘上的保存一个部分被保留(不分裂),当它被映射到内存中。 这意味着数据是在一定的偏移量,在盘表示的部分将通过加载到存储器中之后的相同的量来抵消。
在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;
}
这是修补给出的偏移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;
}
更详细的信息可以在报告本身,这是公开的可以找到这里 。
什么,你想要做的是棘手的,不可移植。
但是你可以学习的GNU emacs unexec
的功能,例如在SRC / unexelf.c (对于Linux,其他操作系统也有类似的文件)。
你也可以发挥连接的招数,例如用自己的ld
脚本。
要注意的是,这些技巧可能是处理器,反编译,内核级和libc-特定版本。
也许你想要的应用程序检查点 。 特别是, BLCR可能对你有用。
这将是不可能的,因为编译器通常如果有可能取代全局和静态常量的立即值机代码。 例如:
const int x=3;
int main()
{
return x;
}
产生用于主()(OSX / GCC -O3)此代码:
_main:
Leh_func_begin1:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
movl $3, %eax // <= immediate constant!
popq %rbp
ret