ret2dl-resolve 笔记

本博客内容主要借鉴自文章:https://bbs.pediy.com/thread-227034.htm

这里做个笔记,方便以后查阅。ret2dl-resolve主要是用于32的程序,因为32的程序方便我们控制栈里面的参数,所以文章后面内容都是基于32位的glibc。

前导知识

如果我们要利用dl-resolve的话,就先必须了解dl-resolve的原理。

dl-resolve

首先我们需要了解两个结构体,在进行动态链接的时候,主要是通过这连个结构体进行解析的。

Elf32_Rel

typedef struct
{
  Elf32_Addr    r_offset; // 指向GOT表的指针
  Elf32_Word    r_info;
  // 一些关于导入符号的信息,我们只关心从第二个字节开始的值((val)>>8),忽略那个07
  // 1和3是这个导入函数的符号在.dynsym中的下标,
  // 如果往回看的话你会发现1和3刚好和.dynsym的puts和__libc_start_main对应
} Elf32_Rel;

用IDA查看一下他的布局。

00000000 Elf32_Rel       struc ; (sizeof=0x8, align=0x4, copyof_2)
00000000 r_offset        dd ?
00000004 r_info          dd ?
00000008 Elf32_Rel       ends

可以看到这里主要是8个字节。

Elf32_Sym

typedef struct
{
  Elf32_Word    st_name; //符号名,是相对.dynstr起始的偏移,这种引用字符串的方式在前面说过了
  Elf32_Addr    st_value;
  Elf32_Word    st_size;
  unsigned char st_info; //对于导入函数符号而言,它是0x12
  unsigned char st_other;
  Elf32_Section st_shndx;
}Elf32_Sym; //对于导入函数符号而言,其他字段都是0

用IDA查看一下他的布局。

00000000 Elf32_Sym       struc ; (sizeof=0x10, align=0x4, mappedto_1)
00000000 st_name         dd ? 
00000004 st_value        dd ?
00000008 st_size         dd ?
0000000C st_info         db ?
0000000D st_other        db ?
0000000E st_shndx        dw ?
00000010 Elf32_Sym       ends

这里总共是16个字节。

_dl_runtime_resolve(link_map, rel_offset)

第一个参数,[0x804a004]是一个link_map的指针,这个结构是干什么的,我们不关心,但是有一点要知道,它包含了.dynamic的指针,通过这个link_map,_dl_runtime_resolve函数可以访问到.dynamic这个section。

第二个参数,是当前要调用的导入函数在.rel.plt中的偏移(不过64位的话就直接是index下标)。

接下来然我们看看一个程序的一些表的位置,可以用命令readelf -S 程序进查看,下面是运行的结果。

ex@Ex:~/test$ readelf -S helloworld
There are 30 section headers, starting at offset 0xe78:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048134 000134 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048148 000148 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048168 000168 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        0804818c 00018c 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481ac 0001ac 000050 10   A  6   1  4
  [ 6] .dynstr           STRTAB          080481fc 0001fc 00004a 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          08048246 000246 00000a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         08048250 000250 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             08048270 000270 000008 08   A  5   0  4
  [10] .rel.plt          REL             08048278 000278 000010 08  AI  5  23  4
  [11] .init             PROGBITS        08048288 000288 000023 00  AX  0   0  4
  [12] .plt              PROGBITS        080482b0 0002b0 000030 04  AX  0   0 16
  [13] .plt.got          PROGBITS        080482e0 0002e0 000008 08  AX  0   0  8
  [14] .text             PROGBITS        080482f0 0002f0 0001c2 00  AX  0   0 16
  [15] .fini             PROGBITS        080484b4 0004b4 000014 00  AX  0   0  4
  [16] .rodata           PROGBITS        080484c8 0004c8 000014 00   A  0   0  4
  [17] .eh_frame_hdr     PROGBITS        080484dc 0004dc 000044 00   A  0   0  4
  [18] .eh_frame         PROGBITS        08048520 000520 000110 00   A  0   0  4
  [19] .init_array       INIT_ARRAY      08049630 000630 000004 04  WA  0   0  4
  [20] .fini_array       FINI_ARRAY      08049634 000634 000004 04  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049638 000638 0000e8 08  WA  6   0  4
  [22] .got              PROGBITS        08049720 000720 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        08049724 000724 000014 04  WA  0   0  4
  [24] .data             PROGBITS        08049738 000738 000008 00  WA  0   0  4
  [25] .bss              NOBITS          08049740 000740 000004 00  WA  0   0  1
  [26] .comment          PROGBITS        00000000 000740 000029 01  MS  0   0  1
  [27] .symtab           SYMTAB          00000000 00076c 000410 10     28  44  4
  [28] .strtab           STRTAB          00000000 000b7c 0001f7 00      0   0  1
  [29] .shstrtab         STRTAB          00000000 000d73 000105 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),

