00:00
嗯,大家好,按照之前的进度,我们应该是看return to Le了,嗯,但是为了方便理解吧,我们先看一下额外的内容,就是Linux里面的动态链接和延迟绑定相关的内容,那Linux下的动态链接它是通过PT和交替表达实现的,这里我们通过一个实验来理解一下,就是实验用到的代码。啊,我先把我之前做的删掉,然后通过。啊。哎呀。傻了。通过这条命令让他编译一下。
01:01
这样除了原有的test.c我们还有一个test.o以及可执行文件test,就是说这两个,那我们通过OG dump,然后杠D可以看到它的这个返回编号的内容。我们来跟源代码对比一下。在原代码的主函数里面,我看到它调用了一个print-banner的函数,这是自己写的吗?然后print-B里面调用了一个C语言的库函数print f,那在这对应的就是。这一串,那我们可以看到,在因为print iPhone10C语言在g Le动态库里面的,只有当运行起来的时候才能确定地址,那此时呢,它是先用。啊,这就这些东西,然后是有符号数的负四来代替。
02:02
那。运行时进行重定位的话,它是没有办法直接修改这里这个代码段的内容的,也就是说它不能把这个把这一块。给它变成它真正的print f的地址,它只能把print f重叠位到数据段,嗯,但是因为你已经编译好了这个东西,你说我怎这个还这个程序怎么才能找到它重定位的那个地址啊,啊,这时候链接器啊,它会生成一小段额外的代码,这段代码可以用来获取print f的地址,嗯,代码就像下面这样。首先啊,你通过重定位以后,把print f的地址存在数据端里面啊,然后这是调用print f的那个Co,令它改成了去调用这个函数,把这个函数会通过。
03:04
Mo ex,就是说把存在这里的print f函数的那个地址放到ex里面,然后再jump过去啊,那想要实现这种功能的话。我们需要。两个东西,第一个是存放外部函数地址的数据段,也就是这一块,第二个呢,是用来记录这个外部就是。来找,来找这个数据段内容的这个函,一个代码就是这样,上面这一块,那相对应的它就产生了两个表,一个呢,是用来存放函数地址的数据数据表,也就是说下面这一个的表叫做全局偏移表,就是got表,那另一个呢,存放额外代码代码的那个表叫做程序链接表,也就是PG表。
04:01
那简单的看就是下面这种情况了,那如果我想调用PF函数,我先去PRD表里面找到对应的,再去通过PRD表里面记录的在各表项的内容,再去找那个真实的地址。那我们发现,如果想要。Plt表正能够通过它获取到函数的地址时候,那你首先G表你得有它的正确的地址才行啊,但是如果一开始就对所有调用到的函数进行重定位的话是比较麻烦的。而且。在Linux下面。是往后拖,拖延了一下,就是说引入了延迟绑定机制,就是说只有动态库的函数被调用的时候,也就是说我执行到。F函数了,我要用到它,那我才会去进行。重定位和地址解析工作,嗯,那这样我们可以用这样的类似的代码来实现,就是说我要调用print f这个函数,那它的plt表里面是首先跳到了plt at go这样的地址上的内容,那一开始这个地址填的是找print f这个函数。
05:23
就是这个lookup-print f这个函数的作用是找到print f的地址,那它跳过来以后,通过重叠位函数找到print的地址,并且把它写到print f at go这个表项上。他在回去再走的时候,就可以通过jump直接跳转到print f这个函数去执行了。那你就是说这样的机制,如果不知道print f的地址,那你去找一下,然后再知道的话,就直接账我去执行,就是就是说只找一次就可以了,对吧,那我们再来看一下它是怎么长的。
06:06
通过OG dump可以直接看它的汇编嘛,对吧,我们看直接看一下可执行程序,就是已经经过链接的那个o Du-d test,我们直接看一下它的返回边。嗯,这是他的那个PT。那其实在OG dump它返回边的时候,PT表象第一个是没有符号名的,然后它自动的给它添,添加为离它最近的那一个了,然后为了避免误会,可以把它改成common,就是公共的意思,那其实看后面的话,发现确实是可以讲common的啊。而且。根据上面这种这样的。
07:02
我们自己想出来的伪代码吧,是吧,可以。想到他第一个帐篷的地址。实际上就是,嗯,比如说它是puts,那它就是puts and got这个地方。嗯。那我们可以通过,就是说它第1PT表的第一条指令,第一条帐篷就是跳到got表里面的,对吧,而而且got表的内容的话,我们可以通过GDB来看一下,就是说。再看一个GDP。现在他帐的地址是这个地方,我们复制出来。
08:08
我们可以看到它里面的内容是什么,是它的下一条指令。在这个地方。也就是说,即使你去到他的高德表象,而它高德表象填的内容是让你再回来去执行下面这一个,为什么?因为他还没有。执行过这个puts函数,所以它的地址没有填在高特表项,而是让填的是那个寻找puts函数的那个地址,那你就是说接下来的内容,我们就可以去找这个POS函数了,它。那我们看一下他做了什么?他回来以后,首先是执行这两条命令,把零给压到站里面,它会作为一个参数啊,这个会作为后面会用到的函数的参数,然后它jump的一个地址,那这个地址我们会发现它就是第一个。
09:06
第一个标题表象的内容。那我们到了第一个以后,就去执行第一个的plt表,那它首先会push,这也是作为一个参数用到的,然后再jump jump到这个地方。那对应这边我们看一下。占到这个地址,在没有运行之前啊,它是全零的。那我们进行等它开始走的时候再看,它变成了这个地址啊,这个地址里面存的是什么呢?存的是一个运行后再重定位的一个函数。
10:02
好,到目前为止我们做一个小的总结啊,就是说如果我们想调用一个没有被调用过的函数,那它是按照这个过程来调用的,首先在它的PT表里面找,然后找到了,我发现它是指向了在got表一个地址啊,Got表的那个地址指向的就是它PT表那个jump指令的下一条,我们又回到了plt。就是说。又回到了我们,原本我们在这里帐篷以后,它又回到了这个地方,那我们继续执行以后,它又到了公共的这个PRT表象,公共的PT表象以后再进行降跑,它去的就是那个运行时重定位的那个函数了。那通过这个函数我们是可以找到我们要找到那个用到的函数的地址的,那现在我们需要知道这个函数它是怎么找到我们要用的那个函数的。
11:00
不对,他他是怎么知道我们要找我们那个函数的啊,还有是他找到函数的地址以后,会怎么知道填到哪好,那第一个问题的话,我们之前在这个地方,就是他自己的那个表题表情里面,它接做了一个push操作,那这一个其实不同的你会发现。不同的PT表现它是不一样的,这里是零叉零,这里是零叉八,那这个它是实际上就代表了一个函数的ID,去告诉这个重定位函数找哪个函数的地址。而且在elf的文件里面,这里面保存了重叠位表的信息,我们可以通过瑞德EF看一下。
12:03
这个地方。这里面这个值我们看一下。804A00C,它对应的是。这个地方你就是他的个表象的地址。那也就是说它会填到它的高特表象地址,就是在这个表里面的这个偏移量。然后。嗯,到这就差不多了,待会我们跟着大佬的流程图来走一遍,还有一点就是说got表前三个。是特殊的,那第三个就是存放着这个重叠位函数的地址,好啊,我们来捋一遍啊,首先你要去调用一个函数。它会来到它的标题表,然后走一步,这里他要jump吗?而jump到的那个地址存放的内容是它的下一条指令。也就是说,它。
13:12
这样回来了。这个星号是指针嘛,对吧,它里面的地址它在。是他要真正跳到的那个地方,所以我们继续走,然后上来你看跳到了公共的P题表象,再继续往下走的话,它进行他走的话,在第三项这个里面填的实际上是。这个函数的地址。实际上是这个函数的地址,那到了到了这个函数以后,它会做两件事情,第一是把got表象,也就是。它调,因为因为它是找这个函数嘛,那它对应的这个地址就是它的高表现了,改成这个函数的那个。
14:06
地址,然后再去让你调用这个函数。就是在没有调用过之前,第一次去调用这个函数的时候,那第二次的话,因为你这里它已经被这个函数给改掉了,改成直接是你想要的那个函数的地址,你就直接这样顺畅的拿一遍就走完了啊,这就是。小弟表和高的表。这样的一个机制吧。
我来说两句