B站 XMCVE Pwn入门课程学习笔记(4)(不断更新)
ret2syscall:
先来回顾一下,这道题是静态链接
补充一下xor异或:
逻辑与:&& and 必须两个操作数全部都是1,才是1
逻辑或: || or 只要有一个是1答案就是1
汇编里异或就是xor 只要有一个不一样就是1,一样的是0
另:二进制中,当符号位为1时(即首个为1),表示的十进制数字为负数。
反码:正数反码 = 原码,负数反码 = 原码符号位不变,其余位取反。 如-5的反码为11111010。
补码:正数补码 = 原码,负数补码 = 反码 + 1
现在负数通常用补码表示,其表示简单,且在CPU里可以用加法实现减法运算
xor 相同寄存器(相同寄存器里村的数据是一样的)结果为0
重新回到这题
输入的地址在这里,需要更长的地址获得ebp在哪里
写入缓冲区与ebp距离为108,总共需要写112+return address
写脚本攻击,用到flat函数
gadget要和下面效果一样
需要用到以下指令
| 为管道符,是将前面的数据输出当作后面的输入
grep是把输入中含有后面字符串行输出
同样的要向ebx、ecx、edx,下面那行可以同时把三个包括
payload,运行获得shell
总体下来就是,先112长度的垃圾数据,后面就是gadget,需要用rop,发现两个gadget地址,每一个gadget后面对应的就是要传入的参数,传参之后,第二个gadget(3个参数)到第三个(int 80),send过去,就可以电泳interactive进行交互
系统调用:
其实对于PWN的知识,到现在我其实依旧云里雾里,需要不断地回想。这个老师讲的真的很好,这里正好重新讲了一遍。
Kenel空间操作系统内核的函数,只会给一个接口
一般函数调用:
C函数就是运行汇编,先传参数,再用call指令即可,这是用户自己写的,即Kenel下面用户空间。
直接call即可
系统调用:
int为中断指令
如果想用execve,要通过寄存器(对应eax)传参给call,eax保存系统调用号
sys_write为1 sys_execve为11,0xb
调用0x80要为系统调用传递参数
调用0x80得到bin/sh
回顾payload构造,就是陆续进行覆盖
程序在执行完main后就返回到pop_eax_ret,把eax下一个字长的数据弹到eax里,把下下爱一个字长的数据弹到eip里,进行execve系统调用,里面保存的值必须为0xb,把0xb弹出到eax中,ret,把紧邻的下一个地址弹出到eip里,执行地址里的代码。以次类推,分别pop数据到ebx,ecx,edx里。利用pwntools获得ebx(bin/sh)的地址,最后int 80
覆盖内容:
payload:
动态链接:
基于没有给gadget。中间过程由gcc完成
动态链接的代码在装载步骤可见,静态链接的代码的步骤在链接过程可见
改为静态链接
查看发现静态链接占的内存大很多
动态链接里的puts就像是一个表象(粉色底),没有函数体
而静态链接里的puts有函数体,还会调用其它函数体。函数都必须保存在各自内部
动态链接的相关结构:
.got是全局偏移量表,是变量地址,.got.plt是函数地址。
动态链接过程:
执行代码段需调用foo,不能直接跳到foo,需要代码中的PLT节,每一个动态链接库中的函数都会在PLT节中创建一个表项
call foo后会跳转到plt foo(进程首次调用foo)表项,.plt中的代码会立即跳转到.got.plt中记录的地址,但是got plt中还没有想要的地址,就会跳回到foo plt。接下来就是要找到foo函数的真实地址,并跳到foo
可以相当于plt是菜单,got是食物的位置
push index是一个参数,最终程序会push俩参数,jmp两次,也就是执行了4条汇编代码。
这里的一些地址其实我也不太懂
然后就可以跳到dl_resolve进行解析找到foo函数的实际地址。
第二次调用foo:
就相当于你第一次点外卖不知道每家店的电话号码(地址),动态链接相当于“懒人外卖系统”,第一次需要查电话本,以后每次直接拨号(看人家比喻的)
找到foo地址后直接指向foo里的代码
整个过程:
查看plt:
检查对应地址中前20个的值,一个表项是16个字节
具体查看一下
汇编语言中,init用来初始化,接着就是plt
分别对应了pts,printf,exit表项,每一个表项的长度为0*10,16字节,也印证了之前的。包括内容也和之前的一样
往下滑(高地址),可以看到got表项,为8字节