注意这里我们要重点关注 .rel.plt 、.dynsym 、 .dynstr 的值。

具体步骤

  1. 用link_map访问.dynamic,取出.dynstr, .dynsym, .rel.plt的指针
  2. .rel.plt + 第二个参数求出当前函数的重定位表项Elf32_Rel的指针,记作rel
  3. rel->r_info >> 8作为.dynsym的下标,求出当前函数的符号表项Elf32_Sym的指针,记作sym
  4. .dynstr + sym->st_name得出符号名字符串指针
  5. 在动态链接库查找这个函数的地址,并且把地址赋值给*rel->r_offset,即GOT表
  6. 调用这个函数

就相当于下面的调用结果:

_dl_runtime_resolve(link_map, rel_offset);

根据rel_offset找到rel _entry:(JMPREL就是.rel.plt的地址)

Elf32_Rel * rel_entry = JMPREL + rel_offset;

由rel_entry->r_info定位符号信息,SYMTAB是表示的是结构体Elf32_Sym的一个数组,而这个数组的基地址就是 .dynsym

Elf32_Sym *sym_entry = SYMTAB[ELF32_R_SYM(rel_entry->r_info)];

再定位符号信息中的符号名,STRTAB是.dynstr的地址,也就是说所有的程序名字的寻址,都是通过这个地址进行偏移的。

char *sym_name = STRTAB + sym_entry->st_name;

根据得到的符号名搜索动态库,找到地址后填充至.got.plt对应位置。

手动解析

这么多概念性的东西,正常人一般都会看的比较云里雾里。这时候就需要我们自己动手解析一遍了。

在手动解析之前,我么必须要知道 .rel.plt 、.dynsym 、 .dynstr 的值。用readelf命令来获取。

ex@Ex:~/test$ readelf -S helloworld
There are 30 section headers, starting at offset 0xe78:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048134 000134 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048148 000148 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048168 000168 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        0804818c 00018c 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481ac 0001ac 000050 10   A  6   1  4
  [ 6] .dynstr           STRTAB          080481fc 0001fc 00004a 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          08048246 000246 00000a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         08048250 000250 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             08048270 000270 000008 08   A  5   0  4
  [10] .rel.plt          REL             08048278 000278 000010 08  AI  5  23  4
  [11] .init             PROGBITS        08048288 000288 000023 00  AX  0   0  4
  [12] .plt              PROGBITS        080482b0 0002b0 000030 04  AX  0   0 16
  [13] .plt.got          PROGBITS        080482e0 0002e0 000008 08  AX  0   0  8
  [14] .text             PROGBITS        080482f0 0002f0 0001c2 00  AX  0   0 16
  [15] .fini             PROGBITS        080484b4 0004b4 000014 00  AX  0   0  4
  [16] .rodata           PROGBITS        080484c8 0004c8 000014 00   A  0   0  4
  [17] .eh_frame_hdr     PROGBITS        080484dc 0004dc 000044 00   A  0   0  4
  [18] .eh_frame         PROGBITS        08048520 000520 000110 00   A  0   0  4
  [19] .init_array       INIT_ARRAY      08049630 000630 000004 04  WA  0   0  4
  [20] .fini_array       FINI_ARRAY      08049634 000634 000004 04  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049638 000638 0000e8 08  WA  6   0  4
  [22] .got              PROGBITS        08049720 000720 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        08049724 000724 000014 04  WA  0   0  4
  [24] .data             PROGBITS        08049738 000738 000008 00  WA  0   0  4
  [25] .bss              NOBITS          08049740 000740 000004 00  WA  0   0  1
  [26] .comment          PROGBITS        00000000 000740 000029 01  MS  0   0  1
  [27] .symtab           SYMTAB          00000000 00076c 000410 10     28  44  4
  [28] .strtab           STRTAB          00000000 000b7c 0001f7 00      0   0  1
  [29] .shstrtab         STRTAB          00000000 000d73 000105 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),

