Pwnable/정리

Buffer Overflow기초 - 8086 CPU 레지스터 구조

dtqdtq01 2018. 9. 9. 23:20


8086 CPU 레지스터 구조














































































  CPU가 프로세스를 실행하기 위해서는 프로세스를 CPU에 적재시켜야 할 것이다. 그리고 이렇게 흩어져 있는 명령어 집합(Instruction Set)과 데이터들을 적절하게 집어내고 읽고 저장하기 위해서는 여러 가지 저장 공간이 필요하다. 또한 CPU가 재빨리 읽고 쓰기를 해야 하는 데이터들이므로 CPU내부에 존재하는 메모리를 사용한다. 이러한 저장 공간을 레지스터(Register)라고 한다.


레지스터(Register)는 다시 그 목적에 따라서 4개의 종류로 나누어진다.


- 범용 레지스터 (General-Purpose Register)

- 세그먼트 레지스터 (Segment Register)

- 플래그 레지스터 (Program Status and Control Register)

- 인스트럭션 레지스터 (Instruction Register)




○  범용 레지스터 (General-Purpose Register)


  범용 레지스터는 프로그래머가 임의로 조작할 수 있게 허용되어 있는 레지스터다. 일종의 4개의 32bit 변수라고 생각하면 된다. 예전의 16bit 시절에서는 각 레지스터를 AX, BX, CX, DX ..  등으로 불렸지만 32bit 시스템으로 전환되면서 E(Extended)가 앞에 붙어 EAX, EBX, ECX, EDX.. 등으로 불린다.




EAX - 피연산자와 연산 결과의 저장소

EBX - DS Segment안의 데이터를 가르키는 포인터

 

ECX - 문자열 처리나 루프를 위한 포인터

 

EDX - I/O 포인터


ESI - DS 레지스터가 가리키는 Date Segment 내의 어느 데이터를 가르키고 있는 포인터. 문자열        처리에서 Source를 가리킴

 

EDI - ES 레지스터가 가르키는 Date Segment 내의 어느 데이터를 가르키고 있는 포인터. 문자열        처리에서 Destination을 가리킴


ESP - SS 레지스터가 가르키는 Stack Segment의 맨 꼭대기를 가리키는 포인터


EBP - SS 레지스터가 가르키는 스택상의 한 데이터를 가리키는 포인터



○  세그먼트 레지스터 (Segment Register)



  세그먼트 레지스터는 프로세스의 특정 세그먼트를 가리키는 포인터 역할을 한다. CS 레지스터는 Code Segment를 가리키고, DS, ES, FS, GS 레지스터는 Data Segment를 가르키고, SS 레지스터는 Stack Segment를 가리킨다. 이렇게 세그먼트 레지스터가 가리키는 위치를 바탕으로 우리는 원하는 Segment안의 특정 데이터, 명령어들 정확하게 끄집어 낼 수가 있게 된다.




아래의 그림은 각 레지스터가 가리키는 세그먼트들을 설명해 주고 있다.




○  플래그 레지스터 (Program Status and Control Register)


  컨트롤 플래그 레지스터는 상태 플래그, 컨트롤 플래그, 시스템 플래그들의 집합이다. 시스템이 리셋되어 최기화 되면 이 레지스터는 0x00000002의 값을 가진다. 그리고 1, 3, 5, 15, 22~31번 비트는 예약되어 있어 소프트웨어에 의해 조작할 수 없게 되어 있다. 위 그림은 플래그 레지스터의 구조를 보여주고 있다.




☞ 상태 플래그 (Status Flags)


CF - Carry Flag, 연산을 수행하면서 carry 혹은 borrow가 발생하면 1이 됩니다. (carry, borrow : 뎃셈 연산 시 bit bound를 넘거나 뺄셈 시 빌려오는 경우)


PF - Parity Flag, 연산 결과 최하위 바이트의 값이 1이 짝수 일 경우에는 1이 되며, 패리티 체크를 하는데 사용됩니다.


AF - Adjust Flag, 연산 결과 carry나 borrow가 3bit 이상 발생할 경우 1이 됩니다.


ZF - Zero Flag, 결과가 zero임을 가리킵니다. if문 같은 조건문에서 참일 경우 set 됩니다.


SF - Sign Flag, 연산 결과 최상위 비트와 값이 같습니다. 


OF - Overflow Flag, 정수형 결과값이 너무 큰 양수이거나 너무 작은 음수여서 피연산자의 데이터 타입에 모두 들어가지 않을 경우 1이 됩니다.


DF - Direction Flag, 문자열 처리에서 1일 경우 문자열 처리 Instruction이 자동으로 감소(문자열 처리가 high address에서 low address로 이루어짐), 0일시 자동으로 증가 합니다.



☞ 시스템 플래그 (System Flags)


IF - Interrupt enable Flag, 프로세서에게 Mask한 Interrput에 응답할 수 있게 하려면 1을 줍니다.


TF - Trap Flag, 디버깅을 할 때 single-step을 가능하게 하려면 1을 줍니다. 


IOPL - I/O Privilege Level field, 현재 수행 중인 프로세스 혹은 Task의 권한 레벨을 가리킨다.


NT - Nested Task flag, Interrput의 chain을 제어한다. 1이 되면 이전 실행 Task와 현재 Task가 연결되어 있음을 나타낸다.


RF - Resume Flag, Exception debug를 하기 위해 프로세서의 응답을 제어한다.


VM - Virtual-8086 Mode flag, Virtual-8086 모드를 사용하려면 1을 준다.


AC - Alignment Check flag, 이 비트와 CR0 레지스터의 AM 비트가 set되어 있으면 메모리 레퍼런스의 Alignment checking이 가능하다.


VIF - Virtual Interrput Flag, IF flag의 가상 이미지이다. VIP Flag와 결합시켜 사용한다.


VIP - Virtual Interrput Pending flag, 인터럽트가 pending(경쟁 상태) 되었음을 가리킨다.


ID - Identification flag, CPUID Instruction을 지원하는 CPU인지를 나타낸다. 



○  인스트럭션 레지스터 (Instruction Register)


  Instruction 포인터 레지스터는 다음 실행할 명령어가 있는 현재 Code Segment의 Offset 값을 가진다. 이것은 하나의 명령어 범위에서 선형 명령 집합의 다음 위치를 가리킬 수 있다. 뿐만 아니라 JMP, Jcc, CALL, RET와 IRET Instruction이 있는 주소값을 가진다. EIP 레지스터는 소프트웨어에 의해 바로 엑세스 할 수 없고 Control-transfer Instrucion이나 Interrput와 Exception에 의해서 제어된다. EIP 레지스터를 읽을 수 있는 방법은 CALL Instruction을 수행하고 나서 프로시저 스택으로부터 리턴하는 Instruction을 읽는 것이다.포로시저 스택의 Return Instruction pointer의 값을 수정하고 Return Instruction(RET, IRET)을 수행함으로 해서 EIP 레지스터의 값을 간접적으로 지정이 가능하다.