加深PLT-GOT表机制的理解

加深PLT-GOT表机制的理解

之前的一篇讲libc的文章中讲过有关plt-got表的延迟绑定机制,而覆盖got表的方法也早已称为pwn中最常用的技巧之一;但是笔者近期闲来无事对改机制进行了更详细的逆向分析,有了一个更加清晰的图景,借此文分享一下:

分析就得事必躬亲,自行找一个有libc调用的程序,32位64位皆可,丢进IDA里面去看PLT表,快捷点的方法就是找个call <libc_func>双击函数名一跟,比如我们下面这个例子:

TIM截图20181112163637

我们随便找个函数看看,就选exit吧:

TIM截图20181112164049

可以看到:PLT表中,exit表项其实是一条jmp指令,这可能和我们的习惯理解有出入,我们习惯思维里面一般感觉表都应该是存一些数据(如地址),但是实际上这里是一个jmp跳板。那么jmp跳到哪呢?就是cs:exit_ptr,最近学了计组才明白这是一个寄存器变址寻址,cs代表一个独立的小代码段(code segment)。

cs段:

往往是由单位指令长(32位/64位)整数倍的地址开始,以一系列align对齐伪命令结尾,可能是为了方便寻址吧,具体作用之后有机会再聊,现在只需要了解这两个特点就好。

在PLT表中,每个jmp跳板其实都是一个cs段,想看的自行看IDA。

我们现在来看一下plt中jmp跳板项的HEX,以exit为例:

TIM截图20181112165458

其中,FF 25代表的就是jmp指令,读者不妨自行看看其他plt表项,每个plt表项的头两个字节都是FF 25;后面的5A 08 20 00是小端序的一个地址偏移,我们刚刚说了此处是寄存器变址寻址,我们现在不妨来看exit的got表:

TIM截图20181112165831

可以看到got表地址的小端序是:E0 0F 20 00,与上面的5A 08 20 00的确不同(寄存器变址寻址),我们做个差,算得结果为:0x786,我们到exit的plt项再看,双击jmp cs:exit_ptr中的cs这个词:

TIM截图20181112170518

我们看到,cs段的End address正是0x786,这就是通过偏移计算出got表地址的过程(这里还是一个间址寻址)

好,现在我们去看got表在初始的时候(未绑定的时候)是个什么样子:

TIM截图20181112191051

未绑定时,got表的值就是0x201050,这个地址处的东西就是上面的extrn,可见:

在延迟绑定机制下,第一次调用某个libc函数时(未绑定时),就会执行到上图的位置,进行extrn将libc中相应函数的真实地址扩展进来,扩展的过程实现了将got表项改写为函数的真实RVA,这个过程就叫做“绑定”!

绑定以后,第二次、第三次再调用这个函数的时候,jmp到的就不是0x201050了,而是jmp到函数的真实地址了!

有关漏洞挖掘:

1.我们篡改的都是got表,而从未听说过篡改plt表这种操作,现在了解了plt表项的实质是一个指令后就明白了,代码段根本就不可写。

2.可供篡改的字节有限时:考虑延迟绑定状态!假如说我们只能获得有限字节数的任意写内存的机会,我们又想要覆盖got表,在某些情形下可能就需要覆盖某些函数的地址高位被随机化的字节,而不是全部字节,目的就是实现当下次调用受害函数时劫持到目标地址,在这种情况下,我们需要考虑在我们进行改写时函数的绑定状态,因为绑定和未绑定时got表中的那个地址值是不一样的,而我们并不是篡改每一个字节!

谢谢阅读!

posted @ 2018-11-12 19:35  Magpie#Canary  阅读(1128)  评论(0编辑  收藏  举报