[Reversing] IA-32 Register

 

리버스 엔지니어링


(1) IA-32(Intel Architecture 32bit) Register

1-1. CPU 레지스터란?

  • CPU 내부에 존재하는 다목적 저장 공간

  • 일반적으로 메모리라고 얘기하는 RAM(Random Access Memory)와는 성격이 다름

  • CPU가 RAM에 있는 데이터를 액세스(Access)하기 위해서는 물리적으로 먼 길을 돌아가야 하기 때문에 오랜 시간이 걸림

  • 하지만 레지스터는 CPU와 한 몸이기 때문에 고속으로 데이터 처리 가능

어셈블리 명령어의 대부분은 레지스터를 조작하고 그 내용을 검사하는 것들이므로, 레지스터를 확실히 이해해야 명령어 자체도 이해가 가능하다.


1-2. IA-32 레지스터 종류

 

IA-32는 지원하는 기능도 무척 많고, 그만큼 레지스터의 수도 많다.

 

IA-32에 존재하는 레지스터들의 종류는 다음과 같다.

 

  • Basic program execution registers

    • x87 FPU registers

    • MMX registers

    • XMM registers

    • Control registers

    • Memory management registers

    • Debug registers

    • Memory type range registers

    • Machine specific registers

    • Machine check register

애플리케이션 디버깅의 초급 단계에서는 Basic program execution register에 대해서 알아두어야 한다.

 

디버깅할 때 가장 많이 보게 될 레지스터이며, 중/고급 단계에서는 추가적으로 Control registers, Memory management registers, Debug registers 등에 대해서도 알아두어야 한다.

 

 

1-2-1. Basic program execution registers

 

Basic program execution registers는 다시 4개의 그룹으로 나눌 수 있다.

 

  • General Purpose Registers (32비트 - 8개)

  • Segment Registers (16비트 - 6개)

  • Program Status and Control Register (32비트 - 1개)

  • Instruction Pointer (32비트 - 1개)

 

[그림 1] Basic program execution registers

 

# 참고

  • 레지스터 이름에 E(Extend)가 붙은 경우는 예전 16비트 CPU인 IA-16 시절부터 존재하던 16비트 크기의 레지스터들을 32비트 크기로 확장시켰다는 뜻

 

각 그룹에 대하여 살펴보도록 하자.

 

1) 범용 레지스터 (General Purpose Registers)

  • 이름처럼 범용적으로 사용되는 레지스터들

  • IA-32에서 각각의 범용 레지스터들의 크기는 32비트(4바이트)

  • 보통은 상수 / 주소 등을 저장할 때 주로 사용되며, 특정 어셈블리 명령어에서는 특정 레지스터를 조작하기도 함

  • 어떤 레지스터들은 특수 용도로 사용되기도 함

 

[그림 2] 범용 레지스터

 

각 레지스터들은 16비트 하위 호환을 위하여 몇 개의 구획으로 나뉘어진다. (EAX 기준)

 

  • EAX : (0 ~ 31) 32비트

  • AX : (0 ~ 15) EAX의 하위 16비트

  • AH : (8 ~ 15) AX의 상위 8비트

  • AL : (0 ~ 7) AX의 하위 8비트

즉 4바이트(32비트)를 다 사용하고 싶을 때는 EAX를 사용하고, 2바이트(16비트)만 사용할 때는 EAX의 하위 16비트 부분인 AX를 사용하면 된다.

 

AX는 다시 상위 1바이트(8비트)인 AH와 하위 1바이트(8비트)인 AL로 나뉘어진다.

 

이런 식으로 하나의 32비트 레지스터를 상황에 맞게 8비트, 16비트, 32비트로 알뜰하게 사용 가능하다.

 

 

각 레지스터의 이름은 아래와 같다.

 

  • EAX : Accumulator for operands and results data

  • EBX : Pointer to data in the DS segment

  • ECX : Counter for string and loop operations

  • EDX : I/O pointer

위 4개의 레지스터들은 주로 산술 연산(ADD, SUB, XOR, OR 등) 명령어에서 상수/변수 값의 저장 용도로 많이 사용된다.

 

어떤 어셈블리 명령어(MUL, DIV, LODS 등)들은 특정 레지스터를 직접 조작하기도 한다.

(명렁어 실행 뒤에 특정 레지스터들의 값이 변경) 

 

그리고 추가적으로 ECX와 EAX는 특수 용도로 사용되며, ECX는 반복문 명령어(LOOP)에서 반복 카운트(loop count)로 사용된다. (루프를 돌 때마다 ECX를 1씩 감소시킴)

 

EAX는 일반적으로 함수 리턴 값에 사용되며, 모든 Win32 API 함수들은 리턴 값을 EAX에 저장한 후 리턴한다.

 

 

# 참고

  • Win32 API 함수들은 내부에서 ECX와 EDX를 사용

  • 따라서 이런 API가 호출되면 ECX와 EDX의 값은 변경됨

  • 따라서 ECX와 EDX에 중요한 값이 저장되어 있다면 API 호출 전에 다른 레지스터나 스택에 백업 필요

 

나머지 범용 레지스터들의 이름은 아래와 같다.

 

  • EBP : Pointer to data on the stack (in the SS segment)

  • ESI : source pointer for string operations

  • EDI : destination pointer for string operations

  • ESP : Stack pointer (in the SS segment) 

위 4개의 레지스터들은 주로 메모리 주소를 저장하는 포인터로 사용된다.

 

ESP는 스택 메모리 주소를 가리키며, 어떤 명령어들(PUSH, POP, CALL, RET)은 ESP를 직접 조작하기도 한다.

