본문 바로가기
정상을향해/Program Analysis

IA-32 Register

by 사이테일 2013. 11. 10.

출처 : www.reversecore.com


 

Register?

Register CPU 내부에 존재하는 저장공간이다.

 

CPU RAM에 있는 데이터를 액세스 하기 위해서는 먼 길을 돌아가야 한다.

하지만 레지스터는 CPU와 한 몸이기 때문에 고속으로 데이터를 처리할 수 있다.

 

, 가격이 비싸고 용량이 작으며, CPU 아키텍쳐와 밀접한 연관이 있어서 그 개수와 크기를 변경할 수 없다.

(변경하려면 CPU 아키텍쳐 자체가 변경되어야 한다.)

 

IA-32 Registers

IA-32는 최신 CPU인 만큼 지원하는 기능도 많다.

따라서 그만큼 레지스터도 많이 가지고 있다.

 

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 registers에 대해서만 알아보도록 하겠다.

(애플리케이션 디버깅의 초급 단계에서는 이것만 알면 된다.)

 

 

Basic program execution registers

 

 

Basic program execution registers 들은 크게 4가지 group으로 나눌 수 있다.

 

 - General Purpose Registers (32bit - 8)

 - Segment Registers (16bit - 6)

 - Program Status and Control Register (32bit - 1)

 - Instruction Pointer (32bit - 1)

 

레지스터 이름에 E(Extended)가 붙은 것들은 예전 16bit CPU부터 존재하던 레지스터들이었는데,

    32bit CPU에서 이름 앞에 E를 붙여서 32bit로 확장되었다는 것을 나타낸다.

 

같은 이유로 64bit CPU에서는 E대신 R을 붙여서 64bit로 확장되었음을 나타낸다.

 

#1. General Purpose Registers

이름 그대로 범용적으로 사용되는 레지스터들이다.

IA-32에서 범용 레지스터의 크기는 각 32bits(4bytes)이다.

 

보통은 변수를 저장할 때 주로 사용되며, 특정 Assembly 명령어에서는 특정 레지스터를 조작하기도 한다.

또한 어떤 레지스터들은 특수한 용도로 사용되기도 한다.

 

아래 그림에 범용 레지스터들이 표시되어 있다.

 

 

 - EAX : 32bit

 - AX : EAX의 하위 16bit

 - AH : AX의 상위 8bit

 - AL : AX의 하위 8bit

 

각 레지스터의 이름은 다음과 같다.

 

 - 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, etc) 명령어에서 변수 저장용도 많이 사용된다.

특정 Assembly 명령어(MUL, DIV, LODS, etc)에서는 특정 레지스터를 직접 조작하기도 한다.

 

그리고 ECXEAX는 특수한 용도로 사용될 때가 있다.

 

ECX는 반복문 명령어(Loop)에서 참조 카운트로 사용된다. (루프를 돌 때마다 ECX 1씩 감소시킨다.)

EAX는 일반적으로 함수 리턴값에 사용된다. (Win32 API 함수들은 모두 리턴값을 EAX에 저장한 후 리턴한다.)

 

Windows Assembly 프로그래밍에서 주의할 점!

    Win32 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 기법이라고 한다.)

 

ESIEDI는 특정 명령어(LODS, STOS, REP MOVS, etc)와 함게 주로 메모리 복사에 사용된다.

 

 

#2. Segment Register

세그먼트란 IA-32 메모리 모델에서 나오는 용어이다.

 

따라서 세그먼트 레지스터를 이해하려면 먼저 OS 내부구조의 '보호모드' '메모리 모델'의 개념을 이해해야 한다.

일단 이에 대해서는 개념적으로 간단히 알아보도록 하자.

 

IA-32 보호모드에서 세그먼트란 메모리를 조각내어

각 조각마다 시작주소, 범위, 접근 권한 등을 부여해서 메모리를 보호하는 기법을 말한다.

 

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

 

세그먼트 메모리는 segment descriptor table이라고 하는 곳에 기술되어 있는데,

세그먼트 레지스터는 이 segment descriptor table index를 가지고 있다.

 

아래 그림은 보호모드에서의 세그먼트 메모리 모델을 나타내고 있다.

 

 

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

 

<Fig. 3>에서 각 세그먼트 레지스터가 가리키는 세그먼트 디스크립터와 가상 메모리가 조합되어 선형주소(Linear Address)가 되며,

 페이징(Paging) 기법에 의해 선형주소가 최종적으로 물리주소(Physical Address)로 변환된다.

 

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

 

각 세그먼트 레지스터의 이름은 아래와 같다.

 

 - CS : Code Segment

 - SS : Stack Segment

 - DS : Data Segment

 - ES : Extra(Data) Segment

 - FS : Data Segment

 - GS : Data Segment

 

이름 그대로 CS는 프로그램의 코드 세그먼트를 나타내며,

SS스택 세그먼트, DS데이터 세그먼트를 나타낸다.

 

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

 

FS 레지스터는 애플리케이션 디버깅에도 자주 등장하는데 SEH(Structured Exception Handling), TEB(Thread Environment Block),

PEB(Process Environment Block) 등을 구할 때 사용된다. (이들은 모두 고급 디버깅 주제이다.)

 

 

#3. Program Status and Control Register

플래그 레지스터의 이름은 EFLAGS이며 32bit (4byte) 크기이다.

 

각 레지스터 bit마다 의미를 가지고 있고 1또는 0의 값을 가지며 On/Off 또는 True/False를 표시한다.

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

 

Flag란 단어 그대로 깃발이 올라가면 1(On), 내려가면 0(Off)으로 이해하면 된다.

 

 

32 bit 모두의 의미를 전부 이해한다는 것은 힘든 일이지만,

애플리케이션 디버깅에 가장 중요한 3가지 Flag는 꼭 이해해야 한다.

 

Zero Flag : 연산 명령 후에 결과값이 0이 되면 ZF 1로 세팅된다.

Overflow Flag : 부호 있는 수(signed integer)의 오버플로우가 발생했을 때 1로 세팅된다.

                     MSB(Most Significant Bit)가 변경되었을 때 1로 세팅된다.

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

 

 

#4. Instruction Pointer

 

EIP : Instruction Pointer

 

CPU가 처리할 명령어의 주소를 나타내는 레지스터이며, 크기는 32bit (4byte)이다.

CPU는 하나의 명령(instruction)을 처리하고 난 후 자동으로 그 명령어 길이만큼 EIP를 증가시킨다.

 

General Purpose Register들과는 다르게 EIP그 값을 직접 변경할 수 없도록 되어 있다.

 

EIP를 변경하고 싶을 대는 특정 명령어(JMP, Jcc, CALL, RET), 인터럽트(interrupt), 예외(exception)를 발생시켜야 한다.

'정상을향해 > Program Analysis' 카테고리의 다른 글

PE File Format (3)  (0) 2013.11.10
PE File Format (2)  (0) 2013.11.10
PE File Format (1)  (0) 2013.11.10
Calling Convention  (0) 2013.11.10
Stack Frame  (0) 2013.11.10
[ASM] 어셈블러 : 범용 레지스터  (0) 2011.05.16