CPU 레지스터
메모리는 아래의 그림과 같은 계층 구조를 갖고 있다. 이러한 계층 구조는 메모리를 필요에 따라 여러 가지 종류로 나누어 놓는 것으로, 이렇게 나누어 놓은 것은 대부분 CPU가 메모리에 더 빨리 접근하도록 하기 위함이다. 하드 디스크는 직접 CPU에 접근할 방법이 존재하지 않고, 메모리는 CPU 외부에 존재하고 있기 때문에 캐시와 레지스터보다 더욱 느리게 접근된다. 이와 같이 레지스터는 CPU가 메모리에 더 빨리 접근하기 위해 존재한다.
레지스터는 CPU의 작은 저장 공간으로 CPU가 데이터에 접근하는 가장 빠른 방법을 제공한다 하였다. IA-32에서 CPU는 8개의 범용 레지스터와 명령 포인터, 5개의 세그먼트 레지스터, 그리고 부동 소수점 데이터 레지스터가 존재하고 있다. 이에 대하여 각각 알아보자.
범용 레지스터 & 명령 포인터
범용 레지스터에는 8개의 레지스터가 존재하고 있다. 리버싱을 한 번이라도 해본 사람이라면 OllyDBG의 우측 상단에 존재하고 있는 레지스터 창을 보았을 것이다. 이러한 범용 레지스터를 설명하기 전에 레지스터의 크기에 대하여 먼저 알아보자.
일반적으로 EAX, ECX, EDX와 같이 'Extened'가 붙어 있는 경우를 많이 볼 수 있다. 하지만 유연한 진행을 위하여 하나의 EAX에서도 일부만 사용해야 할 상황이 필요하다. 그렇기에 비트가 나누어지는 것에 대하여 알아야 하는데, EAX는 32비트(DWORD)로 우리가 흔히 알고 있는 4바이트의 크기를 같는다. AX의 경우 16비트(WORD)의 크기를 갖는데, 이는 다시 상위 8비트(BYTE) AH와 하위 8비트(BYTE) AL로 구분할 수 있다.
EAX 레지스터(Accumulator Register)
주로 산술 연산과 리턴 값을 전달하기 위해 사용되며 상대적으로 사용되어 값이 자주 변하기 때문에 값을 보존하는 용도로 사용하지는 않는다. 산술 연산으로는 곱셈이나 나눗셈, 덧셈, 뺄셈 등 대부분의 경우 EAX에 해당 값이 들어 있는 경우가 많다. EAX가 리턴 값을 사용되는 경우란, C언어를 예로 Main() 함수에서 다른 함수 Sub()를 호출하였을 때 Sub()에서 "return 0;"을 사용하였다면 어셈블리에서는 Sub()가 RETN 명령어를 동작하기 전에 EAX 레지스터에 "MOV EAX, 0"과 같은 명령어를 사용하여 저장한다. 이렇게 값을 저장하기 때문에 해당 값을 다시 Main()에서 사용될 수 있게 된다.
ECX 레지스터(Counter Register)
반복문으로 인해 나타난 루프(Loop)에서 반복의 횟수를 제어할 때 주로 사용되며, EAX와 같이 많은 연산에 사용될 수도 있다.
EDX 레지스터(Data Register)
EAX와 함께 연산 작업에 주로 사용되며, 특히 나눗셈의 경우 피제수(소수)를 EDX에 넣어서 연산하며 연산 결과 몫은 EAX에 나머지는 EDX에 입력된다.
EBX(Base Index Register)
베이스 인덱스를 지정하는 용도로 사용되지만, 다른 레지스터 또한 베이스 인덱스를 지정하는데 자주 사용된다. 따라서 EBX는 특정한 역할을 갖기보다는 주로 변하지 않는 값을 저장할 때 사용된다.
ESI(Source Index Register) & EDI(Destination Index)
ESI와 ESI의 경우 반복문 등을 통하여 ESI에 있는 값을 EDI에 복사하고자 할 때 사용된다. 따라서 복사할 데이터는 ESI에 존재하고 있으며, 복사되어 저장될 새로운 공간을 EDI가 가리키고 있다.
ESP(Stack Pointer Register) & EBP(Base Pointer Register)
하나의 스택 프레임에 있어서 ESP는 스택의 끝 위치를 나타내며 EBP의 경우 스택의 시작 위치를 나타낸다. EBP의 경우 스택 프레임의 시작 위치 값을 갖고 있기 때문에 값이 잘 변하지 않지만, ESP의 경우 스택에 PUSH와 POP 명령어 등을 사용하기 때문에 유동적으로 값이 자주 변화한다.
EIP(Instruction Pointer)
EIP에는 다음에 실행해야 할 명령어가 존재하는 메모리 주소가 저장된다. 현재 명령어를 실행 완료한 후 EIP레지스터에 저장되어 있는 주소에 위치한 명령어를 실행하게 된다.
세그먼트 레지스터
세그먼트는 프로그램에 정의된 메모리 상의 특정 영역으로 코드, 데이터, 스택 등을 포함하며 메모리의 대부분에 위치할 수 있다. 각 세그먼트 레지스터는 자신에게 지정된 주소를 가리키고 있으며, 기본적으로 CS, DS, SS 3개의 레지스터가 사용되며 이외에 ES, FS, GS 레지스터가 필요에 따라 사용될 수 있다.
CS (Code Register)
CS 레지스터는 코드 세그먼트의 시작 주소를 가리키며, 해당 세그먼트 주소에 EIP 레지스터의 오프셋 값을 더하면, 실행하기 위해 메모리로부터 가져와야 할 명령어의 주소가 된다. 일반적인 프로그래밍에서는 이 레지스터를 직접 참조할 필요가 없다.
DS (Data Register)
DS 레지스터는 프로그램의 데이터 세그먼트의 시작 주소를 포함한다. 명령어는 이 주소를 사용하여 데이터의 위치를 알아내며, 이 주소에 EIP 값을 더하면 데이터 세그먼트에 속한 특정 바이트 위치에 대한 참조가 생성된다.
SS (Stack Register)
SS 레지스터는 메모리 상에 스택의 구현을 가능하게 한다. 프로그램은 주소와 데이터의 임시 저장 목적으로 스택을 사용한다. 시스템은 프로그램의 스택 세그먼트의 시작 주소를 SS레지스터에 저장하며, 이 세그먼트 주소에 ESP 레지스터의 오프셋 값을 더하면 참조되고 있는 스택의 현재 워드를 가리킨다.
ES & FS & GS
이 3개의 레지스터는 Extra Segment로 여분의 데이터 세그먼트이다. ES의 경우 주로 문자열과 관련된 명령어를 위해 사용되는 세그먼트며, FS 세그먼트의 경우 TIB를 가리키는 세그먼트로 주로 안티 디버깅에 의해 참조될 수 있다. 특히 FS:[0x30]의 경우 PEB(Process Environment Block)를 가리키고 있기 때문에 디버깅 여부를 확인할 수가 있다. 이와 같이 FS의 경우 특정한 용도로 사용된다. 마지막으로 GS의 경우도 여분의 데이터 세그먼트로 주로 스택 스매싱이 일어났는지 확인할 때 사용할 수 있다.
플래그 레지스터
32비트 플래그는 다양한 컴퓨터 행동의 상태를 나타내는 비트를 포함하고 있다. 많은 플래그가 존재하고 있지만, 여기서는 OllyDBG와 같이 디버거에서 자주 볼 수 있는 플래그들에 대해서만 알아보자.
CF (Carry flag), 연산을 수행하면서 carry 혹은 borrow가 발생하면 1이 된다. Carry와 Borrow는 덧셈 연산 시 bit bound를 넘어가거나 뺄셈을 하는데 빌려오는 경우를 말한다.
PF (Parity flag), 연산 결과 최하위 바이트의 값이 짝수일 경우에 1이 되며 홀수일 경우 0이 된다. 이는 패리티 체크를 하기 위해 사용된다.
AF (Adjust flag), 8(16) 비트 연산에서, 하위 4(8) 비트로부터 상위 4(8) 비트로 자리올림이나 내림이 발생한 경우에 1로 셋 되고 그 외의 경우 0으로 셋 된다.
ZF (Zero flag), 산술 및 논리 연산의 결과가 0 일 때 설정된다. 만약 연산의 결과가 0이 아닌 경우 해당 플래그는 0으로 나타나며, 연산 결과가 0일 경우 플래그가 셋 되어 1이 된다.
SF (Sign flag), 부호 비트가 1인 경우에는 1로 설정되고, 0인 경우 0으로 설정된다. 이는 다시 말해 음수인 경우에 1이 되는 것이며, 양수인 경우 0 임을 뜻한다.
TF (Trap flag), 디버깅에 사용되는 플래그로 설정된 경우 CPU는 명령 하나를 실행할 때마다 자동적으로 내부 인터럽트 1(INT1)이 발생한다. 해당 플래그가 설정된 경우 디버깅 시 Sing-Step이 가능해진다.
DF (Direction flag), 문자열을 처리할 때 해당 플래그가 0일 경우 문자열의 번지를 나타내는 레지스터 값이 자동으로 증가하고, 해당 플래그가 1일 경우 이러한 번지를 나타내는 값이 자동으로 감소한다.
OF (Overflow flag), 정수형 결과 값이 너무 큰 양수이거나 너무 작은 음수여서 피연산자의 데이터 타입에 모두 들어가지 않을 경우 1이 된다.
Reference
http://mafa.tistory.com/entry/3장-CPU-레지스터
http://carpedm20.blogspot.kr/2012/08/blog-post_13.html
https://en.wikipedia.org/wiki/Win32_Thread_Information_Block#Accessing_the_TIB
https://en.wikipedia.org/wiki/Process_Environment_Block
http://egloos.zum.com/voals/v/1669866
http://karfn84.tistory.com/entry/어셈블리-레지스터의-기능
'Reversing > Theory' 카테고리의 다른 글
BOF에 취약한 함수 (1) | 2016.03.30 |
---|---|
윈도우 메모리구조와 메모리분석 기초 (3) | 2016.03.29 |
C기본 문법 어셈블리 변환 (5) | 2016.03.20 |
Visual Studio 메인함수 찾기 (1) | 2016.03.16 |
ClamAV & PEiD to Yara Rules (1) | 2016.03.11 |