본문 바로가기

모의해킹/시스템 해킹

시스템 해킹 기본 지식

728x90

• 프로세스의 메모리 구조

프로세스의 메모리를 5가지의 세그먼트로 구분하고, 운영체제가 메모리를 용도별로 나누며 각 용도에 맞게 적절한 권한을 부여한다(읽기, 쓰기, 실행) -> CPU가 메모리에 대해 권한이 부여된 행위만 할 수 있다.

1. 코드 세그먼트

- 실행 가능한 기계 코드가 위치하는 영역으로 텍스트 세그먼트라고 불린다.

- 프로그램이 동작하려면 코드를 실행(읽기, 실행 권한) => 쓰기 권한은 공격자가 악의적인 코드를 삽입하기가 쉬워져 제거한다

- main() 등의 함수 코드

 

2. 데이터 세그먼트

- 컴파일 시점에 값이 정해진 전역 변수 및 전역 상수들이 위치한다.

- CPU가 데이터 세그먼트를 읽을 수 있어야 하므로, 읽기 권한이 부여된다.

- data 세그먼트 : 전역 변수와 같이 프로그램이 실행되면서 값이 별할 수 있는 데이터

- rodata 세그먼트 : 프로그램이 실행되면서 값이 변하면 안 되는 데이터

 

3. BSS 세그먼트

- 컴파일 시점에 값이 정해지지 않은 전역 변수가 위치한 메모리

- 프로그램이 시작될 때, 모두 0으로 값이 초기화

- 보통 개발자가 선언만 하고 초기화하지 않은 전역 변수 등 포함

- 읽기 및 쓰기 권한이 부여

 

4. 힙 세그먼트

- 실해중에 동적으로 할당될 수 있으며, 리눅스에서는 스택 세그먼트와 반대 방향으로 기존 주소보다 높은 주소로 확장된다.

- C언어에서 malloc(), calloc() 등을 호출해서 할당 받는 메모리가 힙 세그먼트에 위치하게 되고, 일반적으로 읽기와 쓰기 권한이 부여된다.

 

 

5. 스택 세그먼트 

- 프로세스의 스택이 위치하는 영역(함수의 인자나 지역 변수와 같은 임시 변수들이 실행중에 저장되는 영역)

- 스택 프레임 단위로 사용

- 운영체제는 프로세스를 시작할 때 작은 크기의 스택 세그먼트를 먼저 할당해 주고, 부족해질 때마다 이를 확장한다.(기존 주소보다 낮은 주소로 확장된다)

 

 

* 힙과 스택 세그먼트가 자라는 방향이 반대인 이유

- 기존의 힙 세그먼트를 모두 사용하고 나면, 이를 확장하는 과정에서 스텍 세그먼트와 충돌하게 된다.

 

#include <stdlib.h>

int a = 0xa; //a은 데이터 세그먼트
const char b[] = "d_str";  // b와 d_str은 rodata 세그먼트
int c;  // BSS 세그먼트
int foo(int arg) {  //foo 는 코드 세그먼트
  int d = 0xd;  //d은 스택 세그먼트
  retrun 0;
}
int main()
{
   int *e = malloc(sizeof(*e));  //e는 힙 세그먼트
   return 0;
}

 

• 컴퓨터 구조

1. 폰 노이만 구조

컴퓨터에 연산, 제어, 저장의 세 사지 핵심 기능이 필요하다. 연산과 제어를 위한 중앙처리장치(CPU), 저장을 위해 기억 장치(memory)를 사용한다. 장치 간에 데이터나 제어 신호를 교환할 수 있도록 버스(bus)라는 전자 통로를 사용한다.

- 중앙처리장치

프로세스의 코들르 불러오고, 실행하고, 결과를 저장하는 일련의 모든 과정이 일어나는 곳

산술논리장치와 cpu를 제어하는 제어장치, 데이터를 저장하는 레지스터 등으로 구성되어 있다.

 

- 기억장치

컴퓨터가 동작하는데 필요한 여러 데이터를 저장하기 위해 사용되며 용도에 따라 주기억장치와 보조기억장치로 분류된다.

주기억장치는 프로그램 실행과정에서 필요한 데이터들을 임시로 저장하기 위해 사용 -> 램(RAM)

