첫번 째 PLT GOT 동작 순서는 PLT ( puts@plt) -> GOT -> PLT (<puts@plt+6>) -> _dl_runtime_resolve_xsavec 이잖아요.
그래서 gdb로 따라가 보니
► 0x4003f0 puts@plt jmp qword ptr [rip + 0x200c22] <GLOBAL_OFFSET_TABLE+24>
0x4003f6 <puts@plt+6> push 0
0x4003fb <puts@plt+11> jmp 0x4003e0 <0x4003e0>
↓
0x4003e0 push qword ptr [rip + 0x200c22] <GLOBAL_OFFSET_TABLE+8>
0x4003e6 jmp qword ptr [rip + 0x200c24] <_dl_runtime_resolve_xsavec>
↓
0x7ffff7dea8f0 <_dl_runtime_resolve_xsavec> push rbx
입니다.
si와 ni를 통해 따라가면 순서대로
0x4003f0 puts@plt jmp qword ptr [rip + 0x200c22]
0x4003f6 <puts@plt+6> push 0
0x4003fb <puts@plt+11> jmp 0x4003e0
0x4003e0 push qword ptr [rip + 0x200c22]
0x4003e6 jmp qword ptr [rip + 0x200c24]
0x7ffff7dea8f0 <_dl_runtime_resolve_xsavec> push rbx
로 실행이 됩니다.
그러나
pwndbg> got
GOT protection: Partial RELRO | GOT functions: 1
[0x601018] puts@GLIBC_2.2.5 -> 0x4003f6 (puts@plt+6)
를 보면 puts@plt+6 주소(0x4003f6)는 got 0x601018에 들어있어야 하는데 막상
0x4003f0 puts@plt jmp qword ptr [rip + 0x200c22]
에서 점프할 곳의 주소 qword ptr [rip + 0x200c22] 값이 got엔트리값 [0x601018]이 아닌
0x601012나옵니다. (아래 명령어로 확인시)
pwndbg> x/gx $rip
0x4003f0 puts@plt: 0x006800200c2225ff
pwndbg> x/gx $rip + 0x200c22
0x601012: 0x03f600007ffff7de
여기에는 당연히 0x601018에 들어있는 puts@plt+6(0x4003f6
) 주소가 안들어 있고요.
pwndbg> x/gx 0x601018
0x601018: 0x00000000004003f6
그래서 0x601012: 0x03f600007ffff7de 주소 값을 확인해 보면
pwndbg> x/gx 0x03f600007ffff7de
0x3f600007ffff7de: Cannot access memory at address 0x3f600007ffff7de
이라고 나옵니다. 내부적으로 0x601012거쳐서 0x601018 로 이동하고 이안의 값 puts@plt+6(0x4003f6)으로 점프하나요?
마찬가지로
0x4003e0 push qword ptr [rip + 0x200c22] <GLOBAL_OFFSET_TABLE+8>
► 0x4003e6 jmp qword ptr [rip + 0x200c24] <_dl_runtime_resolve_xsavec>
↓
0x7ffff7dea8f0 <_dl_runtime_resolve_xsavec> push rbx
0x4003e6: jmp QWORD PTR [rip+0x200c24] # 0x601010
$rip 는 0x4003e6이나 x/x $rip+0x200c24 주소는 0x601010 이 아닌 0x60100a 입니다. 역시나 내부 적인 과정을 통해 0x601010까지 점프하게 되는 것인지요?
명령어를 제대로 쓰지 못해서 그런것인지 .. 혹시 아시는 분 계실지요..ㅠㅠ
jmp qword ptr [rip + 0x200c22]
는 기계어로 \xFF\x25\x22\x0C\x20\x00
입니다.
일반적으로 Reduced Instruction Set Computer (RISC)인 MIPS나 ARM에서는 명령어 크기가 일정하지만,
Complex Instruction Set Computer (CISC)인 x86-64 아키텍처에서는 명령어 크기가 반드시 64비트가 아닐 수 있습니다.
GDB에서 RIP가 가리키는 곳 즉 화살표로 표시되는 곳은 다음에 실행할 명령어를 가리키고 있는 것입니다!
si
명령어를 실행하면 그제서야 기존에 화살표가 가리키고 있던 명령어를 실행합니다.
네 그게 이상한 점인데 제 gdb에서는 RIP가 가리키는 곳 즉 화살표로 표시되는 곳은 현재 실행 중인 명령어 이고RIP에도 그 주소가 저장되어 있습니다. *RIP 0x4003f0 (puts@plt) ◂— jmp qword ptr [rip + 0x200c22] ───────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────── ► 0x4003f0 <puts@plt> jmp qword ptr [rip + 0x200c22] <_GLOBAL_OFFSET_TABLE_+24> 0x4003f6 <puts@plt+6> push 0 이렇게요.. 0x4003f0 <puts@plt> 를 실행 중일때 rip를 보면 0x4003f0 값이 나오는데요 화살표가 0x4003f0을 가리키며 실행 중일 때 rip는 왜 다음 명령어인 0x4003f6를 가리키지 않는 것일까요?
라는 위 대댓글에 답변을 드리려는데 줄바꿈이 불편해서 여기에 씁니다.
- 일단 '현재 실행 중인 명령어'라는 표현이 gdb에서는 부적합할 수 있습니다. (부적합하기보다는, 어휘에 따라서 상황 이해를 어렵게 할 수 있습니다.)
0x4003f0 puts@plt jmp qword ptr [rip + 0x200c22]
가 만약 실행 중인 명령어라면, gdb는 어디에서 멈춰있는걸까요?
보다 쉽게 생각하기 위해서0x4003f0 mov rax, rdx
와 같이 생각하기 쉬운 친구로 바꿔봐도 괜찮습니다.
$rip --> 0x4003f0 mov rax, rdx
라면, 지금 gdb로 보고있는 프로그램은 뭘 하고 있을까요? rdx의 값을.. 천천히.. rax에.. 복사하는 중일까요? 아니면 이전 명령어를 "실행 중" 일까요..?
특수한 상황을 제외하면 유저 입장에서 각 인스트럭션은 'atomic' 하다고 봐도 무방합니다.
따라서 우리가 ni, si
등을 통해 다음 인스트럭션을 '실행하도록' 명령을 주는게 아니면 "실행 중인" 명령어는 없는 것과 같습니다.