본문 바로가기
프로그래밍/해킹

x86-64 아키텍처 정리

by 만디기 2024. 7. 5.

- AMD는 인텔의 32비트 CPU 아키텍처인 IA-32를 64비트로 확장한 AMD64 아키텍처를 발표하였다.

- AMD64가 시장에서 널리 인정받자, 인텔을 비롯한 다양한 회사에서 이를 기반으로 다양한 이름의 아키텍처를 발표하기 시작했는데, 이 과정에서 보다 범용적이고 중립적으로 지칭되는 x86-64라는 명칭이 탄생하게 되었고, 현재 대다수 개인용 컴퓨터는 이 x86-64 아키텍처 기반의 CPU를 탑재하고 있다.

- CPU가 한 번에 처리할 수 있는 데이터의 크기(이해할 수 있는 데이터의 단위)를 WORD라고 부른다. 예를 들어, 일반적인 32비트 아키텍처에서 ALU는 32비트까지 계산할 수 있으며, 레지스터의 용량 및 각종 버스들의 대역폭이 32비트이다. 따라서 이들로 구성된 CPU는 설계 상 32비트의 데이터까지만 처리할 수 있게 된다.

- WORD가 크면 가용할 수 있는 메모리 자원이 그만큼 많아진다.

 

1. 범용 레지스터

 

- 주 용도는 있으나, 그 외의 다양한 용도로 사용될 수 있는 레지스터이다.

- x86-64에서 각각의 범용 레지스터는 8바이트를 저장할 수 있으며, 부호 없는 정수를 기준으로 까지의 수를 나타낼 수 있다.

- 이 외에도 x64에는 r8, r9, … , r15까지의 범용 레지스터가 더 존재한다.

이름 주 용도
rax (accumulator register) 함수의 반환 값
rbx (base register) x64에서는 주된 용도 없음
rcx (counter register) 반복문의 반복 횟수, 각종 연산의 시행 횟수
rdx (data register) x64에서는 주된 용도 없음
rsi (source index) 데이터를 옮길 때 원본을 가리키는 포인터
rdi (destination index) 데이터를 옮길 때 목적지를 가리키는 포인터
rsp (stack pointer) 사용중인 스택의 위치를 가리키는 포인터
rbp (stack base pointer) 스택의 바닥을 가리키는 포인터

 

2. 세그먼트 레지스터

- x64 아키텍처에는 cs, ss, ds, es, fs, gs 총 6가지 세그먼트 레지스터가 존재하며, 각 레지스터의 크기는 16비트이다.

- 세그먼트 레지스터는 x64로 아키텍처가 확장되면서 용도에 큰 변화가 생긴 레지스터이다.

- 과거 IA-32, IA-16에서는 세그먼트 레지스터를 이용하여 사용 가능한 물리 메모리의 크기를 키우려고 했다. 예를 들어 IA-16에서는, 어떤 주소를 cs:offset라고 한다면, 실제로는 cs<<4 + offset의 주소를 사용하여 16비트 범위에서 접근할 수 없는 주소에 접근할 수 있었다. 당시에는 범용 레지스터의 크기가 작아서 사용 가능한 메모리의 주소 폭이 좁았지만, x64에서는 사용 가능한 주소 영역이 굉장히 넓기 때문에 이런 용도로는 거의 사용되지 않는다.

- 현대의 x64에서 cs, ds, ss 레지스터는 코드 영역과 데이터, 스택 메모리 영역을 가리킬 때 사용되고, 나머지 레지스터는 운영체제 별로 용도를 결정할 수 있도록 범용적인 용도로 제작된 세그먼트 레지스터이다.

 

3. 명령어 포인터 레지스터

- 프로그램은 일련의 기계어 코드들로 이루어져 있다. 이 중에서 CPU가 어느 부분의 코드를 실행할지 가리키는게 명령어 포인터 레지스터의 역할이다.

- x64 아키텍처의 명령어 레지스터는 rip이며, 크기는 8바이트이다.

 

4. 플래그 레지스터

- 플래그 레지스터는 프로세서의 현재 상태를 저장하고 있는 레지스터이다.

- x64 아키텍처에서는 RFLAGS라고 불리는 64비트 크기의 플래그 레지스터가 존재하며, 과거 16비트 플래그 레지스터가 확장된 것이다.

- 플래그 레지스터는 자신을 구성하는 여러 비트들로 CPU의 현재 상태를 표현합니다.

- RFLAGS는 64비트이므로 최대 64개의 플래그를 사용할 수 있지만, 실제로는 아래 그림의 20여개의 비트만 사용한다.

- 플래그를 사용하는 간단한 예로, 3의 값을 갖는 a와 5의 값을 갖는 b가 있을 때, a에서 b를 빼는 연산을 하면, 연산의 결과가 음수이므로 SF가 설정된다. 그러면 CPU는 SF를 통해 a가 b보다 작았음을 알 수 있다.

플래그 의미
CF(Carry Flag) 부호 없는 수의 연산 결과가 비트의 범위를 넘을 경우 설정 됩니다.
ZF(Zero Flag) 연산의 결과가 0일 경우 설정 됩니다.
SF(Sign Flag) 연산의 결과가 음수일 경우 설정 됩니다.
OF(Overflow Flag) 부호 있는 수의 연산 결과가 비트 범위를 넘을 경우 설정 됩니다.

 

5. 레지스터 호환

- IA-32에서 CPU의 레지스터들은 32비트 크기를 가지며, 이들의 명칭은 각각 eax, ebx, ecx, edx, esi, edi, esp, ebp였다. 호환성을 위해 이 레지스터들은 x86-64에서도 그대로 사용이 가능하다.

- rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp가 이들의 확장된 형태이며, eax, ebx 등은 확장된 레지스터의 하위 32비트를 가리킨다. 예를 들어, eax는 rax의 하위 32비트를 의미한다.

- 마찬가지로 과거 16비트 아키텍처인 IA-16과의 호환을 위해 ax, bx, cx, dx, si, di, sp, bp는 eax, ebx , ecx , edx, esi, edi, esp, ebp의 하위 16비트를 가리킨다.

- 정리 : rax : 64비트 / eax : rax의 하위 32비트 / ax : eax의 하위 16비트 / ah : ax의 상위 8비트 / al : ax의 하위 8비트 

'프로그래밍 > 해킹' 카테고리의 다른 글

Wireshark 관련 지식  (0) 2024.07.08
x86 어셈블리  (0) 2024.07.06
Command Injection for Windows  (1) 2024.07.05
Shell Code 앞에 붙는 접두사에 대한 고찰.  (0) 2024.07.04
ExploitTech: Command Injection for Linux  (0) 2024.07.04