从上面可得 .rel.plt 的值是0x08048278 、.dynsym 的值是0x080481ac、 .dynstr 的值是0x080481fc

下面是我们要实验的代码:

; int __cdecl main(int argc, const char **argv, const char **envp)
  public main
main proc near

argc= dword ptr  8
argv= dword ptr  0Ch
envp= dword ptr  10h

  lea     ecx, [esp+4]
  and     esp, 0FFFFFFF0h
  push    dword ptr [ecx-4]
  push    ebp
  mov     ebp, esp
  push    ebx
  push    ecx
  call    __x86_get_pc_thunk_ax
  add     eax, 130Ah
  sub     esp, 0Ch
  lea     edx, (aHelloWorld - 8049724h)[eax] ; "hello world"
  push    edx
  mov     ebx, eax
  call    _puts
  add     esp, 10h
  mov     eax, 0
  lea     esp, [ebp-8]
  pop     ecx
  pop     ebx
  pop     ebp
  lea     esp, [ecx-4]
  retn
main endp

我们在call _puts出下断点,然后在_dl_runtime_resolve出下来。

pwndbg> 
0x0804842b in main ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────
 EAX  0x8049724 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049638 (_DYNAMIC) ◂— 0x1
 EBX  0x8049724 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049638 (_DYNAMIC) ◂— 0x1
 ECX  0xffffcd70 ◂— 0x1
 EDX  0x80484d0 ◂— push   0x6f6c6c65 /* 'hello world' */
 EDI  0x0
 ESI  0xf7fae000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c
 EBP  0xffffcd58 ◂— 0x0
 ESP  0xffffcd40 —▸ 0x80484d0 ◂— push   0x6f6c6c65 /* 'hello world' */
 EIP  0x804842b (main+37) —▸ 0xfffe90e8 ◂— 0x0
──────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
   0x804841a <main+20>    add    eax, 0x130a
   0x804841f <main+25>    sub    esp, 0xc
   0x8048422 <main+28>    lea    edx, [eax - 0x1254]
   0x8048428 <main+34>    push   edx
   0x8048429 <main+35>    mov    ebx, eax
  0x804842b <main+37>    call   puts@plt <0x80482c0>
        s: 0x80484d0 ◂— 'hello world'

   0x8048430 <main+42>    add    esp, 0x10
   0x8048433 <main+45>    mov    eax, 0
   0x8048438 <main+50>    lea    esp, [ebp - 8]
   0x804843b <main+53>    pop    ecx
   0x804843c <main+54>    pop    ebx