보조기억장치는 운영체제, 프로그램 등과 같은 데이터를 장기간 보관하고자 할 때 사용 -> 하드 드라이브(HDD), SSD

 

- 버스

데이터가 이동하는 데이터 버스, 주소를 지정하는 주소 버스, 읽기/쓰기를 제어하는 제어 버스가 있다.

랜선이나 데이터 전송 소프트웨어, 프로토콜 등도 버스라고 불린다.

 

* CPU안에 레지스터가 필요한 이유

필요한 데이터를 빠르게 공급하고, 반출할 수 있어야 자신의 효율을 제대로 발휘할 수 있다. CPU는 교환속도를 획기적으로 단축하기 위해 레지스터와 캐시라는 저장장치를 내부에 갖고 있습니다.

 

• x86-64 아키텍처

- 인텔의 64비트 CPU 아키텍처이다.

- 레지스터는 CPU가 데이터를 빠르게 저장하고 사용할 때 이용하는 보관소이며, 산술 연산에 필요한 데이터를 저장하거나 주소를 지정하고 참조하는 등 다양한 용도로 사용한다.

1. 범용 레지스터 

- 8바이트를 저장할 수 있으며, 부호 없는 정수를 기준으로 2^64-1까지의 수를 나타낼 수 있다.

이름 주용도
rax (accumulator register) 함수의 반환 값
rbx (base register) x64에서는 주된 용도 없음
rcx (counter register) 반복문의 반복 횟수, 각종 연산의 시행 횟수
rsi (source index) 데이터를 옮길 때 원본을 가리키는 포인터
rdi (destination index) 데이터를 옮길 때 목적지를 가리키는 포인터
rsp (stack pointer) 사용중인 스택의 위치를 가리키는 포인터
rbp (stack base pointer) 스택의 바닥을 가리키는 포인터

 

2. 세그먼트 레지스터

- cs, ss, ds, es, fs, gs 총 6가지 세그먼트 레지스터가 존재하며, 레지스터의 크기는 16비트이다.

- cs, ds, ss 레지스터는 코드 영역과 데이터,스택 메모리 영역을 가리킬 때 사용되고 나머지는 레지스터 운영체제 별로 용도를 결정할 수 있도록 범용적인 용도로 제작된 세그먼트 레지스터이다.

 

3. 명령어 포인트, 레지스터

- CPU가 어느 부분의 코드를 실핼할지 가리키는 레지스터이다.

- rip 아키텍처의 명령어이며, 크기는 8바이트이다.

 

4. 플래그 레지스터

- 프로세스의 현재 상태를 저장하고 있는 레지스터이다.

- RFLAGS라고 불리며 64비트 크기의 플래그 레지스터가 존재한다.

- 자신을 구성하는 여러 비트들로 CPU의 현재 상태를 표현한다.

- 최대 64비트이므로 최대 64개의 플래그를 사용할 수 있지만, 실제로는 오른쪽의 20여 개의 비트만 사용한다.

플래그 의미
CF (Carry Flag) 부호 없는 수의 연산 결과가 비트의 범위를 넘을 경우 설정 됩니다.
ZF (Zero Flag) 연산의 결과가 0일 경우 설정 됩니다.
SF (Sign Flag) 연산의 결과가 음수일 경우 설정됩니다.
OF (Overflow Flag) 부호 있는 수의 연산 결과가 비트 범위를 넘을 경우 설정 됩니다.

 

rax는 64비트 기준
eax는 32비트
ax는 16비트
ah, al는 8비트
ah(high)는 ax의 상위 8비트
al(low)는 ax의 하위 8비트

// 한문자에 4비트 이다.
rax: 0x0123456789abcdef   // 64비트 기준
eax:         0x89abcdef   // 32비트
ax :             0xcdef   // 16비트
ah :             0xcd     //상위 8비트
al :               0xef   // 하위 8비트

 

'모의해킹 > 시스템 해킹' 카테고리의 다른 글

shell_basic  (0) 2023.12.09
Welcome  (0) 2023.12.09
qemu & gdb 세팅  (0) 2023.05.30
리눅스 커널 & 파일 시스템 빌드  (0) 2023.05.29
리눅스 커널 해킹 (배경 지식)  (0) 2023.05.27