Hacking/Pwnable

레지스터 (Register)

GunP4ng 2024. 3. 20. 23:25

x86-64 아키텍처: 레지스터 (Register)


1. 레지스터

1. 레지스터란?

레지스터는 CPU 가 요청을 처리하는데 필요한 데이터를 일시적으로 저장하는 기억장치이다. CPU 가 재빨리 읽고 쓰기를 해야하는 데이터들이므로 CPU 내부에 존재하는 메모리를 사용한다.

연산 제어, 디버깅 등의 목적으로 사용한다.

 

연산을 위한 데이터를 레지스터에 저장하고, 그 결과값도 레지스터에 저장한다.

레지스터 > 메모리 > 하드디스크 순으로 속도가 빠르다

 

32bit / 64bit 시스템에서 말하는 비트 수는 명령을 한 번에 처리할 수 있는 레지스터의 비트 수이다.

32bit 시스템이 인식 가능한 메모리가 4GB 인 이유는 32bit 로 한 번에 표현할 수 있는 주소가 4GB 이기 때문이다.

 

최초의 16비트 시스템에서는 0~15비트까지 레지스터 공간을 제공했었다.

레지스터는 CPU 당 한 개만 존재하는 것이 아니며, 필요와 용도에 따라 여러 종류가 있다.

각 레지스터의 사용 방식에 따라 구분해서 사용했다.

32비트로 환경이 변화했을 때도 그대로 유지되었으며 확장의 의미로 각 레지스터의 이름 앞에 E(Extension) 을 붙여서 사용하고 있다.

 

2. 레지스터의 데이터 단위

비트 (Bit)

데이터를 표현할 수 있는 가장 작은 단위이다. 0과 1로 구분된다.

 

바이트 (Byte)

8개의 비트가 모이면 바이트라고 한다. 0xFF (255) 까지 표현 가능하다.

8비트와 대응하는 레지스터는 AL, AH, BL, BH, CL, CH, DL, DH 등이 있다.

 

워드 (WORD)

2개의 바이트가 모이면 워드(WORD)라 한다. 0xFFFF (65535) 까지 표현 가능하다.

16비트와 대응하는 레지스터는 AX, BX, CX, DX, SI, DI, BP, SP, IP 가 있다.

 

더블 워드 (DWORD, Double WORD)

워드 2개가 모이면 더블 워드(DWORD)이다. 0xFFFFFFFFF (4294967295) 까지 표현 가능하다.

32비트와 대응하는 레지스터는 EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, EIP 가 있다.

 

킬로바이트 (KiloByte)

32비트의 제곱으로 값을 표현한다

레지스터의 크기

 

32비트 레지스터 EAX 에서

하위 16비트는 AX로 접근이 가능하고

AX의 상위 8비트를 AH, 하위 8비트를 AL 로 나타낸다.

이는 16비트 시스템 호환을 위한 설계이기도 하고, 레지스터 공간의 낭비를 없애기 위함이다.

 

 

2. 레지스터의 종류

1.  32bit 레지스터

32비트 레지스터

프로그램 실행 관련 레지스터를 먼저 알아보자.

주황색으로 표시된 것이 범용 레지스터, 녹색이 EIP 레지스터, 파란색이 16비트 세그먼트 레지스터이다.

 

시스템 관련 레지스터로는

파란색이 32비트 컨트롤 레지스터, 녹색이 각각 시스템에 관련된 레지스터들이다.

 

실수 연산 및 SIMD 관련 레지스터는 위의 그림처럼 구성되어 있다.

(SIMD: Single Instruction Multiple Data 하나의 명령어로 여러개의 데이터를 한번에 처리하는 기법)

 

2. 64bit 레지스터

64비트 레지스터

64비트 레지스터는 32비트 레지스터와 비슷하다.

64비트가 되면 레지스터의 크기와 개수가 늘어나고, 속도가 더 빨라지게 된다.

