小白垃圾笔记而已,不建议阅读。
本来是仅仅写的文字,因为我并没有调试出来,在群里问了师傅后才知道是因为我开起了
full Pelro保护。
按理说应该关闭的,或者开启部分也可以。 gcc -z lazy -o test test.c // 部分开启, 即Partial RELRO
gcc -z norelro -o test test.c // 关闭, 即No RELRO。
gcc -z lazy test.c -o file3 -m32
明天再写。。。。。。。。。。。。。先不要看。。。。
plt和got本来就存在于elf文件,也就是说他们在磁盘里躺着的时候就已经有了,只是,那个时候他们还是一个占位符。并不是真正的地址。
plt和got是如何结合实现外部函数(glibc)的调用的呢?假如说程序要调用puts()函数。
当函数第一次调用系统函数的时候,(此时程序并不知道所要调用的系统函数(puts)对应libc中对应的地址)
会先去找plt表,plt表里有什么呢??
plt表有一个跳转指令,有一个地址,这个地址是got表中存放的该函数在libc中对应的地址。刚开始got表中对应的并不是libc中的真实地址,而是plt表的地址,是刚刚跳转过来地址的下一跳地址。
因为这个时候got表存储的是plt表中的下一条指令地址。
上述过程意思就是plt->got->plt
好好的为啥要跳过来呢?因为我们需要plt表调用函数,掉用什么函数呢?调用查找puts函数在glibc中对应地址的函数。
如何实现?
在函数对应的plt表中第一行是跳转指令,跳转到got表对应地址(刚开始got中对应的地址是跳转指令的下一条指令也就是下边的push),第二条是push,将该函数对应的一个固定的数入栈,第三条指令是跳转:跳转到plt表前边的一个函数,这个函数会去libc中找该函数对应的地址,然后填充到对应got表的地址,并且跳转过去执行。
这个函数调结束后会调用got表对应地址会填充为刚刚调用函数在libc中的真正地址。并且会执行刚刚调用的函数。
那么第二次再次调用的时候会怎样呢?
和第一次刚开始是一样的。去plt表找地址,plt第一条指令跳转到got,与第一次不同的是该函数got表这个时候对应的地址是真实的地址而不是plt表的第二条指令的地址,那么就会直接调用puts库函数(libc中的)。