본문 바로가기

Hacking & Security/System

Buffer Overflow Basic 1

기초관련 내용은 달고나 문서를 참조했습니다.

1.    8086  Memory Architecture

   

위 사진은 8086 시스템의 기본적인 메모리구조다.

시스템이 초기화되기 시작하면 시스템은 커널을 메모리에 적재시키고 가용 메모리 영역(Available Space)을 확인하게 된다.
( 커널 : 컴퓨터 운영체계의 가장 중요한 핵심으로써 운영체계의 다른 모든 부분에 여러가지 기본적인 서비스를 제공.

메모리나 저장장치 내에서 운영체계의 주소공간 관리 , 메모리 관리 역할 )


요즘 사용되는 시스템의 CPU는 64bit이므로 메모리 영역은 0 ~ 2^64 -1 범위를 갖는다.


프로세스 : 하나의 프로그램이 실행되기 위한 메모리 구조.

운영체제는 하나의 프로세스를 실행시키면 이 프로세스를 segment라는 단위로 묶어서 가용 메모리 영역에 저장시킨다. ( 세그먼트에 프로세스가 포함됨.)






오늘날의 시스템은 멀티테스킹이 가능하므로 가용영역에는 여러 개의 프로세스의 세그먼트가 저장되어 병렬적으로 작업 수행이 가능하다.

segment는 언급한 바와 같이 하나의 프로세스를 묶은것으로 실행 시점에 메모리의 어느 위치에 저장될 지가 결정된다.


하나의 세그먼트는 위 그림과 같은 구조를 가지고 있다.    각각을 code segment , data segment , stack segement라고 한다.


Code segment : 시스템이 알아들을 수 있는 명령어 (Instruction)들이 들어있다.    기계어 코드로써 컴파일러가 만들어낸 코드이다.

Instruction들은 명령을 수행하면서 분기,점프,시스템 호출 등을 수행하게 되는데  분기와 점프의 경우는 메모리상의 특정위치에 있는 명령을 지정해줘야한다.
하지만 segment는 자신이 현재 메모리상에 어느위치에 저장될지 컴파일 과정에서는 알 수 없기 떄문에 정확한 주소를 지정할 수 없다.

따라서 segment에서는 logical address를 사용한다.

logical address는 실제 메모리상의 주소 (Physical address)와 매핑되어있다.


Data segment : 프로그램 실행시 사용되는 데이터가 들어간다.    여기서의 데이터는 전역변수들을 말한다.

프로그램 내에서 전역변수를 선언하면 data segment에 자리잡게 된다.


Stack segment : 현재 수행되고 있는 handler , task , program이 저장하는 데이터 영역으로 우리가 사용하는 버퍼가 바로 이 stack segment에 자리잡게 되며 지역변수들이 자리잡는 공간이다.

스택은 처음 생성될 때 필요한 만큼만 만들어지고 프로세스의 명령에 의해 데이터를 저장해 나가는 과정을 거치게 된다.

이것은 stack pointer ( SP )라고 하는 레지스터가 스택의 최상위에 자리잡고있다.

스택에 데이터를 저장하고 읽어들이는 과정은 PUSh&POP Instruction에 의해 수행된다.



2. 8086 CPU 레지스터

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


일반적인 프로그램의 레지스터 구조는 다음과 같다.


레지스터는 그 목적에 따라서 범용 레지스터 , 세그먼트 레지스터 , 플래그 레지스터 , 인스트럭션 포인터로 구성된다.    

범용 레지스터 :  논리&수리 연산에 사용되는 피연산자 , 주소 계산에 사용되는 피연산자 , 메모리 포인터가 저장되는 레지스터.

세그먼트 레지스터 : code segment , data segment , stack segment를 가리키는 주소가 들어있는 레지스터.
플래그 레지스터 : 프로그램의 현재 상태나 조건등을 검사하는데 사용되는 플래그가 들어있는 레지스터.

인스트럭션 포인터 : 다음 수행해야 하는 명령이 들어있는 메모리의 주소가 들어가있다.


범용 레지스터는 프로그래머가 임의로 조작할 수 있게 허용되어 있는 레지스터다.    일종의 4개 (EAX,EBX,ECX,EDX)의 32bit 변수라고 생각하면 된다.

(예전 16bit 시절에는 AX,BX,CX,DX..등으로 불렀지만 32bit 시스템으로 전환되면서 E(Extended)가 앞에 붙음)
ESP - SS 레지스터가 가리키는 stack segment의 맨 꼭대기를 가리키는 포인터 , EBP - SS 레지스터가 가리키는 스택상의 한 데이터를 가리키는 포인터


세그먼트 레지스터는 프로세스의 특정 세그먼트를 가리키는 포인터 역할을 한다. ( CS : 코드 세그먼트 , D~FS : 데이터 세그먼트 , SS : 스택 세그먼트를 가리킴 )
이렇게 세그먼트 레지스터가 가리키는 위치를 바탕으로 우리는 원하는 segment 안의 특정 데이터 , 명령어를 정확히 끄집어 낼 수 있다.


인스트럭션 포인터 레지스터는 다음 실행할 명령어가 있는 현재 code segment의 offset값을 가진다.
EIP 레지스터를 읽을 수 있는 방법은 CALL 명령어를 수행하고 나서 프로시저 스텍으로부터 리턴하는 명령어의 address를 읽는것이다.

위 내용을 알아야 buffer overflow 공격을 하는데 있어 적절한 padding 사용과 return address의 정확한 위치르 찾고 필요한 어셈블리코드를 추출하고 이해할수있다.

'Hacking & Security > System' 카테고리의 다른 글

PLT & GOT  (0) 2018.10.31
Linux 환경에서의 메모리 보호기법  (0) 2018.08.21
환경변수란 ?  (0) 2018.01.30
Buffer Overflow Basic 3  (0) 2018.01.16
Buffer Overflow Basic 2  (0) 2018.01.16