위의 그림을 보면 64비트가 되면서 E(Extension) 로 시작하던 레지스터들이 R(Register) 로 바뀌는 것을 볼 수 있다.

그리고 R8, R9 ... R15 레지스터 8개가 추가된다.

 

 

3. 범용 레지스터 (General Purpose Register)

1. 범용 레지스터

범용 레지스터는 가장 많이, 자주 쓰이고 중요한 레지스터이다.

상수나 주소를 저장할 때 쓰이기도 하고, 메모리 포인터를 저장할 때도 사용된다. 특수한 목적으로 사용되기도 한다

범용 레지스터

2. 산술 연산 레지스터

AX : 산술 논리 연산에 사용된다. 함수의 리턴값이 저장된다.

BX : 배열의 인덱스 값을 저장한다.

CX : 반복문의 횟수 지정 시에 사용된다. (counter) 문자열 처리에도 사용된다.

DX : AX 의 보조적인 역할이다. AX와 합쳐져서 확장된 메모리로 사용한다. I/O 주소를 지정할 때도 사용한다.

 

3. 인덱스 레지스터

SI (Source Index) : 복사나 비교를 할 때 사용되는 소스 문자가 저장된다.

DI (Destination Index) : 복사나 비교를 할 때 사용되는 목적지 문자. stos, movs 를 사용할 때마다 1씩 증가한다.

 

4. 포인터 레지스터

SP (Stack Pointer) : 스택의 가장 윗부분을 가리킨다. 스택에 값이 쌓이면 ESP 값도 증가한다.

BP (Base Pointer) : 스택의 제일 바닥부분의 주소를 가리킨다. EBP 밑에는 Return 값이 있다.

 

5. R8, R9 ... R15 레지스터

64비트 R8,R9 ... R15 레지스터

R8, R9, ... R15 레지스터는 특별히 정해진 용도 없이 다양하게 사용된다.

 

 

4. 세그먼트 레지스터 (Segment Register)

1. 세그먼트 레지스터

세그먼트 레지스터는 현재 메모리 주소를 표현하기 위한 세그먼트 디스크립터 테이블(GDT, Global, Descriptor Table)의 위치를 나타내며, 각 영역의 기본 위치를 가리킨다.

세그먼트 레지스터

세그먼트 레지스터는 총 6개로 이루어져 있다.

CS, DS, SS, ES, FS, GS

 

세그먼트 레지스터 접두사를 이용해 명시적으로 특정 세그먼트를 설정할 수 있다.

데이터 영역을 접근하면서 DS 레지스터 이외의 세그먼트 레지스터를 사용할 수 있다는 얘기다.

스택 영역도 마찬가지다. 하지만 CS 레지스터는 사용할 수 없다.

 

세그먼트 레지스터의 구성 요소는 다음과 같다.

  • Index : SDT(Segment Descriptor Table) 에 대한 인덱스. 13비트이다.
  • TI : Table Indicator 의 약자로 디스크립터 테이블이 global(= 0)인지 Local(= 1)인지 설정
  • PRL : 요구 특권 레벨 값. (00: 커널, 11: 유저)

특권 레벨은 해당 메모리로 접근할 수 있는 권한을 말한다.

자세한건 나중에 따로 다루도록 하고 세그먼트 레지스터에 대해 알아보자.

 

2. CS (Code Segment)

코드 영역을 가리키는 레지스터이다.

데이터 이동 명령으로 값을 변경할 수 없다.

(jmp 명령 또는 인터럽트 관련 명령으로 변경 가능하다)

 

3. SS (Stack Segment)

스택 영역을 가리키는 레지스터이다.

CS 와 다르게 데이터 이동 명령으로 값을 변경할 수 있다.

SP, BP 등의 레지스터를 통해 스택에 접근할 때 암시적으로 사용된다.

 

4. DS (Data Segment)

데이터 영역을 가리키는 레지스터이다.