───────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────
00:0000│ esp  0xffffcd40 —▸ 0x80484d0 ◂— push   0x6f6c6c65 /* 'hello world' */
01:0004│      0xffffcd44 —▸ 0xffffce04 —▸ 0xffffcff6 ◂— '/home/ex/test/helloworld'
02:0008│      0xffffcd48 —▸ 0xffffce0c —▸ 0xffffd00f ◂— 'CLUTTER_IM_MODULE=xim'
03:000c│      0xffffcd4c —▸ 0x804841a (main+20) ◂— add    eax, 0x130a
04:0010│      0xffffcd50 —▸ 0xffffcd70 ◂— 0x1
05:0014│      0xffffcd54 ◂— 0x0
... 
07:001c│      0xffffcd5c —▸ 0xf7deee81 (__libc_start_main+241) ◂— add    esp, 0x10
─────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────
  f 0  804842b main+37
   f 1 f7deee81 __libc_start_main+241
pwndbg> si
0x080482c0 in puts@plt ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────
 EAX  0x8049724 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049638 (_DYNAMIC) ◂— 0x1
 EBX  0x8049724 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049638 (_DYNAMIC) ◂— 0x1
 ECX  0xffffcd70 ◂— 0x1
 EDX  0x80484d0 ◂— push   0x6f6c6c65 /* 'hello world' */
 EDI  0x0
 ESI  0xf7fae000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c
 EBP  0xffffcd58 ◂— 0x0
 ESP  0xffffcd3c —▸ 0x8048430 (main+42) ◂— add    esp, 0x10
 EIP  0x80482c0 (puts@plt) ◂— jmp    dword ptr [0x8049730]
──────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
  0x80482c0  <puts@plt>                  jmp    dword ptr [_GLOBAL_OFFSET_TABLE_+12] <0x8049730>

   0x80482c6  <puts@plt+6>                push   0
   0x80482cb  <puts@plt+11>               jmp    0x80482b0
    
   0x80482b0                              push   dword ptr [_GLOBAL_OFFSET_TABLE_+4] <0x8049728>
   0x80482b6                              jmp    dword ptr [0x804972c] <0xf7feae10>
    
   0xf7feae10 <_dl_runtime_resolve>       push   eax
   0xf7feae11 <_dl_runtime_resolve+1>     push   ecx
   0xf7feae12 <_dl_runtime_resolve+2>     push   edx
   0xf7feae13 <_dl_runtime_resolve+3>     mov    edx, dword ptr [esp + 0x10]
   0xf7feae17 <_dl_runtime_resolve+7>     mov    eax, dword ptr [esp + 0xc]
   0xf7feae1b <_dl_runtime_resolve+11>    call   _dl_fixup <0xf7fe4f40>
───────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────
00:0000│ esp  0xffffcd3c —▸ 0x8048430 (main+42) ◂— add    esp, 0x10
01:0004│      0xffffcd40 —▸ 0x80484d0 ◂— push   0x6f6c6c65 /* 'hello world' */
02:0008│      0xffffcd44 —▸ 0xffffce04 —▸ 0xffffcff6 ◂— '/home/ex/test/helloworld'
03:000c│      0xffffcd48 —▸ 0xffffce0c —▸ 0xffffd00f ◂— 'CLUTTER_IM_MODULE=xim'
04:0010│      0xffffcd4c —▸ 0x804841a (main+20) ◂— add    eax, 0x130a
05:0014│      0xffffcd50 —▸ 0xffffcd70 ◂— 0x1
06:0018│      0xffffcd54 ◂— 0x0
... 
─────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────
  f 0  80482c0 puts@plt
   f 1  8048430 main+42
   f 2 f7deee81 __libc_start_main+241
pwndbg> b _dl_runtime_resolve
Breakpoint 2 at 0xf7feae10: file ../sysdeps/i386/dl-trampoline.S, line 35.
pwndbg> c
Continuing.

