stxxp

[Pwnable] x86-64 아키텍처 - 레지스터 본문

Security/Pwnable

[Pwnable] x86-64 아키텍처 - 레지스터

stxxp 2024. 3. 15. 21:49

진짜 정말 아주 오랜만에 글을 쓴다. 이 블로그를 다시 찾은 것 자체가 참 오랜만인 것 같다.

해킹 공부에 소홀했던 지난날을 반성하며 앞으로 자주 글을 써보려 한다.

◎ 목차
# x86-64
# 레지스터
   1. 범용 레지스터
   2. 세그먼트 레지스터
   3. 명령어 포인터 레지스터
   4. 플래그 레지스터
   5. 32bit 이하 아키텍처 레지스터와의 호환성

 

 

# x86-64

x86-64은 인텔의 IA-32를 64bit로 확장한 AMD64 아키텍처가 인정받기 시작한 후, 인텔을 비롯한 여러 회사들이 이를 기반으로 한 여러 아키텍처를 만들어내는 과정에서 탄생한 아키텍처이다. 좀 더 정확히는 AMD64 기반 아키텍처를 범용적으로 지칭하는 명칭이 탄생한 것이라 할 수 있다. 다시 말해 AMD64 = x86-64라고 봐도 무방하다. 또한 x86-64를 줄여서 x64라고도 부른다.

 

32bit 아키텍처 혹은 64bit 아키텍처처럼 이름 앞에 붙은 Nbit는 CPU가 한번에 처리할 수 있는 데이터의 크기를 말한다. 이 데이터의 양을 CPU가 이해할 수 있는 데이터의 단위라는 의미에서 WORD라고 부른다. 예를 들어 32bit에서는 1WORD는 4byte이다(1WORD=4byte=32bit). 

 

당연하게도 WORD가 크다는 것은 CPU가 아주 많은 양의 데이터를 한번에 처리한다는 것이므로 WORD가 클수록 메모리 자원을 많이 잡아먹는 고사양의 게임 등을 실행하기 용이할 것이다. 기본적으로 64bit 정도가 되면 해당 아키텍처에서 이론상으로 16EB(16엑사사이트는 대충 16*10^7테라바이트로 엄청난 크기임)의 가상메모리를 제공받을 수 있다. 이는 메모리 자원 부족으로 고사양의 프로그램을 실행할 수 없는 상황은 거의 발생하지 않음을 의미한다.

 

 

 

# 레지스터 Register

CPU가 데이터를 빠르게 저장하고 사용할 때 이용하는 임시보관소를 레지스터라고 부른다. 레지스터는 사용하는 용도에 따라 다음과 같이 분류할 수 있다.

 

1. 범용 레지스터 General Register

범용 레지스터는 주용도가 지정되어 있지만, 그 외의 용도로도 사용 가능한 레지스터이다. x86-64에서 모든 범용 레지스터는 8byte(=64bit)를 저장할 수 있고, 부호 없는 정수 기준 2^64 - 1까지의 수를 표현할 수 있다.

이름 주용도
RAX (accumulator register) 함수의 반환값
RBX (base register) x64에서 주용도 없음
RCX (counter register) 반복문의 반복 횟수 or 각종 연산의 시행 횟수
RDX (date register) x64에서 주용도 없음
RSI (source index) 데이터 이동시 원본을 가리키는 포인터
RDI (destination index) 데이터 이동시 목적지를 가리키는 포인터
RSP (stack pointer) 사용중인 스택의 위치를 가리키는 포인터
RBP (stack base pointer) 스택의 바닥을 가리키는 포인터
r8~r15 범용적으로 사용

 

2. 세그먼트 레지스터 Segment Register

과거 IA-32 등에서는 세그먼트 레지스터를 사용해 물리 메모리의 크기를 키우는 용도로 사용했다고 한다. 그러나 64bit로 확장되며 사용 가능한 주소 영역이 대폭 넓어졌기 때문에 현재는 이런 용도로는 거의 사용하지 않는다. x86-64에서 모든 세그먼트 레지스터는 각각 16bit를 저장할 수 있다.

이름 주용도
CS (code segment) 코드 영역 및 데이터
DS (data segment)
SS (stack memory segment)
ES (extra segment) 범용적으로 사용
>> 운영체제 별로 용도를 결정할 수 있도록 함
FS (general purpose segment)
GS (general purpose segment)

 

3. 명령어 포인터 레지스터 Instruction Pointer Register

프로그램은 0과 1만으로 이루어진 기계어 코드로 구성되어 있다. 이러한 프로그램에서 CPU는 어느 부분의 코드를 실행할 것인지 알 필요가 있다. 이 때, 명령어 포인터 레지스터의 역할은 다음에 실행할 명령어의 위치를 가리키는 것이며 크기는 8byte이다.

이름 주용도
RIP (instruction pointer register) 다음 명령어의 주소

 

4. 플래그 레지스터 Flag Register

플래그 레지스터는 CPU의 현재 상태를 저장하고 있는 레지스터이다. 현재 상태가 무엇을 의미하는지는 아래에서 설명하겠다. x64에서는 RFLAGS라 불리는 64bit 크기의 플래그 레지스터가 존재하는데 실제로는 다음과 같은 약 20bit 정도만 사용한다.

플래그 레지스터

 

아래는 이중에서도 많이 쓰이는 플래그들이다.

이름 의미
CF (carry flag) 부호 없는 수의 연산 결과가 비트의 범위를 넘을 경우 설정됨.
ZF (zero flag) 연산 결과가 0인 경우 설정됨.
SF (sign flag) 연산 결과가 음수인 경우 설정됨.
OF (overflow flag) 부호 있는 수의 연산 결과가 비트 범위를 넘을 경우 설정됨.

사용 예를 들자면, a=4 이고 b=4일 때 a-b의 연산 결과는 0이므로 ZF가 설정된다(기본값 0에서 1로 변경됨). 이렇게 된 경우, CPU는 ZF가 1로 설정된 것을 통해 a와 b가 같은 값이었음을 알 수 있다. 

 

4. 32bit 이하 아키텍처 레지스터와의 호환성

x86-64는 IA-32의 확장 아키텍처로, 호환이 가능하다. IA-32의 레지스터에는

| eax | ebx | ecx | edx | esi | esp | ebp |

가 있다. 지금까지 표로 정리했던 rax 등의 레지스터는 위의 32bit 아키텍처의 레지스터를 확장한 형태이기에 eax는 rax의 하위 32bit를 의미하는 것이다.

 

*위 글은 Dreamhack의 System Hacking 로드맵을 수강하며 공부용으로 정리한 글입니다.

 

 


https://dreamhack.io/lecture/roadmaps/2

'Security > Pwnable' 카테고리의 다른 글

[Pwnable] Dreamhack: ssp_001 write-up  (0) 2024.04.07
[Pwnable] BOF 예제 풀기  (0) 2024.03.19
[WolvCTF] Pwn: babypwn write-up  (2) 2024.03.19
[HackCTF] SysROP writeup  (0) 2020.11.27
HackCTF | bof_basic & bof_basic2  (0) 2020.11.06