阅读Keith Makan的“ ELF格式简介:ELF标头”后,他修改了e_entry


e_entry字段列出了程序应开始执行的文件中的偏移。指向您的_start方法(当然,如果您使用常用的东西对其进行编译)。您可以将e_entry指向任何您喜欢的地方,例如,我将展示您可以调用在正常执行下否则将无法实现的函数。


man 5 elf中也有记录,我想知道Radare是否具有重写ELF特定标头的功能,或者当前的手动方式是手动写入位?例如,我知道它将用ie显示入口点。

评论

您绝对要使用radare2做到这一点吗?如果不是,请查看bfd项目(由binutils使用)。

@ 0xC0000022L我不确定是否有办法做到这一点,通常来说,我认为Radare无法做某事,然后我问,发现它可以做到(这个网站的巨大价值)。我认为它只能解析ELF。如果它只能解析ELF,我认为一种解决方法是一个很大的贡献,因为我对RE还是很陌生的,而且我敢肯定其他人也会像我一样测试水域。如果Radare稍后增加了此功能,我将返回并标记选择的新答案。

#1 楼

是的,显然可以。 Radee2具有处理二进制标头的内置功能。这包括读取,解析和修改二进制文件的标头。而且对于elfpe文件也没有什么不同,它们都可以同时使用。
创建我们的测试文件

如您在问题中链接的文章中所述,使用具有在常规情况下永远不应执行的功能的二进制文件很容易。这是链接的文章中使用的确切代码:如您所见,函数never_call将会很好……永远不会被调用。该程序将执行入口点,该入口点将执行main函数并返回。

现在让我们使用本文中使用的命令行对其进行编译,然后执行该程序:

$ ./example.elf
[*] you ran this binary!

$ r2 -w -nn example.elf
[0x00000000]> .pf.elf_header.entry=0x0000063a
[0x00000000]> q

$ ./example.elf
[*] wow how did you manage to call this?


正如我们所说,只有main()被执行。现在让我们在radare2中打开二进制文件,看看魔术发生了。


radare2时间!

查找函数的地址

根据您的要求,我们希望通过将elf头中的指向地址修改为never_call函数来修改二进制文件的入口点。所以首先,我们需要在二进制文件中找到never_call的地址。

$ cat example.c

#include <stdio.h>


void never_call (void) {
    printf ("[*] wow how did you manage to call this?\n");
    return;
}

int main (int argc, char **argv) {
    printf ("[*] you ran this binary!\n");
    return 0;
}


我们可以看到函数never_call位于地址0x0000063a。您现在可能已经知道,f命令用于列出由radare2标记的标志,其中包括作为函数名称的符号。然后,我们使用r43的内部grep ~并为相关功能进行grepped。

解析ELF标头

首先,我们需要使用0寻求寻址s 0的地址,然后才可以使用新命令pf解析标头。命令pf用于打印格式化的数据,例如结构,枚举和类型。让我们使用elf64加载pfo elf64的格式定义,并使用pf.命令列出格式定义:

$ gcc -Wall -o example.elf example.c
$ ./example.elf
[*] you ran this binary!


加载的定义之一是elf_header,其中包含elf64标头。我们可以像这样打印标题:

$ r2 example.elf
[0x00000530]> f~never_call
0x0000063a 19 sym.never_call


您可以看到,radare2以可读格式打印了elf64标题,因此现在我们可以看到entry位于0x18,指向0x530,这是我们的原始入口点函数。我们可以使用radare2命令ie来打印entrypooint来进行验证:

[0x00002400]> s 0        # Seek to pos 0 in the binary

[0x00000000]> pfo elf64  # Load a Format Definition File for elf

[0x00000000]> pf.
pf.elf_header [16]z[2]E[2]Exqqqxwwwwww ident (elf_type)type (elf_machine)machine version entry phoff shoff flags ehsize phentsize phnum shentsize shnum shstrndx

pf.elf_phdr [4]E[4]Eqqqqqq (elf_p_type)type (elf_p_flags)flags offset vaddr paddr filesz memsz align

pf.elf_shdr x[4]E[8]Eqqqxxqq name (elf_s_type)type (elf_s_flags_64)flags addr offset size link info addralign entsize


实际上,您可以看到入口点是0x530,而haddr是标头地址是0x18。

修改入口点

为了修改该入口,我们需要以写入模式打开文件。我们可以简单地从当前会话中执行oo+以便以写模式重新打开文件,或者使用-wradare2参数。

然后,我们可以简单地使用pf命令写入解析结构体never_call函数的地址。我们既可以自己执行它,也可以使用.命令“将命令的输出解释为r2命令”。

因此,除了执行wv8 ...之外,我们只需执行以下操作:

[0x00000000]> pf.elf_header
     ident : 0x00000000 = .ELF...
      type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
   machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
   version : 0x00000014 = 0x00000001
     entry : 0x00000018 = (qword)0x0000000000000530
     phoff : 0x00000020 = (qword)0x0000000000000040
     shoff : 0x00000028 = (qword)0x0000000000001948
     flags : 0x00000030 = 0x00000000
    ehsize : 0x00000034 = 0x0040
 phentsize : 0x00000036 = 0x0038
     phnum : 0x00000038 = 0x0009
 shentsize : 0x0000003a = 0x0040
     shnum : 0x0000003c = 0x001d
  shstrndx : 0x0000003e = 0x001c


现在entry应该被我们的never_call函数0x63a覆盖。

[0x00000000]> ie
[Entrypoints]
vaddr=0x00000530 paddr=0x00000530 baddr=0x00000000 laddr=0x00000000 haddr=0x00000018 hvaddr=0x00000018 type=program


执行

大!现在,我们可以退出雷达并执行程序。

[0x00000000]> oo+
[0x00000000]> pf.elf_header.entry=0x0000063a
wv8 0x0000063a @ 0x00000018



最后的话

这个长答案解释了方法的每个步骤,但实际上可以缩小为一个简单的命令.pf.elf_header.entry=0x0000063a,该命令将elf标头中的entry设置为所需的地址。在TL; DR版本中,我演示了使用-w打开write-mode中的二进制文件以及使用-nn加载二进制结构(pfo elf64等)。如此简单地,打开像这样的r2 -w -nn example.elf的radare2并执行.pf.elf_header.entry=<address>就可以解决您的问题。尽管它是一个令人恐惧的框架,但它确实强大且具有适当的知识,可以完成比起初看起来更多的事情。今日雷达|使用radare2解析文件格式

r2book |类型



评论


哇,这真的很酷。从UI的角度来看,如果.pf.elf_header.entry = 0x0000063a不写$$而是写@ @,那就太好了。不过第二次正确了。

–埃文·卡洛尔(Evan Carroll)
18-11-20在9:46



我只是用它来回答网站上的另一个问题,再次感谢您回答有关re.se的所有问题。我让他们来。 =)reverseengineering.stackexchange.com/a/19936/22669

–埃文·卡洛尔(Evan Carroll)
18年11月20日在22:58

#2 楼

我认为源代码不支持此功能。
编辑:我错了,对此感到抱歉。 ,我推荐LIEF。