我目前正在使用ELF注入器,并且我的方法是标准的:找到代码洞穴(足够长的0序列),用我要执行的指令重写它,然后跳回到原始程序的开始以按以下方式执行
要在代码洞穴中实际执行代码,我尝试了两种不同的方法,两种方法都导致了sigsegv。
第一个方法是将入口点更改为代码洞穴的开始。第二个是“窃取”原始代码中的一些第一条指令,并跳转到我的代码洞穴中,然后在执行注入的代码后,我将首先执行被盗的指令,然后跳转到最后一条被盗的指令之后的指令。原始程序。
我还更改了代码洞穴所在的部分的访问标志。
以下是在gdb中调试程序的屏幕截图:



这是代码洞穴所在部分的标志:
[19] 0x555555556058->0x555555556160 at 0x00002058: .eh_frame ALLOC LOAD READONLY CODE HAS_CONTENTS
这是Valgrind的输出。

所以这里有一个实际上允许执行本节中的代码的方法。
我还考虑过将新节添加到二进制文件中并在其中编写代码。如果有人有经验,我会很感激的。
编辑:我想我知道我的错是-我为该部分设置了可执行标志,但其中的段不是可执行的。但是似乎我发现的代码洞穴也不属于任何部分,因为代码洞穴的开头实际上是一个部分的结尾,而代码洞穴的结尾实际上是另一部分的开头。在它们之间没有其他部分。
编辑2:我将代码洞穴更改为.fini部分,属于可执行段。但是,我仍然对部分(和段)之间的空白感到困惑。
这是readelf输出的屏幕截图
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000000318  00000318
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.gnu.propert NOTE             0000000000000338  00000338
       0000000000000020  0000000000000000   A       0     0     8
  [ 3] .note.gnu.build-i NOTE             0000000000000358  00000358
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .note.ABI-tag     NOTE             000000000000037c  0000037c
       0000000000000020  0000000000000000   A       0     0     4
  [ 5] .gnu.hash         GNU_HASH         00000000000003a0  000003a0
       0000000000000024  0000000000000000   A       6     0     8
  [ 6] .dynsym           DYNSYM           00000000000003c8  000003c8
       00000000000000a8  0000000000000018   A       7     1     8
  [ 7] .dynstr           STRTAB           0000000000000470  00000470
       0000000000000082  0000000000000000   A       0     0     1
  [ 8] .gnu.version      VERSYM           00000000000004f2  000004f2
       000000000000000e  0000000000000002   A       6     0     2
  [ 9] .gnu.version_r    VERNEED          0000000000000500  00000500
       0000000000000020  0000000000000000   A       7     1     8
  [10] .rela.dyn         RELA             0000000000000520  00000520
       00000000000000c0  0000000000000018   A       6     0     8
  [11] .rela.plt         RELA             00000000000005e0  000005e0
       0000000000000018  0000000000000018  AI       6    24     8
  [12] .init             PROGBITS         0000000000001000  00001000
       000000000000001b  0000000000000000  AX       0     0     4
  [13] .plt              PROGBITS         0000000000001020  00001020
       0000000000000020  0000000000000010  AX       0     0     16
  [14] .plt.got          PROGBITS         0000000000001040  00001040
       0000000000000010  0000000000000010  AX       0     0     16
  [15] .plt.sec          PROGBITS         0000000000001050  00001050
       0000000000000010  0000000000000010  AX       0     0     16
  [16] .text             PROGBITS         0000000000001060  00001060
       0000000000000185  0000000000000000  AX       0     0     16
  [17] .fini             PROGBITS         00000000000011e8  000011e8
       000000000000000d  0000000000000000  AX       0     0     4
  [18] .rodata           PROGBITS         0000000000002000  00002000
       0000000000000012  0000000000000000   A       0     0     4
  [19] .eh_frame_hdr     PROGBITS         0000000000002014  00002014
       0000000000000044  0000000000000000   A       0     0     4
  [20] .eh_frame         PROGBITS         0000000000002058  00002058
       0000000000000108  0000000000000000   A       0     0     8
  [21] .init_array       INIT_ARRAY       0000000000003db8  00002db8
       0000000000000008  0000000000000008  WA       0     0     8
  [22] .fini_array       FINI_ARRAY       0000000000003dc0  00002dc0
       0000000000000008  0000000000000008  WA       0     0     8
  [23] .dynamic          DYNAMIC          0000000000003dc8  00002dc8
       00000000000001f0  0000000000000010  WA       7     0     8
  [24] .got              PROGBITS         0000000000003fb8  00002fb8
       0000000000000048  0000000000000008  WA       0     0     8
  [25] .data             PROGBITS         0000000000004000  00003000
       0000000000000010  0000000000000000  WA       0     0     8
  [26] .bss              NOBITS           0000000000004010  00003010
       0000000000000008  0000000000000000  WA       0     0     1
  [27] .comment          PROGBITS         0000000000000000  00003010
       000000000000002a  0000000000000001  MS       0     0     1
  [28] .symtab           SYMTAB           0000000000000000  00003040
       0000000000000618  0000000000000018          29    46     8
  [29] .strtab           STRTAB           0000000000000000  00003658
       0000000000000202  0000000000000000           0     0     1
  [30] .shstrtab         STRTAB           0000000000000000  0000385a
       000000000000011a  0000000000000000           0     0     1



Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000002d8 0x00000000000002d8  R E    0x8
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R E    0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000005f8 0x00000000000005f8  R E    0x1000
  LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                 0x00000000000001f5 0x00000000000001f5  R E    0x1000
  LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000
                 0x0000000000000160 0x0000000000000160  R E    0x1000
  LOAD           0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
                 0x0000000000000258 0x0000000000000260  RWE    0x1000
  DYNAMIC        0x0000000000002dc8 0x0000000000003dc8 0x0000000000003dc8
                 0x00000000000001f0 0x00000000000001f0  RWE    0x8
  NOTE           0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000020 0x0000000000000020  R E    0x8
  NOTE           0x0000000000000358 0x0000000000000358 0x0000000000000358
                 0x0000000000000044 0x0000000000000044  R E    0x4
  GNU_PROPERTY   0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000020 0x0000000000000020  R E    0x8
  GNU_EH_FRAME   0x0000000000002014 0x0000000000002014 0x0000000000002014
                 0x0000000000000044 0x0000000000000044  R E    0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RWE    0x10
  GNU_RELRO      0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
                 0x0000000000000248 0x0000000000000248  R E    0x1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 
   03     .init .plt .plt.got .plt.sec .text .fini 
   04     .rodata .eh_frame_hdr .eh_frame 
   05     .init_array .fini_array .dynamic .got .data .bss 
   06     .dynamic 
   07     .note.gnu.property 
   08     .note.gnu.build-id .note.ABI-tag 
   09     .note.gnu.property 
   10     .eh_frame_hdr 
   11     
   12     .init_array .fini_array .dynamic .got 



