본문 바로가기

Layer7

코드 분석하기

 

< 스택 프레임 생성 >

복귀할 포인터 위치를 저장하기 위해 rbp를 스택에 추가함

 

실행이 끝난 후, 현재 스택 주소로 복귀하기 위해 rsp값을 rbp에 넣음.

rsp, rbp 주소 : 0x7fffffffdff0


 

Stack

rsp에서 0x10만큼을 뺌 → 0x10만큼의 지역변수 공간을 확보함

 

rax에 fs:[0x28] 값을 8byte 크기만큼 복사

stack canary는 fs:[0x28]에서 가져오며, 이를 스택에 저장하고 함수가 끝나기 전에 다시 fs:[0x28]와 비교

더보기

Stack canary : buffer overflow를 감시하기 위해 buffer와 return address 사이에 존재

 

return address로 넘어가기 전 canary값이 원래 값과 같은지 확인

  • 값이 같지 않을 경우, 프로그램 강제 종료

buffer overflow는 canary의 값을 덮어씀

→ 컴퓨터는 return address로 넘어가기 전 buffer overflow 그리고 강제종료에 대해 경고

 

https://www.youtube.com/watch?v=N7kGd76evsM

 

← RBP 주소

Stack

[rbp - 8]의 주소에 8byte 크기로 rax 값을 넣음

[rbp - 8]의 주소(=0xc310b2cbe7a4d100)에는 8byte 크기의 stack canary 값이 들어있음

 

 

eax 레지스터를 0으로 초기화

 

[rip + 0xde6]의 주소를 rdi에 복사

[rip + 0xde6] → 다음 실행할 명령어 주소 + 0xde6

 

eax 레지지스터를 0으로 초기화


printf 함수 호출

PLT(Procedure Linkage Table) : 외부 프로시저를 연결해 주는 테이블. PLT를 통해 다른 라이브러리에 있는 프로시저를 호출해 사용할 수 있음.

더보기

프로시저(procedure) : C언어에서 함수와 비슷한 개념. 하지만 함수와 달리 리턴 값을 남기지 않음.

 

[rbp - 0x10]의 주소를 rax에 복사. rax, rsp 스택 위치가 같음

 

rax의 값을 rsi에 복사. rax, rsi, rsp 스택 위치가 같음

scanf의 두 번째 인자 : rsi (입력받은 값이 들어감)

 

[rip + 0xddb]의 주소를 rdi에 복사 (scanf로 입력 받은 값이 들어감)

scanf의 첫 번째 인자 : %d

 

eax 레지스터를 0으로 초기화


scanf 함수 호출 → scanf로 입력 받은 값은 rdi에 저장

 

[rbp - 0x10]의 주소 값을 8byte 크기로 eax에 복사 

 

eax의 값을 edi에 복사

 

test 함수 호출

 

[rbp - 0xc] 주소에 4byte 크기로 eax 값 복사 (eax는 test 함수의 return 값을 담고 있음)

 


<조건 분기문>

[rbp - 0xc] 주소에 있는 4byte 크기의 값 - 1 의

  • 결과가 0이면([rbp - 0xc == 1]) ZF가 1
  • 결과가 0이 아니라면([rbp - 0xc != 1]) ZF가 0

 

ZF가 0([rbp - 0xc != 1])이면 main+120으로 점프함

 

[rbp - 0xc]에 있는 4byte 크기의 값 - 0 의

  • 결과가 0이면([rbp] - 0xc == 0) ZF가 1
  • 결과가 0이 아니라면([rbp - 0xc] != 0) ZF가 0

ZF가 0([rbp - 0xc] != 0])이면 main+136으로 점프함

 


eax에 0을 넣음 (=return 0)

 

<main+21>에서 [rbp - 8]에 8byte 크기로 복사한 canary 값을 rdx에 복사

 

rdx값과 원래의 값(qword ptr fs:[0x28])이 다르다면 buffer overflow를 당했다 판단하고 강제 종료

 

rdx값과 원래의 값(qword ptr fs:[0x28])이 같다면 <main + 161>로 점프

 

<스택 프레임 해체>

<main+161> leave

  • mov esp, ebp
  • pop ebp

→ ebp의 값을 esp에 복사함. 현재 ebp가 가리키는 값을 esp값으로 설정해 현재 ebp는 이전 함수의 ebp로 복구

 

<main+162> ret

  • pop eip
  • jmp eip

→ 현재 esp가 가리키는 값(return address)를 eip로 설정, eip로 점프

 


위 코드를 C언어 코드로 보면 다음과 같다

'Layer7' 카테고리의 다른 글

ELF file  (0) 2021.06.02
코드 분석 하기  (0) 2021.05.30
Assembly X86 Stack 관리  (1) 2021.05.24
Assembly X64  (0) 2021.05.22
실행파일 생성 과정  (0) 2021.05.15