_IO_str_overflow
의 주소를 구할 때 강의 내용 보면 아래처럼 _IO_file_jumps
의 주소를 구한 다음에 여기서 0xd8 만큼 더해서 구하는데,
io_file_jumps = libc_base + libc.symbols['_IO_file_jumps']
io_str_overflow = io_file_jumps + 0xd8
fake_vtable = io_str_overflow - 16
심볼 테이블 보면 _IO_str_overflow
함수가 있는 것 같은데 왜 아래처럼 _IO_str_overflow
를 바로 구하면 안되는 걸까요?
io_str_overflow = libc_base + libc.symbols['_IO_str_overflow']
fake_vtable = io_str_overflow - 16
그리고 _IO_str_overflow
가 _IO_file_jumps
에서 0xD8 만큼 떨어졌다는 사실은 어디서 찾을 수 있는지도 궁금합니다.
위에서 구한 fake_vtable의 값은 (libc_base + libc.symbols['_IO_file_jumps'] + 0xd8) - 16
이며 아래에서 구한 fake_vtable의 값은 (libc_base + libc.symbols['_IO_str_overflow'] - 16)
입니다. *(libc_base + libc.symbols['_IO_file_jumps'] + 0xd8)
가 _IO_str_overflow()
의 주소를 들고 있습니다. 따라서 libc_base + libc.symbols['_IO_file_jumps'] + 0xd8
와 libc_base + libc.symbols['_IO_str_overflow']
은 같지 않습니다.
또한 인자로 주어야 하는 값은 함수의 주소가 아닌 함수를 들고 있는 vtable의 값을 주어야 하기 때문에 위 방법으로 구해야만 합니다. 추가적으로 IO_validate_vtable은 vtable이 _IO_(w)file_*
을 저장해 둔 구간 사이에 있는지 검증하기 때문에 다른 임의의 주소를 vtable로 사용할 수 없습니다.
gdb에서 p _IO_file_jumps
을 입력하면 위치를 확인하실 수 있으며 x/30gx
등으로 실제 떨어진 거리가 얼마인지 확인할 수 있습니다.
저도 궁금해서 찾아봤는데 아래와 같았습니다
1.0xD8만큼 떨어진 방법을 아는 법
우선 fopen 후에 bp를 걸고 실행해보면 rax에 fp가 저장됩니다. _IO_FILE_plus가 있을텐데, _IO_FILE + vtables입니다
_IO_FILE 의 크기는 0xd0이니까 0xd8을 더하면 vtables의 주소를 구할 수 있습니다
pwndbg> x/x $rax+0xd8
0x108f338: 0x00007a29e060e2a0
pwndbg> x/x 0x00007a29e060e2a0
0x7a29e060e2a0 <_IO_file_jumps>: 0x0000000000000000
_IO_file_jumps 구조체가 있습니다.
pwndbg> p *(struct _IO_jump_t *)0x00007a29e060e2a0
$22 = {
__dummy = 0,
__dummy2 = 0,
__finish = 0x7a29e02b22d0 <_IO_new_file_finish>,
__overflow = 0x7a29e02b32b0 <_IO_new_file_overflow>,
__underflow = 0x7a29e02b2fd0 <_IO_new_file_underflow>,
__uflow = 0x7a29e02b4370 <__GI__IO_default_uflow>,
__pbackfail = 0x7a29e02b5c00 <__GI__IO_default_pbackfail>,
__xsputn = 0x7a29e02b18d0 <_IO_new_file_xsputn>,
__xsgetn = 0x7a29e02b1530 <__GI__IO_file_xsgetn>,
__seekoff = 0x7a29e02b0b30 <_IO_new_file_seekoff>,
__seekpos = 0x7a29e02b4940 <_IO_default_seekpos>,
__setbuf = 0x7a29e02b07f0 <_IO_new_file_setbuf>,
__sync = 0x7a29e02b0670 <_IO_new_file_sync>,
__doallocate = 0x7a29e02a40b0 <__GI__IO_file_doallocate>,
__read = 0x7a29e02b18b0 <__GI__IO_file_read>,
__write = 0x7a29e02b1130 <_IO_new_file_write>,
__seek = 0x7a29e02b08b0 <__GI__IO_file_seek>,
__close = 0x7a29e02b07e0 <__GI__IO_file_close>,
__stat = 0x7a29e02b1120 <__GI__IO_file_stat>,
__showmanyc = 0x7a29e02b5d80 <_IO_default_showmanyc>,
__imbue = 0x7a29e02b5d90 <_IO_default_imbue>
}
여기서 x/60gx
이렇게 아래의 값을 출력해보면, 아래쪽에 _IO_str_jumps 가 있습니다
pwndbg> x/60gx 0x00007a29e060e2a0
0x7a29e060e2a0 <_IO_file_jumps>: 0x0000000000000000 0x0000000000000000
0x7a29e060e2b0 <_IO_file_jumps+16>: 0x00007a29e02b22d0 0x00007a29e02b32b0
0x7a29e060e2c0 <_IO_file_jumps+32>: 0x00007a29e02b2fd0 0x00007a29e02b4370
0x7a29e060e2d0 <_IO_file_jumps+48>: 0x00007a29e02b5c00 0x00007a29e02b18d0
0x7a29e060e2e0 <_IO_file_jumps+64>: 0x00007a29e02b1530 0x00007a29e02b0b30
0x7a29e060e2f0 <_IO_file_jumps+80>: 0x00007a29e02b4940 0x00007a29e02b07f0
0x7a29e060e300 <_IO_file_jumps+96>: 0x00007a29e02b0670 0x00007a29e02a40b0
0x7a29e060e310 <_IO_file_jumps+112>: 0x00007a29e02b18b0 0x00007a29e02b1130
0x7a29e060e320 <_IO_file_jumps+128>: 0x00007a29e02b08b0 0x00007a29e02b07e0
0x7a29e060e330 <_IO_file_jumps+144>: 0x00007a29e02b1120 0x00007a29e02b5d80
0x7a29e060e340 <_IO_file_jumps+160>: 0x00007a29e02b5d90 0x0000000000000000
0x7a29e060e350: 0x0000000000000000 0x0000000000000000
0x7a29e060e360 <_IO_str_jumps>: 0x0000000000000000 0x0000000000000000
0x7a29e060e370 <_IO_str_jumps+16>: 0x00007a29e02b62a0 0x00007a29e02b5f10
_IO_str_jumps 구조체도 출력해보면, 네 번째 값에 __overflow가 정의되어 있습니다 (0x7a29e060e360+24)
__GI_IO_str_overflow를 가리키고 있습니다
pwndbg> p *(struct _IO_jump_t *)0x7a29e060e360
$30 = {
__dummy = 0,
__dummy2 = 0,
__finish = 0x7a29e02b62a0 <_IO_str_finish>,
__overflow = 0x7a29e02b5f10 <__GI__IO_str_overflow>,
떨어진 거리를 구하면 0xd8 차이납니다
pwndbg> p (0x7a29e060e360+24)-0x00007a29e060e2a0
$31 = 216
2.libc.symbols['_IO_str_overflow'] 와의 차이
_IO_str_jumps 구조체의 __overflow는 결국 __GI__IO_str_overflow를 가리킵니다. 다만 다른 점은 위치입니다
강의에서 설명하다시피, vtables의 주소가 __libc_IO_vtables 섹션 안에 있어야 합니다
위에서 구한 libc.symbols['_IO_file_jumps']+0xd8은 아래와 같이 __libc_IO_vtables 섹션에 존재합니다
pwndbg> info symbol 0x00007a29e060e2a0+0xd8
_IO_str_jumps + 24 in section __libc_IO_vtables of /lib/x86_64-linux-gnu/libc.so.6
하지만 libc.symbols['_IO_str_overflow'] 는 .text 섹션에 존재합니다
pwndbg> p _IO_str_overflow
$33 = {int (_IO_FILE *, int)} 0x7a29e02b5f10 <__GI__IO_str_overflow>
pwndbg> info symbol 0x7a29e02b5f10
_IO_str_overflow in section .text of /lib/x86_64-linux-gnu/libc.so.6
그래서 위의 것을 써야합니다.