⭐ 이번 시간은 저번 시간보다 중요한 명령어를 배운다!
val을 스택 최상단에 쌓음
📌 rsp란?
현재 스택의 최상단 주소를 갖고있는 레지스터
rsp -= 8 ; 왜 감소인가? 메모리 방향때문 어쩌구 저쩌
[rsp] = val
;[Register]
rsp = 0x7fffffffc400
;[Stack]
0x7fffffffc400 | 0x0 <= rsp
0x7fffffffc408 | 0x0
;[Code]
push 0x31337
;[Register]
rsp = 0x7fffffffc3f8
;[Stack]
0x7fffffffc3f8 | 0x31337 <= rsp
0x7fffffffc400 | 0x0
0x7fffffffc408 | 0x0
스택 최상단의 값을 꺼내서 reg에 대입
rsp += 8 ; 스택 주소는 반대임 그냥 받아들일 것
reg = [rsp-8]
;[Register]
rax = 0
rsp = 0x7fffffffc3f8
;[Stack]
0x7fffffffc3f8 | 0x31337 <= rsp
0x7fffffffc400 | 0x0
0x7fffffffc408 | 0x0
;[Code]
pop rax
;[Register]
rax = 0x31337
rsp = 0x7fffffffc400
;[Stack]
0x7fffffffc400 | 0x0 <= rsp
0x7fffffffc408 | 0x0
📌 프로시저란?
특정 기능을 수행하는 코드 조각, 어셈블리어에 함수같은 거라고 생각하자
⭐ 호출할때는 프로시저 실행 후 원래 실행 흐름으로 돌아와야 하므로 call 다음에 명령어 주소(return address, 반환주소)를 스택에 저장하고 프로시저로 rip를 이동
addr에 위치한 프로시져 호출
push return_address
jmp addr
;[Register]
rip = 0x400000
rsp = 0x7fffffffc400
;[Stack]
0x7fffffffc3f8 | 0x0
0x7fffffffc400 | 0x0 <= rsp
;[Code]
0x400000 | call 0x401000 <= rip
0x400005 | mov esi, eax
...
0x401000 | push rbp
;[Register]
rip = 0x401000
rsp = 0x7fffffffc3f8
;[Stack]
0x7fffffffc3f8 | 0x400005 <= rsp ; 다시 돌아갈 주소가 스택에 쌓임
0x7fffffffc400 | 0x0
[Code]
0x400000 | call 0x401000
0x400005 | mov esi, eax
...
0x401000 | push rbp <= rip
스택 프레임 정리
📌 rbp란?
스택의 시작점, 바닥을 가리키고 있는 레지스터
rsp은 꼭대기이므로 반대
mov rsp, rbp
pop rbp
;[Register]
rsp = 0x7fffffffc400
rbp = 0x7fffffffc480
;[Stack]
0x7fffffffc400 | 0x0 <= rsp
...
0x7fffffffc480 | 0x7fffffffc500 <= rbp
0x7fffffffc488 | 0x31337
;[Code]
leave
;[Register]
rsp = 0x7fffffffc488
rbp = 0x7fffffffc500
;[Stack]
0x7fffffffc400 | 0x0
...
0x7fffffffc480 | 0x7fffffffc500
0x7fffffffc488 | 0x31337 <= rsp
...
0x7fffffffc500 | 0x7fffffffc550 <= rbp
return address로 반환
pop rip
;[Register]
rip = 0x401008
rsp = 0x7fffffffc3f8
[Stack]
0x7fffffffc3f8 | 0x400005 <= rsp
0x7fffffffc400 | 0
;[Code]
0x400000 | call 0x401000
0x400005 | mov esi, eax
...
0x401000 | mov rbp, rsp
...
0x401007 | leave
0x401008 | ret <= rip
;[Register]
rip = 0x400005
rsp = 0x7fffffffc400
[Stack]
0x7fffffffc3f8 | 0x400005
0x7fffffffc400 | 0x0 <= rsp
;[Code]
0x400000 | call 0x401000
0x400005 | mov esi, eax <= rip
...
0x401000 | mov rbp, rsp
...
0x401007 | leave
0x401008 | ret
cat flag
를 실행하면, cat은 flag라는 파일을 읽어서 사용자의 화면에 출력해 줘야 합니다. 그런데 flag는 파일 시스템에 존재하므로 이를 읽으려면 파일시스템에 접근할 수 있어야 합니다. 유저 모드에서는 이를 직접 할 수 없으므로 커널이 도움을 줘야 합니다. 여기서, 도움이 필요하다는 요청을 시스템 콜이라고 합니다. 유저 모드의 소프트웨어가 필요한 도움을 요청하면, 커널이 요청한 동작을 수행하여 유저에게 결과를 반환합니다. x64아키텍쳐에서는 시스템콜을 위해 syscall
명령어가 있습니다. 시스템 콜 System Call
유저 모드에서 커널 모드의 시스템 소프트웨어에게 어떤 동작을 요청하기 위해 사용
요청: rax
인자 순서: rdi → rsi → rdx → rcx → r8 → r9 → stack
;[Register]
rax = 0x1
rdi = 0x1
rsi = 0x401000
rdx = 0xb
;[Memory]
0x401000 | "Hello Wo"
0x401008 | "rld"
[Code]
syscall
;-----------------;
;output
Hello World