B站pwn教程笔记-4
ret2syscall题目
file查看elf文件 这是静态链接,里面有大量函数。
在使用ROPgadget的时候,grep命令可以用管道符链接在后面。用于查找。有的语句一下子就可以给很多寄存器给值,这样的gadget是我们最喜欢选择的,还省事一点,如下图最后一行。
pwntools自己有个ELF对象功能。可以创建一个ELF对象,并且有许许多多的方法用在这个对象上。
比如搜索指定的字符串功能,出来的结果是一个生成器,so:next(这一串代码)就可以直接出来地址了。出来的是十进制,可以用hex转为16进制。
疑难解答环节
系统内核函数不可以直接call调用,方式是有变化的。首先就是要int 0x80,这是一个中断号,系统有不止一个中断号,但是0x80代表开始进行系统调用了。然后,通过给寄存器传特定参数,告诉系统调用特定的系统函数,如sys_execve()就是0xb
看下图,需要注意不要犯迷糊的点在于,ret后实际上已经切换到另一个栈帧了(比如从被调函数转为了主调函数的栈帧),所以pop实际上不会发生冲突,因为pop是在自己的栈帧工作的。
动态链接过程
下图还是稍微简化了,中间的过程更复杂。
有可能会出现ELF文件本身不包含int 0x80这种情况,就是gadget不好直接找。
可以用上述代码实现PIE的关闭和静态链接。其中去掉--static就是动态链接 。下图就是动态链接的函数列表,比较少了。而静态的比较多,他会把很多库函数也包括来。
动态链接这里面粉色的都是一个标记相当于,运行的时候会解析,然后去动态链接库找对应的代码。
动态链接的相关结构
只有动态链接的文件才会有
.got是全局偏移量表,是变量地址,.got.plt是函数地址。
动态链接的过程
plt是程序中解析函数真实地址的一个节,在代码段吧。保存着程序调用的动态链接库函数,比如read、foo。plt最开始的指令看图。而.got.plt是保存的数据,存放的位置是数据段。
假设存在一个foo函数在动态链接库里面。由于程序自己不含有foo的代码,所以call foo实际上是在找foo函数在plt的地方,如下图所示。
在程序首次执行foo函数 的时候,.got.plt里面本身并没有foo函数实际的地址,所以第一次plt跳转到.got.plt的时候,.got.plt会立刻跳转回去,然后plt的任务就变成了找到foo的真实地址。
这时候已经跳转回来了。push index是一个参数。最终程序会push俩参数,jmp两次,也就是执行了4条汇编代码。
index:相当于函数在plt里面的索引。
push got+4 说明用的哪个动态链接库的函数。
接下来跳转到GOT+8开始解析库函数真实地址的任务。 这里是使用了.dl_resolve这个函数,具体实现不要学了,反正弄完之后把真实地址已经给了.got.plt。
如果是第二次调用,因为已经写入了真实地址,也不再进行上述操作了,直接锁定到真实地址就可以了。
(这里的真实地址说的是foo在动态链接库里面的位置)
IDA+gdb观察动态链接过程
gcc编译的时候 ,-m32表示编译为32位。因为64位传参方式之类会有区别,但是差别不大。为了便于学习,目前还是以32位为主。但是-m32需要电脑有相关库代码,这里还是编译为64位。。。
由于此程序只调用一个puts函数。所以plt只有一个。
查看plt表。需要注意的是,默认x不带/20只会显示的少一点。
init节就是代码初始化。
看看IDA里面的plt。蓝色字体说明了对应的函数了。16个字节一个。
更高地址分别是got、.plt.got。每个是8字节,因为64位一个地址是8字节。
看看got自己存的东西,默认存的其实是plt的地址哦(vmmap看虚拟内存地址)
此时刚调用puts。got表存储的就已经是puts真实地址,使用disass反汇编这个地址的机器码看看。
ret2libc
几个动调知识
1.无法返回上一步的状态。想看上一步的状态只能在上一步打一个断点,run到断点处。
2.start:优先停在main函数第一行,然后是程序入口第一行。
backtrace:就像函数调用栈状态。main调用了-->my_puts()
return:执行到函数末尾了。
方法介绍
也需要ROP创造执行shellcode的环境。但通常返回的是动态链接库里面。
难点:因为是动态链接,自带的gadget较少。
注意,这里有个干扰函数,但是这里的system函数确实给plt表增加了一个表项(前提是动态连接的软件),相当于知道system地址了。我们就可以让她在libc执行一个system。
因为是32位,我们要在栈上控制一手参数,让system函数的参数变成有用的。
参数都是在父函数。最终栈帧构造如下(以后会详细讲解):
最后一个知识点:C语言传递字符串参数传递的是起始指针。字符串存在.rodata段的地方。所以system("/bin/sh")实际上是下面: