首页
社区
课程
招聘
[原创]ROP高级用法之ret2_dl_runtime_resolve
发表于: 2019-4-10 17:04 17249

[原创]ROP高级用法之ret2_dl_runtime_resolve

2019-4-10 17:04
17249

我们知道在Linux中如果程序想要调用其他动态链接库的函数,必须要在程序加载的时候动态链接;在一个程序运行过程中,可能很多函数在程序执行完时都不会用到,比如一些错误处理函数或者一些用户很少用到的功能模块;所以ELF采用一种叫做延迟绑定(Lazy Binding)的做法,基本思想就是当函数第一次被调用的时候才进行绑定(符号查找、重定位等);
而在Linux 中是利用_dl_runtime_resolve(link_map_obj, reloc_index)函数来对动态链接的函数进行重定位的;

首先总的来说一下_dl_runtime_resolve函数如何使程序第一次调用一个函数:

现在我们通过一个实例来解释上面的过程:
任意打开一个ELF程序,这里我用XDCTF2015的pwn200中的strlen函数为例来看Linux中程序如何第一次调用一个函数;
在0x8048588下断点;

然后si进入call strlen@plt;

我们看到程序没有直接转到strlen函数,而是跳转到了_dl_runtime_resolve函数;并且push了两个参数:

刚好是_dl_runtime_resolve(link_map_obj, reloc_index)需要的参数;其中0x804a004就是link_map指针,然后0x10就是reloc_index;

我们来看看如何通过这两个参数找到strlen函数的;
首先找到link_map的地址0xf7ffd940:

然后通过link_map找到.dynamic的地址:

其中第三个地址就是.dynamic的地址,即0x08049f14;
然后通过.dynamic来找到.dynstr、 .dynsym、 .rel.plt的地址:

.dynamic的地址加0x44的位置是.dynstr;
.dynamic的地址加0x4c的位置是.dynsym;
.dynamic的地址加0x84的位置是.rel.plt;

然后用.rel.plt的地址加上参数reloc_index,即0x08048330 + 0x10找到函数的重定位表项Elf32_Rel的指针,记作rel;

这里rel为0x8048340,所以:

然后我们将r_info>>8,即0x00000407>>8 = 4作为.dynsym中的下标;
此时我们来到.dynsym的位置,去找找strlen函数的名字符串偏移;

注意是下标,不是相对与.dynsym地址的偏移,如果是找地址偏移需要下标乘以0x10;
所以这里的name_offset = 0x00000020;
然后用.dynstr的地址加上name_offset,就是这个函数的符号名字符串st_name;

最后在动态链接库查找这个函数的地址,并且把地址赋值给*rel->r_offset,即GOT表就可以了;

现在我们仍然利用这个程序来具体看看ret2_dl_runtime_resolve的利用手法;
事实上,虚拟地址是通过最后一个箭头,即从st_name得来的,只要我们能够修改这个st_name的内容就可以执行任意函数。比如把st_name的内容修改成为"system";
而index_arg即参数n是我们可以控制的,我们需要做的是通过一系列操作。把index_arg可控转化为st_name可控;我们需要在一个可写地址上构造一系列伪结构就可以完成利用或在条件允许的情况下直接修改.dynstr;
所以我们需要在程序中找一段空间start出来,放我们直接构造的fake_dynsym,fake_dynstr和fake_rel_plt等,然后利用栈迁移的手法将栈转移到start;

r_info的计算方法是:

 
 
0x8048579 <main+90>     call   setbuf@plt <0x8048390>

   0x804857e <main+95>     add    esp, 0x10
   0x8048581 <main+98>     sub    esp, 0xc
   0x8048584 <main+101>    lea    eax, [ebp - 0x6c]
   0x8048587 <main+104>    push   eax
 ► 0x8048588 <main+105>    call   strlen@plt <0x80483b0>
        s: 0xffffbd8c ◂— 'Welcome to XDCTF2015~!\n'

   0x804858d <main+110>    add    esp, 0x10
   0x8048590 <main+113>    sub    esp, 4
   0x8048593 <main+116>    push   eax
   0x8048594 <main+117>    lea    eax, [ebp - 0x6c]
   0x8048597 <main+120>    push   eax
0x80483b0  <strlen@plt>                jmp    dword ptr [_GLOBAL_OFFSET_TABLE_+20] <0x804a014>

   0x80483b6  <strlen@plt+6>              push   0x10 //参数n
   0x80483bb  <strlen@plt+11>             jmp    0x8048380
    ↓
   0x8048380                              push   dword ptr [_GLOBAL_OFFSET_TABLE_+4] <0x804a004>
   0x8048386                              jmp    dword ptr [0x804a008] <0xf7fead80>
       ↓   
   0xf7fead80 <_dl_runtime_resolve>       push   eax
   0xf7fead81 <_dl_runtime_resolve+1>     push   ecx
   0xf7fead82 <_dl_runtime_resolve+2>     push   edx
push   0x10 //参数n
push   dword ptr [_GLOBAL_OFFSET_TABLE_+4]<0x804a004>

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2019-4-10 17:51 被钞sir编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 359
活跃值: (14015)
能力值: ( LV13,RANK:606 )
在线值:
发帖
回帖
粉丝
2
师傅,想问一下 exp 里面的那个 start 设置的有什么讲究嘛?谢谢
2020-3-4 17:01
0
雪    币: 1506
活跃值: (4411)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
3
yichen115 师傅,想问一下 exp 里面的那个 start 设置的有什么讲究嘛?谢谢[em_91]
离bss段起始位置远一点,并且要主要应该内存对齐
2020-3-30 09:56
0
雪    币: 359
活跃值: (14015)
能力值: ( LV13,RANK:606 )
在线值:
发帖
回帖
粉丝
4
钞sir 离bss段起始位置远一点,并且要主要应该内存对齐
嗯嗯,谢谢
2020-3-31 14:07
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
leave_ret = 0x0804851D师傅是怎么找到的啊,我用ropgadget找的用了不行
2022-5-6 23:02
0
游客
登录 | 注册 方可回帖
返回
//