Breakpoint 2, _dl_runtime_resolve () at ../sysdeps/i386/dl-trampoline.S:35
35  ../sysdeps/i386/dl-trampoline.S: No such file or directory.
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────
 EAX  0x8049724 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049638 (_DYNAMIC) ◂— 0x1
 EBX  0x8049724 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049638 (_DYNAMIC) ◂— 0x1
 ECX  0xffffcd70 ◂— 0x1
 EDX  0x80484d0 ◂— push   0x6f6c6c65 /* 'hello world' */
 EDI  0x0
 ESI  0xf7fae000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d6c
 EBP  0xffffcd58 ◂— 0x0
 ESP  0xffffcd34 —▸ 0xf7ffd940 ◂— 0x0
 EIP  0xf7feae10 (_dl_runtime_resolve) ◂— push   eax
──────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
   0x80482c0  <puts@plt>                  jmp    dword ptr [_GLOBAL_OFFSET_TABLE_+12] <0x8049730>

   0x80482c6  <puts@plt+6>                push   0
   0x80482cb  <puts@plt+11>               jmp    0x80482b0
    
   0x80482b0                              push   dword ptr [_GLOBAL_OFFSET_TABLE_+4] <0x8049728>
   0x80482b6                              jmp    dword ptr [0x804972c] <0xf7feae10>
    
  0xf7feae10 <_dl_runtime_resolve>       push   eax <0x8049724>
   0xf7feae11 <_dl_runtime_resolve+1>     push   ecx
   0xf7feae12 <_dl_runtime_resolve+2>     push   edx
   0xf7feae13 <_dl_runtime_resolve+3>     mov    edx, dword ptr [esp + 0x10]
   0xf7feae17 <_dl_runtime_resolve+7>     mov    eax, dword ptr [esp + 0xc]
   0xf7feae1b <_dl_runtime_resolve+11>    call   _dl_fixup <0xf7fe4f40>
───────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────
00:0000│ esp  0xffffcd34 —▸ 0xf7ffd940 ◂— 0x0
01:0004│      0xffffcd38 ◂— 0x0
02:0008│      0xffffcd3c —▸ 0x8048430 (main+42) ◂— add    esp, 0x10
03:000c│      0xffffcd40 —▸ 0x80484d0 ◂— push   0x6f6c6c65 /* 'hello world' */
04:0010│      0xffffcd44 —▸ 0xffffce04 —▸ 0xffffcff6 ◂— '/home/ex/test/helloworld'
05:0014│      0xffffcd48 —▸ 0xffffce0c —▸ 0xffffd00f ◂— 'CLUTTER_IM_MODULE=xim'
06:0018│      0xffffcd4c —▸ 0x804841a (main+20) ◂— add    eax, 0x130a
07:001c│      0xffffcd50 —▸ 0xffffcd70 ◂— 0x1
─────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────
  f 0 f7feae10 _dl_runtime_resolve
   f 1  8048430 main+42
   f 2 f7deee81 __libc_start_main+241
Breakpoint _dl_runtime_resolve
pwndbg>

可以从上面的调试代的栈中看出,link_map的值是0xf7ffd940,而rel_offset的值是0

00:0000esp  0xffffcd34 —▸ 0xf7ffd940 ◂— 0x0
01:0004│      0xffffcd38 ◂— 0x0

接下来我们就来手动解析一遍,首先找到对应的Elf32_Rel,也就是重定向表,用Elf32_Rel * rel_entry = JMPREL + rel_offset;公式进行查找。也就是相对于.rel.plt 的值(0x08048278)的偏移。其结果如下:

Breakpoint _dl_runtime_resolve
pwndbg> p *(Elf32_Rel *)(0x08048278 + 0x0)
$1 = {
  r_offset = 134518576, 
  r_info = 263
}

然后找到对应的Elf32_Sym,也就是符号表,用Elf32_Sym *sym_entry = SYMTAB[ELF32_R_SYM(rel_entry->r_info)];公式进行查找。SYMTAB是相对于.dynsym 的值(0x080481ac)的数组偏移,而ELF32_R_SYM就可以看成是将值向右移8位,也就是不要最后字节。其结果如下:

