안녕하세요.
칸입니다.
오늘은 저번에 말씀드렸듯이 IA-32 Register에 대해 자세히
정리 해보도록 하겠습니다.
(2017.01.09)
0. 들어가기에 앞서...
매 정리 포스팅때마다 말씀드렸지만 저도 아직 배우는 입장이라 100% 맞는것은 아닙니다. [정리]가 붙어있는 글들은 제가 공부한 내용을 정리할 겸 올리는 글입니다. 참고해주세요. 또한 본문에 활용되는 대부분의 예제는 '리버싱핵심원리', 이승원 저자, 인사이트 를 참고했음을 밝힙니다.
1. 레지스터(Register)란?
레지스터는 CPU 내부에 존재하는 다목적 저장 공간입니다. CPU는 레지스터와 한몸이기때문에 고속으로 데이터를 처리할 수 있습니다. 또한 레지스터에는 범용 레지스터, 세그먼트 레지스터, 상태 플래그 지스터, 명령 포인터 레지스터가 존재합니다.
Q. 왜 레지스터를 알아야 하는가?
A. 리버싱 초급 단계에서 애플리케이션 디버깅을 잘 하려면 디버거가 해석(디스어셈)해주는 어셈블리 명령어를 공부해야 합니다. IA-32(Intel Architecture 32bit)에서 제공하는 어셈블리 양은 매우 방대해서 한번에 공부하기는 쉽지 않습니다. 또한 어셈블리 명령어의 대부분은 레지스터를 조작하고 그 내용을 검사하는 것들이라 레지스터를 모르면 명령어 자체도 이해하기 힘듭니다.
2. IA-32 레지스터
IA-32 레지스터 종류는 여러가지 입니다. 예컨대 Basic program execution registers, x87 FPU Registers, MMX registers 등이 있습니다. 애플리케이션 디버깅의 초급단계에서는 Basic program execution register에 대해 알아두어야 합니다. 책에서는 향후 중/고급 단계가 되면 Control Register, Memory management registers 등에 대해서도 공부해보길 권장하고 있습니다.
2.1 Basic program execution registers
Basic program execution registers 를 4개의 그룹으로 다시 나눌수 있습니다.
-> [ 그림 2.1.1] 참고
* General Purpose Registers (범용 레지스터) - 32bit 8개
* Segment Registers (세그먼트 레지스터) - 16bit 6개
* Program Status and Control Register (프로그램 상태와 컨트롤 레지스터) - 32bit 1개
* Instruction Pointer (명령어 포인터) - 32bit 1개
[그림 2.1.1]
※ 참고
-> 레지스터 이름에 E(Extended, 넓혔다)가 붙은 경우 16Bit CPU인 IA-16 시절부터 존재하던 16비트 크기의 레지스터들을 32Bit 크기로 확장시켰다는 뜻입니다.
2.1.1 범용 레지스터
쉽게 막쓰는 레지스터들이라고 생각하면 됩니다. 8개의 각각의 범용 레지스터의 크기는 32Bit(4Byte)입니다. 주로 상수나 주소등을 저장할 때 사용되고, 특정 어셈블리 명령어에서는 특정 레지스터를 조작하기도 합니다.
[그림 2.1.2]
출처는 위와 같음
위에 4개의 레지스터(EAX, EBX, ECX, EDX)는 주로 산술연산(ADD, SUB, XOR 등) 명령어에서 상수나 변수 값의 저장용도로 많이 사용되고, 어떤 어셈블리 명령어(MUL, DIV, LODS 등)들은 특정 레지스터를 직접 조작합니다(이러한 명령어가 실행된 이후에는 특정 레지스터들의 값이 변경됩니다).
앞에 어셈블리어 정리에서 말했듯이 ECX는 반복문 명령어(LOOP)에서 반복카운트(예컨대 for문에서의 i역할,보통 for문에서의 i와 다르게 루프를 돌때마다 ECX를 1씩 감소됩니다)로 사용됩니다.
또한 EAX는 산술연살과 더불어 함수 리턴값에도 사용됩니다 모든 Win32 API 함수들은 리턴 값을 저장한 후 리턴합니다.
나머지 4개 범용 레지스터의 이름은 다음과 같습니다.
* 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.1.2 세그먼트 레지스터
세그먼트(Segment)란 IA-32의 메모리 관리 모델에서 나오는 용어입니다. IA-32 보호 모드에서 세그먼트는 메모리를 조각내어 각 조각마다 시작주소, 범위, 접근 권한 등을 부여해서 메모리를 보호하는 기법입니다.
세그먼트 레지스터는 총 6개가 존재합니다. 이름은 CS, SS, DS, ES, FS, GS 이고 크기는 16Bit(2Byte)입니다.
CS와 SS, DS의 경우 이름그대로 CS는 Code Segment로 프로그램의 코드 세그먼트를 나타내며, SS는 Stack Segment, DS는 Data Segment를 나타냅니다.
ES, FS, GS 세그먼트는 추가적인 데이터 세그먼트 입니다. 마지막으로 FS 레지스터는 애플리케이션 디버깅에도 자주 등장하게 되는데 SEH, PEB등의 주소를 계산할 때 사용되며 이는 고급 디버깅 주제이므로 저는 아직은 자세하게 알지 못합니다.
2.1.3 프로그램 상태와 컨트롤 레지스터
플래그(Flag) 레지스터의 이름은 EFLAGS이며 32Bit(4Byte) 크기 입니다.
* EFLAGS : Flag Register
[그림 2.1.3]
출처는 위와 같음
[그림 2.1.3]은 EFLAGS 레지스터를 나타냅니다. 그림을 보면 알수 있듯이 각각의 비트마다 0이나 1을 가지고 있는데 이는 On/Off 나 True/False를 의미합니다. 일부 비트는 시스템에서 직접 세팅하고 일부는 프로그램에서 사용된 명령의 수행 결과에 따라 세팅됩니다. ( Flag 단어 그대로 생각해서 올라가면 1(on/true) 내려가면 0(off/false)로 이해하면 됩니다)
일단 초급단계 이므로 애플리케이션 디버깅에 필요한 3가지 flag인 ZF, OF, CF에 대해서만 이해하면 됩니다.왜냐하면 이 3개의 플래그는 조건 분기 명령어(Jcc, 예컨대 JE, JZ, JNZ 등 )에서 이들 Flag의 값을 확인하고 그에 따라 동작 수행 여부를 결정하기 때문입니다.
* Zero Flag(ZF)
연산 명령 후에 결과값이 0이 되면 ZF가 1(True)로 세팅 됩니다.
* Oerflow Flag(OF)
부호 있는 수(signed integer, 실수)의 오버플로가 발생했을 때 1로 세팅됩니다. 그리고 MSB(Most Significant Bit, ex 00001200-> 10001200)가 변경되었을 때 1로 세팅됩니다.
* Carry Flag(CF)
부호 없는 수(unsigned integer, 정수)의 오버플로가 발생했을 때 1로 세팅됩니다.
※ 참고
* Overflow : 레지스터나 컴퓨터가 다룰수 있는 수의 범위에서 삐어져 나온 상태
ex) 2bit에서 3+2 = 5, 11 + 10 = 101 이때 overflow라 함
* MSB(Most Significant Bit) : 최상위 비트, 가장 왼쪽에 있는 비트
https://ko.wikipedia.org/wiki/%EC%B5%9C%EC%83%81%EC%9C%84_%EB%B9%84%ED%8A%B8
* unsigned 와 signed
ex) char 1 byte(8bit) -128 ~ +127
unsigned 1 byte(8bit) 0 ~ 255
2.1.4 명령어 포인터 (Instruction Pointer)
* EIP : Instruction Pointer
EIP는 CPU가 처리할 명령어의 주소를 나타내는 레지스터이고 크기는 32Bit(4Byte)입니다. 이또한 앞에 E가 붙여있으므로 16비트의 IP 레지스터의 확장형태라는 것을 알 수 있습니다.
CPU는 EIP에 저장된 메모리 주소의 명령어(Instruction)를 하나 처리하고 난 후 자동으로 그 명령어 길이만큼 EIP를 증가시킵니다.
범용 레지스터들과는 다르게 EIP는 그 값을 직접 변경할 수 없도록 되어 있어 다른 명령어를 통하여 간접적으로 변경해야 합니다. 예컨대 특정 명령어(JMP, Jcc, CALL, RET)를 사용하거나 인터럽트(Interrupt). 예외(Exception)를 발생 시켜야 합니다.
3. 마치면서...
다음번에는 스택에 대해 정리해보도록 하겠습니다.
읽어 주셔서 감사합니다.
'Security > Malware Analysis' 카테고리의 다른 글
[정리] 스택 (0) | 2018.03.07 |
---|---|
[정리] 리틀, 빅 엔디언 (0) | 2018.03.07 |
[정리] 어셈블리어 정리 (0) | 2018.03.07 |