[리버싱 핵심원리] 1부 4장 정리
본 게시글의 내용은 리버싱 핵심원리를 보며 복습 겸 정리를 위해 작성하였습니다.
책 내용과 일부 다를 수 있고, 이해를 돕기 위한 저만의 예시도 일부 포함되어 있습니다.
본 게시글에서 사용되는 소스코드와 파일은 리버싱 핵심원리에서 제공하는 파일을 사용하며, 사용하는 도구는 다를 수 있습니다.
레지스터
레지스터(Register)란 CPU(프로세서) 내부에 존재하는 다목적 공간을 말합니다. CPU 내부에서 데이터를 저장하고 처리하는 아주 작은 메모리 공간으로, CPU가 직접 접근하고 제어할 수 있는 가장 빠른 저장 장치(메모리보다 더 빠름)입니다.
IA-32
IA-32(Intel Architecture, 32Bit)는 인텔(Intel)의 32비트 x86 아키텍쳐를 말합니다. 32비트의 주소 공간과 데이터 레지스터를 지원합니다. 현재는 64비트 아키텍쳐인 IA-64나 x86-64가 널리 사용되고 있지만, 일부 구형 시스템에선 IA-32를 사용하거나 동작하도록 지원하는 경우가 있기 때문에 알아두는 것이 좋습니다.
Basic Program Execution Registers
기본 프로그램 실행 레지스터(Basic Program Execution Registers)는 IA-32에서 기본적인 프로그램 실행을 위한 레지스터를 말하며, 4개의 그룹으로 나뉩니다.
General Purpose Registers
범용 레지스터(General Purpose Registers)는 이름 그대로 범용적으로 사용되는 레지스터입니다. IA-32에서는 EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP라는 8개의 32비트 레지스터가 존재하며, 각 레지스터는 특정 용도에 따라 구분되어 사용되기도 합니다.
각 레지스터는 하위 호환을 위해 몇 개의 구획으로 나누어집니다. (아래는 EAX 기준)
- EAX: 0~31 (32Bit)
- AX: 0~15 (EAX의 하위 16Bit)
- AH: 8~15 (AX의 상위 8Bit)
- AL: 0~7 (AX의 하위 8Bit)
32Bit를 다 사용하고 싶다면 EAX를 사용하고, 16Bit만 사용하고 싶다면 AX를, 8Bit를 사용하고 싶다면 AH나 AL을 사용합니다. 레지스터를 상황에 맞게 필요한만큼 사용할 수 있습니다.
IA-32에서는 16비트 아키텍쳐에서 사용하던 레지스터를 확장한 32비트 레지스터를 도입했고, 레지스터 이름 앞에 E를 수식하여 확장된(Extended) 레지스터임을 구분하고 있습니다.
EAX(Accumulator Register) 레지스터는 주로 산술 연산에 사용되고, 함수 호출 시 반환 값이 저장되는 용도로 사용되기도 합니다.
EBX(Base Register) 레지스터는 주로 메모리 주소 계산에 사용됩니다.
ECX(Counter Register) 레지스터는 반복 연산(반복문)의 카운터로 사용됩니다.
EDX(Data Register) 레지스터는 일부 산술 연산과 I/O 연산 작업에서 사용됩니다.
ESI(Source Index) 레지스터는 문자열 데이터 처리에서 원본 문자열 데이터를 가리키는 인덱스로서 사용됩니다.
EDI(Destination Index) 레지스터는 문자열 데이터 처리에서 대상(Target) 문자열 데이터를 가리키는 인덱스로서 사용됩니다.
EBP(Base Pointer) 레지스터는 스택 프레임을 참조하는 데 사용됩니다. 함수 호출 시 스택에 저장된 인자나 지역 변수를 가리킵니다.
ESP(Stack Pointer) 레지스터는 스택의 최상위 주소를 가리킵니다. 함수 호출 시 스택에 데이터를 push 또는 pop할 때 사용됩니다.
스택 메모리 관리는 중요하기 때문에 ESP 레지스터를 다른 용도로 사용해선 안 됩니다.
Segment Registers
세그먼트(Segment)는 컴퓨터 시스템에서 메모리를 논리적으로 나누는 단위로, 특정 데이터나 작업을 수행할 때 사용되는 메모리 영역을 말합니다.
세그먼트는 페이징(Paging) 기법과 함께 가상 메모리를 실제 물리 메모리로 변경할 때 사용됩니다. 세그먼트 메모리는 Segment Descriptor Table(SDT)이라는 곳에 기술되어 있는데, 세그먼트 레지스터는 이 SDT의 Index를 갖고 있습니다. 이 세그먼트 레지스터를 사용함으로써 SDT에 접근할 수 있습니다.
세그먼트 레지스터는 CS, DS, SS, ES, FS, GS로 총 6개이며, 각 크기는 16비트입니다. CS는 실행 중인 프로그램의 코드 세그먼트, DS는 데이터 세그먼트, SS는 스택 세그먼트를 나타냅니다. ES, FS, GS는 추가적인 데이터 세그먼트로, 더 이상의 자세한 설명은 생략하고 이후 고급 디버깅에서 다시 다룹니다.
EFLAGS
상태 레지스터(Flag Registers)를 EFLAGS(Extended Flags Register)라 부르며, CPU의 상태와 실행 중인 프로그램의 제어를 관리합니다.
EFLAGS는 총 32Bit의 크기를 갖고 있으며, 과거 16Bit FLAGS의 확장 버전입니다. 각 Bit는 0 또는 1의 값을 가지며, 일부 Bit는 명령 결과에 따라 값이 설정됩니다.
EFLAGS의 각 비트에 있는 플래그를 이해하고 외우는 건 쉬운 일이 아닙니다. 그렇기에 아래의 세 가지 플레그만 기억해주세요.
- ZF(Zero Flag): 연산 명령 후 결과 값이 0이 되면 ZF가 1로 설정됩니다.
- OF(Overflow Flag): 부호 있는 수(Signed Integer)의 오버플로우가 발생했을 때 1로 설정됩니다. 부호 비트(MSB, Most Significant Bit)가 변경되었을 때도 1로 설정됩니다.
- CF(Carry Flag): 부호 없는 수(Unsigned Integer)의 오버플로우가 발생했을 때 1로 설정됩니다.
Instruction Pointer
Instruction Pointer는 CPU가 다음에 실행할 명령의 메모리 주소를 저장하는 레지스터입니다. IA-32에서 EIP 레지스터에 사용하며, IP 레지스터의 확장된 버전입니다.
범용 레지스터와는 다르게 직접 값을 수정할 수 없기 때문에 명령어를 통해 간접적으로 수정해야 합니다.
주제 가리지 않고 잡다하게 다 하는 블로그