728x90
반응형

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

 

728x90
728x90

+ Recent posts