본문 바로가기

리버스 엔지니어링

IA-32 Register 기본 설명

애플리케이션 디버깅의 디버깅을 위해기본적으로알아야 할  IA-32(Intel Architecture 32비트)의 레지스터에 대하여 알아보도록 하자.



CPU 레지스터란?


레지스터(Register)란 CPU 내부에 존재하는 다목적 저장 공간이다. 우리가 일반적인 메모리라고 하는  RAM과는 성격이 다른데 RAM은 메모리를 물리적으로 멀리 돌아가야 때문에 떄문에 시간이 오래 걸리지만 레지스터는 CPU 내부에 있기 때문에 고속으로 데이터를 처리할 수 있다.



레지스터에 대해서 알아야 하는 이유


리버싱 초급 단계에서 애플리케이션 디버깅을 잘 하려면 디버거가 해석해주는 어셈블리 명령어를 공부해야 한다. IA-32에 제공하는 어셈블리 명령어는 매우 방대한 양이라서 한번에 공부하기는 쉽지 않다. 어셈블리명령어는 대부분은 레지스터를 조작하고 그 내용을 검사하는 것들인데 정작 레지스터를 모르면 명령어를 이해하기 힘든 면이 있다.


IA-32의 레지스터는 기능도 많고 수도 많지만 일단 Basic Program Execution Register에 대해 알아야 하는데 디버깅을 할 때 가장 많이 보이기 때문이다. Basic Program Execution Register는 4개의 그룹으로 나누어지는데 종류는 다음과 같다.



 General Purpose Registers (32비트 - 8개)

 Segment Registers (16비트 - 6개)

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

 Instruction Pointer (32비트 - 1개)



각 하나씩 확인해보자


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


범용 레지스터는 이름처럼 범용적으로 사용되는 레지스터이다.  IA-32에서 각각의 범용 레지스터들의 크기는 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에 저장한 수 리턴한다.


나머지 범용 레지스터의 이름은 다음과 같다


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)


위 레지스터들은 주로 메모리 주소를 저장하는 포인터로 사용된다. ESP는 스택 메모리 주소를 가르키는데 어떤 명령어들(PUSH,POP,CALL,RET)는 ESP를 직접 조작하기도 한다. 스택 메모리 관리는 프로그램에서 매우 중요하기 때문에 ESP를 다른 용도로 사용하지 말아야 한다

EBP는 함수가 호출되었을 때 그 순간의 ESP를 저장하고 있다가 함수가 리턴 하기 직전에 다시 ESP에 값을 되돌려줘서 스택이 깨지지 않게 한다.(이러한 방법을 stack frame 기법이라고 한다.)

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



2) 세크먼트 레지스터(Segment Register


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

 IA-32 보호모드에서 시그먼트란 메모리를 조각내어 각 조각마다 시작수고, 범위, 접근 권한 등을 부여해서 메모리를 보호하는 기법을 말한다. 또한 세그먼트는 페이징기법과 함께 가상 메모리를 실제 물리 메모리로 변경할 때 사용된다. 세그먼트 메모리는 Segment Descriptor Table(SDT)이란 곳에 기술되어있는데 세그먼트 레지스터는 바로 이 SDT의 인덱스를 가지고 있다.




보호모드에서의 세그먼트는 총 6개가 있는데 각각의 크기는 16비트이다. 


CS : Code Segment

SS : Stack Segment

DS : Data Segment

ES : Extra Segment

FS : Data Segment

GS : Data Segment


CS는 말그대로 코드 세그먼트를 나타네며 SS는 스택 세그먼트 DS는 데이터 세그먼트를 나타낸다. ES,FS,GS는 추가적인 데이터 세그먼트이다.  FS레지스터는 애플리케이션 디버깅에서 자주 나오는데  SEH,TEB,PEB등 주소를 계싼할 떄 사용되며 고급 디버깅 주제이기도 하다.


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


EFLAGS : flag Register




플래그 레지스터의 이름은 EFLAGS이며 32비트 크기이다. EFLAGS 레지스터는 각각의  비트맘다 의미를 가지고 있는데 각 비트마다 1또는 0의 값을 가진느에 이는 on/off를 의미한다. 리버싱 입문단계에서는 주로 쓰이는 ZF,OF,CF만 알아보자.


Zero Flag(ZF)

 연산 명령 후에 결과 값이 0이 되면 ZF가 1(ture)로 세팅된다


Overflow Flag(OF)

 부호 있는 수가 오버플로우가 발생했을때 1로 세팅되고 MSB가 변경되었을 때 1로 세팅된다.


Carry Falg(CF)

 부호 없는 수가 오버플로가 발생했을때 1로 세팅된다.


OF와 CF의 차이를 잘 구별하자.


4) Instruction Pointer


EIP : Instruction Pointer

 Instruction Pointer는 CPU가 처리할 명령어의 주소를 나타내는 레지스터이며 크기는 32비트이다. CPU는 EIP에 저장된 메모리 주소의 명령어를 하나 처리하고 난 후 자동으로 그 명령어 길이만큼 EIP를 증가시킨다. 이런 식으로 명령어를 계속 처리하나간다.

 범용 레지스터들과 다르게 EIP는 그 값을 직접 변경 할 수 없도록 되어 있어서 다른 명령어를 통하여 간접적으로 변경해야 하는데 특정 명령어(JMP,Jcc,CALL,RET)를 사용하거나 인터럽트 예외를 발생시켜야 한다.





지금까지 IA-32 레지스터에 대해서 간략히 살펴보았는데 디버깅의 기초는 어셈블리 명령어의 이해라고 할 수 있다. 그 명령어의 많은 부분은 레지스터를 조작하는 내용이라서 레지스터를 잘 알면 디버깅을 많이 하는데 큰 도움이 될것이다. 하지만 일단은 범용 레지스터의 8개의 각각의 쓰임새라도 알아두자 

'리버스 엔지니어링' 카테고리의 다른 글

abex' crackme#1 분석  (0) 2018.01.04
스택이란?  (0) 2018.01.04
리틀 엔디언 표기법  (0) 2018.01.04
Hello World 문자열 패치  (0) 2018.01.03
Ollydbg BP 설치 방법  (0) 2018.01.03