pwndbg> p ((Elf32_Sym *)0x080481ac)[ 263>>8 ]
$2 = {
  st_name = 26, 
  st_value = 0, 
  st_size = 0, 
  st_info = 18 '\022', 
  st_other = 0 '\000', 
  st_shndx = 0
}

最后我们通过char *sym_name = STRTAB + sym_entry->st_name;能找到我们对应的函数名字符串了,STRTAB的值就是 .dynstr 的值(0x080481fc)。其结果如下:

pwndbg> p (char *)(0x080481fc + 26)
$3 = 0x8048216 "puts"

到此我们完成了一次手动解析。

ret2dl-resolve

当你知道dl-resolve原理之后,其实进行ret2dl-resolve操作也就是不难了,主要是通过控制程序流,来构建假的Elf32_Rel和假的Elf32_Sym,然后让_dl_runtime_resolve函数解析我们自己的字符串,比如system字符串,这样我们就可以直接调用system函数来拿shell。

主要步骤

  1. 通过将eip覆盖为_dl_runtime_resolve地址,rel_offset参数我们要实先构造号,让它能通过 .rel.plt地址 的偏移找到假的Elf32_Rel
  2. 伪造 rel_entry 使 sym_entry落在可控区域,伪造 sym_entry 使 sym_name 落在可控区域;
  3. 伪造sym_name为‘system’

光这么看是比较难理解这个漏洞的,理解这个漏洞最好的办法就是手动构造一遍。

绕过

在执行ret2dl-solve时,还有一点必须绕过,那就是.gnu.version+ELF32_R_SYM(rel_entry->r_info) * 2必须是一个较小的值,否则下面的代码就会执行错误。

In file: /glibc/glibc-2.23/elf/dl-runtime.c
   87       if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
   88   {
   89     const ElfW(Half) *vernum =
   90       (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
   91     ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
 ► 92     version = &l->l_versions[ndx];
   93     if (version->hash == 0)
   94       version = NULL;
   95   }

总结

仅仅是光看文章来理解ret2dl-resolve的话是很困难的,最好能动手操作一下。

ret2dl64

下面是ret2dl64的实例代码,原理就是伪造 link_map 来进行地址偏移后调用。


layout = [
    0, 0x601230, 0, 0x601230 , 0 , 0x601230, #  dynstr,  dynsym,  rel_plt
    libc.bss() - libc.symbols['__libc_start_main'], p32(0x7), p32(1), 0, # Elf64_Rela
    (p32(0), p8(0), p8(1), p16(0), (libc.symbols['system'] - libc.symbols['__libc_start_main'] + 0x10 ** 16) % (0x10 ** 16), 0), # Elf64_Sym
]

sh.send(flat(layout))

sh.interactive()

一般为了方便 rel_offset 设置为0。

   0x7ffff7de4dfe <_dl_fixup+14>    mov    rax, qword ptr [rdi + 0x68]
 ► 0x7ffff7de4e02 <_dl_fixup+18>    mov    rdi, qword ptr [rax + 8]
   0x7ffff7de4e06 <_dl_fixup+22>    mov    rax, qword ptr [r10 + 0xf8]
   0x7ffff7de4e0d <_dl_fixup+29>    mov    rax, qword ptr [rax + 8]
   0x7ffff7de4e11 <_dl_fixup+33>    lea    r8, [rax + rdx*8]
   0x7ffff7de4e15 <_dl_fixup+37>    mov    rax, qword ptr [r10 + 0x70]
   0x7ffff7de4e19 <_dl_fixup+41>    mov    rcx, qword ptr [r8 + 8]

上面这些我们要注意的值,对应的结构如下:

    [val_0x68+8]==STRTAB dynstr
    [val_0x70+8]==SYMTAB dynsym
    [val_0xf8+8]==JMPREL rel_plt

const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; 对应上面的 p32(0x7), p32(1),其中7是magic,1是symtab的数据偏移。

其他资料