Opcode: 스택
x64 아키텍쳐에서는 다음의 명령어로 스택을 조작할 수 있음
push val: val을 스택 최상단에 쌓음 (연산: rsp -= 8, [rsp] = val)
[Register]
rsp = 0x7fffffffc400
[Stack]
0x7fffffffc400 | 0x0 ≦ rsp
0x7fffffffc408 | 0x0
[Code]
push 0x31337
해석
rsp(Stack Pointer): 현재 스택의 최상위 주소
rsp 주소에 현재 스택의 최상위 값이 존재 - '0x0'
rsp 주소에서 8바이트(64비트 아키텍처에서는 8바이트가 한 워드) 위로 올라가면 또 다른 8바이트 값이 있음 - '0x0'
스택에 0x31337 푸시 - c400 - c3f8 -> 8만큼 차이
결과
[Register]
rsp = 0x7fffffffc3f8
[Stack]
0x7fffffffc3f8 | 0x31337 ≦ rsp
0x7fffffffc400 | 0x0
0x7fffffffc408 | 0x0
pop reg: 스택 최상단의 값을 꺼내서 reg에 대입 (연산: reg = [rsp], 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
Opcode: 프로시저
특정 기능을 수행하는 코드 조각
호출(Call): 프로시저를 부르는 행위
반환(Return): 프로시저에서 돌아오는 것
call 다음의 명령어 주소(return address, 반환 주소)를 스택에 저장하고 프로시저로 rip 이동
x64 어셈블리언어에는 프로시저의 호출과 반환을 위한 call, leave, ret 명령어 존재
call addr: 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(명령 포인터 레지스터), rsp(스택 포인터)
after call 0x401000 - 현재 위치의 다음 명령어의 주소(0x400005)가 스택에 푸시됨
rsp는 8만큼 감소하여 스택의 새로운 맨 위를 가리킴
결과
[Register]
rip = 0x401000
rsp = 0x7fffffffc3f8
[Stack]
0x7fffffffc3f8 | 0x400005 <= rsp
0x7fffffffc400 | 0x0
[Code]
0x400000 | call 0x401000
0x400005 | mov esi, eax
...
0x401000 | push rbp <= rip
leave: 스택프레임 정리
연산: mov rsp rbp / pop rbp
예제
[Register]
rsp = 0x7fffffffc400
rbp = 0x7fffffffc480
[Stack]
0x7fffffffc400 | 0x0 <= rsp
...
0x7fffffffc480 | 0x7fffffffc500 <= rbp
0x7fffffffc488 | 0x31337
[Code]
leave
해석
Register(레지스터): rsp(스택 포인터), rbp(베이스 포인터)
mov rsp, rbp / pop rbp
leave 명령: 현재 함수의 프롤로그에서 설정된 스택 프레임이 제거됨
rsp가 rbp로 복원되고 rbp의 원래 값인 0x7fffffffc500이 rbp로 복원됨
결과
[Register]
rsp = 0x7fffffffc488
rbp = 0x7fffffffc500
[Stack]
0x7fffffffc400 | 0x0
...
0x7fffffffc480 | 0x7fffffffc500
0x7fffffffc488 | 0x31337 <= rsp
...
0x7fffffffc500 | 0x7fffffffc550 <= rbp
스택 프레임이란?
함수별로 자신의 지역변수 또는 연산과정에서 부차적으로 생겨나는 임시 값들을 저장하는 영역
스택 영역을 구분 없이 사용한다면, 서로 다른 두 함수가 같은 메모리 영역을 사용할 수 있음
A라는 함수가 B라는 함수를 호출하는데, 같은 스택 영역을 사용한다면 B에서 A의 지역변수를 모두 오염시킬 수 있음, B에서 반환한 뒤 A는 정상적인 연산을 수행할 수 없음
ret: return address로 반환
연산: pop rip
예제
[Register]
rip = 0x401021
rsp = 0x7fffffffc3f8
[Stack]
0x7fffffffc3f8 | 0x400005 <= rsp
0x7fffffffc400 | 0x123456789abcdef
[Code]
0x400000 | call 0x401000
0x400005 | mov esi, eax
...
0x401000 | push rbp
0x401001 | mov rbp, rsp
0x401004 | sub rsp, 0x30
0x401008 | mov BYTE PTR [RSP], 0x3
...
0x401020 | leave
0x401021 | ret <= rip
해석
Register: rip(명령 포인터 레지스터), rsp(스택 포인터)
Stack: rsp 주소에 현재 스택의 맨 위 값이 있음, 0x400005
rsp 주소에서 8바이트 아래로 내려가면 다음 슬롯이 있고 값은 0x123456789abcdef
call 0x401000: rip은 0x401000으로 변경됨
call 0x401000: 스택과 레지스터 상태
결과
[Register]
rip = 0x400005
rsp = 0x7fffffffc400
[Stack]
0x7fffffffc3f8 | 0x400005
0x7fffffffc400 | 0x123456789abcdef <= rsp
[Code]
0x400000 | call 0x401000
0x400005 | mov esi, eax <= rip
...
0x401000 | push rbp
0x401001 | mov rbp, rsp
0x401004 | sub rsp, 0x30
0x401008 | mov BYTE PTR [RSP], 0x3
...
0x401020 | leave
0x401021 | ret
스택 프레임의 할당과 해제
func 함수를 호출, 다음 명령어의 주소인 0x4000005는 스택에 push
main: rip
stack: rsp(0x7fffffffc400), rbp(0x7fffffffc480)
스택
push val: rsp를 8만큼 빼고, 스택의 최상단에 val을 쌓음
pop reg: 스택 최상단의 값을 reg에 넣고, rsp를 8만큼 더함
프로시저
call addr: addr의 프로시저 호출
leave: 스택 프레임 정리
ret: 호출자의 실행 흐름으로 돌아감
Q1. 레지스터, 메모리 및 코드가 다음과 같다. Code를 1까지 실행했을 때, rax에 저장된 값은?
[Register]
rbx = 0x401A40
=================================
[Memory]
0x401a40 | 0x0000000012345678
0x401a48 | 0x0000000000C0FFEE
0x401a50 | 0x00000000DEADBEEF
0x401a58 | 0x00000000CAFEBABE
0x401a60 | 0x0000000087654321
=================================
[Code]
1: mov rax, [rbx+8]
2: lea rax, [rbx+8]
0xC0FFEE
Q2. Code를 2까지 실행했을 때, rax에 들어있는 값은?
0x401A48
Q3. 레지스터, 메모리 및 코드가 다음과 같다. Code를 1까지 실행했을 때, rax에 저장된 값은?
[Register]
rax = 0x31337
rbx = 0x555555554000
rcx = 0x2
=================================
[Memory]
0x555555554000| 0x0000000000000000
0x555555554008| 0x0000000000000001
0x555555554010| 0x0000000000000003
0x555555554018| 0x0000000000000005
0x555555554020| 0x000000000003133A
==================================
[Code]
1: add rax, [rbx+rcx*8]
2: add rcx, 2
3: sub rax, [rbx+rcx*8]
4: inc rax
0x3133A
Q4. Code를 3까지 실행했을 때, rax에 저장된 값은?
0
Q5. Code를 4까지 실행했을 때, rax에 저장된 값은?
1
Q6. 레지스터, 메모리 및 코드가 다음과 같다. Code를 1까지 실행했을 때, rax에 저장된 값은?
[Register]
rax = 0xffffffff00000000
rbx = 0x00000000ffffffff
rcx = 0x123456789abcdef0
==================================
[Code]
1: and rax, rcx
2: and rbx, rcx
3: or rax, rbx
0x1234567800000000
Q7. Code를 2까지 실행했을 때, rbx에 저장된 값은?
0x000000009ABCDEF0
Q8. Code를 3까지 실행했을 때, rax에 저장된 값은?
0x123456789ABCDEF0
Q9. 레지스터, 메모리 및 코드가 다음과 같다. Code를 1까지 실행했을 때, rax에 저장된 값은?
[Register]
rax = 0x35014541
rbx = 0xdeadbeef
==================================
[Code]
1: xor rax, rbx
2: xor rax, rbx
3: not eax
0xEBACFBAE
35014541
deadbeef
3d 5e (0a) (1d) 4b 5e (4e) (1f)
EB AC FB AE
'Security & Analysis > Analysis' 카테고리의 다른 글
[Dreamhack] Reverse Engineering#2 - Assembly & Architecture (0) | 2023.12.11 |
---|---|
[Dreamhack] Reverse Engineering#1 - Computer Architecture (0) | 2023.12.11 |
[ASCII Table] 아스키 코드표 (0) | 2023.01.12 |
[DHCP] 개념 - 원리 - 기능 - 취약점 - Relay Agent (0) | 2022.11.02 |
[APK] 안드로이드 앱 난독화 해제 및 소스코드 분석 (0) | 2022.09.15 |