可以看出,.fini节从11e8开始,大小为d。下一部分-.rodata从2000开始。这是否意味着11e8 + d2000之间的空间不属于任何部分?该段也结束于11F5,这是属于它的最后一个段的末尾-.fini
编辑3:设法解决了这个问题-必须选择属于可执行段的段。仍然对节的大小有些困惑。
实际上设法将代码注入二进制文件中,但是,我从一个只有.text节的程序集中得到了指令:
.text
.globl _start
_start:
  #save the base pointer
  pushq %rbp
  pushq %rbx
  mov %rsp,%rbp

  #write syscall = 1
  movq , %rax
  #print to stdout
  movq , %rdi
  #9 character long string
  movq , %rdx

  # push "INJECTED\n" to the stack  
  movq q4312078qx0a, %rcx
  pushq %rcx
  movq q4312078qx44455443454a4e49, %rcx
  pushq %rcx

  movq %rsp, %rsi

  syscall

  #remove the string
  pop %rcx
  pop %rcx

  movq q4312078q, %rax
  movq q4312078q, %rdi
  movq q4312078q, %rdx

  
  pop %rbx
  pop %rbp
  ret

它在原始程序执行之前打印“ INJECTED”。当这种有效载荷起作用时,实现更好且实际可用的喷油器还有哪些其他想法?也许可以调用受害二进制文件链接的libc函数或某些其他库函数?因为似乎要从代码中获取实际指令,所以我们想注入,这有点麻烦。

评论

谢谢。您可以用代码段替换图像,以便于阅读和复制/粘贴吗?

@IgorSkochinsky完成。还写了关于我的进度的另一个编辑。也许您会对如何实现更好的喷油器有一些想法?感谢您的帮助!

在边界上增加了答案。最好单独提出一个有关使用libc函数的问题。

#1 楼

执行ELF文件时,OS加载程序不关心节,而只关心段(即程序头)。您需要确保您的代码属于可执行段。

可以看到,.fini节从11e8开始,大小为d。
下一部分-.rodata从2000。这是否表示11e8 + d和2000之间的
空间不属于任何部分?该段也以11F5结尾,这是该段最后一个段的结尾-.fini。

是的,11F5和2000之间的空格是一种“无人区”。从理论上讲,这些字节将不会出现在内存中。但是,实际上,内存保护和映射以页面粒度(0x1000)起作用,因此这些字节被映射到内存中并且可以执行,因此您的补丁程序可以工作。为了使所有内容“合法”,最好将段的长度延长到2000。

评论


是的,谢谢。如果我错了,请纠正我,但查看readelf输出,.fini节从11e8开始,大小为d。下一部分从2000开始。实际上是否表示从11e8 + d到2000的空间不属于任何部分?

–纳扎尔·帕斯捷尔纳克(Nazar Pasternak)
20/11/28在13:24

@NazarPasternak对不起,我从这里看不到您的屏幕;)无论如何,您应该查看的是细分,而不是板块。

–伊戈尔·斯科钦斯基♦
20-11-28在13:25



@NazarPasternak只需将所有相关信息添加到问题中(也可以是段)

–伊戈尔·斯科钦斯基♦
20-11-28在13:27

是的,但是要弄清楚我的代码将驻留在哪个段中,我需要知道它当前在哪个段中:(

–纳扎尔·帕斯捷尔纳克(Nazar Pasternak)
20-11-28在13:28