데이터 이동 명령으로 값을 변경할 수 있다.

 

5. ES (Extra Segment)

데이터 관련 확장 레지스터이다.

문자열과 관련된 작업을 처리할 때 암시적으로 사용된다.

 

6. FS, GS

데이터 관련 확장 레지스터이다.

ES 와 함께 확장 레지스터로 사용되므로 알파벳 순서로 E 다음 F, G

그래서 이름이 FS, GS 이다.

 

 

5. E-flag 레지스터 (E-flag Register)

1. E-flag 레지스터

E-flag 레지스터는 말 그대로 16비트인 flag 레지스터가 확장(Extend)되었다는 말이다.

시스템 제어용 플래그로 사용되거나 어셈블리의 조건 처리, 상태 저장 용도로 중요한 역할을 한다.

E-flag 레지스터

1, 3, 5, 15, 22~31 번 비트는 예약되어 있어 소프트웨어에 의해 조작할 수 없다.

각 플래그별 기능을 알아보자.

 

2. 연산결과를 나타내는 플래그

CF (Carry Flag) : 덧셈 뺄셈에서 빌림수(Borrow) 발생시 1로 설정

PF (Parity Flag) : 연산 결과가 짝수이면 1, 홀수면 0으로 설정

AF (Auxiliary Flag) : 16(8)비트 연산 시 빌림수 발생시 1로 설정

ZF (Zero Flag) : 연산 결과가 0이면 1로 설정

SF (Sign Flag) : 연산 결과 최상위 비트가 1인 경우 1로 설정

OF (Overflow Flag) : 연산 결과가 용량을 초과하였을 경우 1로 설정

 

3. 시스템 제어 플래그

TF (Trap Flag) : 프로그램 추적 시 1로 설정, 명령을 한 행씩 실행한다.

IF (Interupt enable Flag) : 외부 인터럽트 요구를 받아들일 때 1로 설정

AC (Alignment Check) : CR0 레지스터의 AM 비트와 함께 1로 설정하면 메모리 참조 시 정렬 체크를 활성화 한다.

IOPL (I/O Privilege Level) : 현재 특권 수준이 IOPL 보다 높은 경우에 I/O 주소에 접근한다, 11이 가장 낮다.

NT (Nested Task) : 연결 작업을 제어한다. 1로 설정 시 현재 작업이 기존 실행 작업과 연결됨을 의미한다.

RF (Resume Flag) : 디버깅 시 프로세서에 일시 중지 예외 발생을 제어한다.

VM (Virtual-8086 Mode) : Virtual-8086-mode 활성화 시 1로 설정

VIF (Virtual Interrupt Flag) : 가상 이미지의 인터럽트 요구를 받아들일 때 1로 설정된다. VIP와 같이 사용된다.

VIP (Virtual Interrupt Pending) : 가상 모드 인터럽트가 지연 시 1로 설정

ID (ID Flag) : CPUID 명령어 지원 여부로 1로 설정 시 지원한다.

 

4. 문자열 제어

DF (Direction Flag) : 문자열 복사 명령과 관련된 제어 플래그. 1로 설정되어 있으면 문자열 복사 시 주소값이 감소한다.

 

 

6. IP (Instruction Pointer) 레지스터

1. IP 레지스터

CPU가 처리해야 하는 명령어의 주소를 나타내는 레지스터이다.

CPU에서는 EIP 에 저장된 주소의 명령어를 처리하고 크기만큼 다음으로 이동하여 도 명령어를 실행시킨다.

이러한 싸이클을 변경하고 싶다면 분기문을 사용하면 된다. (JMP, CALL, RET 등)

 

32bit 에서는 EIP, 64bit 에서는 RIP 로 사용된다.

 

 

Reference

https://m.blog.naver.com/mjnms/220460825993

https://plummmm.tistory.com/113

와우해커 BOF 달고나 문서