(스택 메모리 관리는 프로그램에서 매우 중요하기 때문에 ESP를 다른 용도로 사용하지 말아야 한다.)

 

EBP는 함수가 호출되었을 때 그 순간의 ESP를 저장하고 있다가, 함수가 리턴하기 직전에 다시 ESP에 값을 되돌려줘서 스택이 깨지지 않도록 하며, 이것을 Stack Frame 기법이라 한다.

 

ESI와 EDI는 특정 명령어들(LODS, STOS, REP MOVS 등)과 함께 주로 메모리 복사에 사용된다.

 

 

2) 세그먼트 레지스터

  • 세그먼트(Segment)란 IA-32의 메모리 관리 모델에서 나오는 용어

  • IA-32 보호 모드에서 세그먼트란 메모리를 조각내어 각 조각마다 시작 주소, 범위, 접근 권한 등을 부여해서 메모리를 보호하는 기법을 말함

  • 세그먼트는 페이징(Paging) 기법과 함께 가상 메모리를 실제 물리 메모리로 변경할 때 사용

  • 세그먼트 메모리는 Segnet Descriptor Table(SDT)이라고 하는 곳에 기술되어 있는데, 세그먼트 레지스터는 바로 SDT의 index를 가짐

 

[그림 3] 세그먼트 메모리 모델

 

[그림 3]은 보호 모드에서의 세그먼트 메모리 모델을 나타낸다.

 

세그먼트 레지스터는 총 6개(CS, SS, DS, ES, FS, GS)이며 각각의 크기는 16비트(2바이트)이다.

 

[그림 3]은 각 세그먼트 레지스터가 가리키는 세그먼트 디스크립터(Segment Descriptor)와 가상 메모리가 조합되어 선형 주소(Linear Address)가 되며, 페이징 기법에 의해 선형 주소가 최종적으로 물리 주소(Physical Address)로 변환 된다.

 

만약 OS에서 페이징을 사용하지 않는다면 선형 주소는 그대로 물리 주소가 된다.

 

 

각 세그먼트 레지스터 이름은 다음과 같다.

  • CS : Code Segment

  • SS : Stack Segment

  • DS : Data Segment

  • ES : Extra(Data) Segment

  • FS : Data Segment

  • GS : Data Segment

이름 그대로 CS는 프로그램의 코드 세그먼트를 나타내며, SS는 스택 세그먼트, DS는 데이터 세그먼트를 나타낸다.

 

EF, FS, GS 세그먼트는 추가적인 데이터 세그먼트이다.

 

FS 레지스터는 애플리케이션 디버깅에도 자주 등장하는데 SEH(Structured Ex-ception Handling), TEB(Thread Environment Block), PEB(Process Environment Block) 등의 주소를 계산할 때 사용된다.

 

 

 

3) 프로그램 상태와 컨트롤 레지스터

  • EFLAGS : Flag Register

  • 플래그(Flag) 레지스터 이름은 EFLAGS이며, 32비트(4바이트) 크기

  • EFLAGS 레지스터 역시 16비트의 FLAGS 레지스터의 32비트 확장 형태

[그림 4] EFLAGS Register

 

EFLAGS 레지스터는 [그림 4]와 같이 각각의 비트마다 의미를 가지고 있으며, 각 비트는 1 또는 0의 값을 가진다.

 

이는 On/Off 혹은 True/False를 의미한다.

 

일부 비트는 시스템에서 직접 세팅하고, 일부 비트는 프로그램에서 사용된 명령의 수행 결과에 따라 세팅된다.

 

 

# 참고

  • Flag는 단어 그대로 깃발이 올라가면 1(On/True), 내려가면 0(Off/False)

  • flag(ZF, OF, CF)가 중요

  • 이유는 조건 분기 명령어(Jcc)에서 이들 Flag의 값을 확인하고 그에 따라 동작 수행 여부를 결정하기 때문

 

3개의 플래그 내용은 다음과 같다.

 

  • Zero Flag(ZF) : 연산 명령 후에 결과 값이 0이 되면 ZF가 1(True)로 세팅

  • Overflow Flag(OF) : 부호 있는 수(signed integer)의 오버플로가 발생했을 때 1로 세팅되며, MSB(Most Significant Bit)가 변경되었을 때 1로 세팅

  • Carry Flag(CF) : 부호 없는 수(unsigned integer)의 오버플로가 발생했을 때 1로 세팅

 

 

4) Instruction Pointer

  • EIP : Instruction Pointer

  • CPU가 처리할 명령어의 주소를 나타내는 레지스터

  • 크기는 32비트(4바이트)이며, 16비트의 IP 레지스터의 확장 형태

  • CPU는 EIP에 저장된 메모리 주소의 명령어(instruction)를 하나 처리하고 난 후 자동으로 그 명령어 길이만큼 EIP를 증가시킴

  • 이런 형식으로 계속 명령어를 처리해 나감

범용 레지스터들과 다르게 EIP는 그 값을 직접 변경할 수 없도록 되어 있어서 다른 명령어를 통하여 간접적으로 변경해야 한다.

 

EIP를 변경하고 싶을 때는 특정 명령어(JMP, Jcc, CALL, RET)를 사용하거나 인터럽트(Interrupt), 예외(Exception)를 발생시켜야 한다.


# Reference

 

http://www.yes24.com/Product/Goods/7529742

'Reversing' 카테고리의 다른 글

[Reversing] Process Explorer  (0) 2020.03.26
[Reversing] 스택  (0) 2020.03.25
[Reversing] 리틀 엔디언 표기법  (0) 2020.03.24
[Reversing] OllyDbg 사용법  (0) 2020.03.24
[Reversing] 리버스 엔지니어링이란?  (0) 2020.01.04

+ Recent posts