경희대학교 장대희 교수님의 소프트웨어보안 수업을 기반으로 정리한 글입니다.
프로세스 구조
프로그램: 다운로드 받아 디스크에 저장되는 파일 (if 윈도우, 더블 클릭 해서 실행하는 것)
프로세스: 실행 중인 프로그램
프로그램을 런타임으로 실행하면 디스크에 있던 프로그램의 데이터들의 OS의 도움을 받아 메모리에 올라가 프로세스가 된다.
때문에, 프로그램을 실행해 주기 위해선 다양한 메모리 영역이 확보되어야 한다. (e.g., 코드, 데이터, 스택 영역)

프로세스는 자신만의 가상 메모리 주소 공간을 갖게 되고, 그 그상 메모리 주소 공간의 레이아웃이 통상 위와 같이 나뉘어진다.
※ 파이썬의 경우, 작성한 코드가 메모리를 어떻게 사용할지는 파이썬 인터프리터라는 다른 계층이 알아서 복잡하게 처리하기에 실제적으로 관여하기가 어렵다. 때문에, 프로세스가 사용하는 메모리 영역을 관찰 및 분석하려면 C 언어로 빌드한 결과인 exe 파일 같은 리눅스에서 바로 실행할 수 있는 바이너리 파일을 IDA, GDB 등의 디버깅 도구로 분석해야 한다.
Example) vars.c



메모리 할당 및 관리
메모리 할당 함수: malloc, calloc, realloc


Example)

구조체 배열을 위한 메모리 할당


stud1.c


메모리 관리 함수


memset: "1바이트 = 8비트", memset에서 255로 초기화하면 모든 비트를 1로 세팅하는 효과가 난다.
memcmp: 문자열이 아닌 메모리 바이트 비교 시 사용한다. (e.g., 암호키 일치 여부 판단)
Example)
mem.c

BOF 유발 함수: gets

gets 함수는 메모리 버퍼의 시작 위치를 받고, 키보드 or standard input으로부터 enter에 해당하는 바이트가 들어올 때까지 바이트를 계속 받아 메모리의 한 바이트씩 채워 나간다. 때문에 BOF를 유발할 수도 있고, 스크립트로 이상한 데이터를 줘서 값을 조작할 수 있기에 현재는 사용 불가한 함수이다.
x86 Basics
x86이란 가장 대중적으로 사용하는 인텔 CPU 또는 AMD CPU의 아키텍처이다.

※ register: CPU가 access 할 수 있는 가장 빠르고 작은 저장 장치로, CPU 자체에 내장된 초소형 임시 저장 공간이다.
Stack Frame Layout (x86)
stack framem은 함수마다 존재한다.

일반적인 프로그램 동작 시, 함수가 독립적으로 동작하기에 스택 프레임이 쌓였다가 없어졌다를 반복한다.
하지만, 재귀함수를 과하게 호출하면, 계속 중첩되어 쌓이다 프로그램이 터져 버린다.
※ Heap은 bin 같은 단위를 통해 관리된다.
실습: GDB 사용
1. disas main

main 함수의 어셈블리 코드 확인

2. 브레이크포인트 걸기
breakpoint: 디버깅을 일시정지하는 지점, 이때 breakpoint는 함수 명 또는 주소 값으로 설정 가능
- b main: main 함수 시작 지점에 bp 설정
- info breakpoint: 브레이크포인트 걸어 둔 목록
- delete [Num]: 해당 브레이크포인트 삭제

디버깅을 하려면 프로그램을 일시정지 하는 게 중요하기에, bp를 특정 시점에 걸어놓고 디버깅 해야 한다.
이때, bp를 건다는 것은 특정 어셈블리 코드가 실행되기 직전에 멈추도록 지정하는 것이다. (어셈블리 코드의 메모리 위치에 bp)
3. 실행 및 single step 해보기
- run: 설정해둔 breakpoint까지 실행 후 일시정지
- si (stepi): 코드 한 줄 실행, 함수를 만나면 함수 안으로 진입
- ni (nexti): 코드 한 줄 실행, 함수 내부로 진입하지 않음
- p (print) [함수명]: 해당 함수의 주소 출력

4. info register로 레지스터 값 확인해보기
- info reg: 레지스터 전체 정보 출력
- p $[레지스터명]: 특정 레지스터 정보 출력 (e.g., p $rip, p $rdi)

5. continue로 프로그램 끝까지 실행
- c (continuing): 브레이크 포인트가 여러 개인 경우, 다음 bp까지 실행
- q (quit): gdb 종료
- k (kill): 디버깅되고 있는 프로그램 종료

⭐ 실습: 메모리 덤프하기
덤프(dump): 메모리의 내용을 그대로 꺼내서 보여주는 것
x/[포맷] [주소]: 주소에 해당하는 메모리 덤프
- x/10gx 0x400100 -> 주소 0x400100부터 10개의 8바이트(64비트) 값을 16진수로 출력
- x/20gx $rdi -> 레지스터 $rdi가 가리키는 주소부터 20개의 8바이트 값을 16진수로 출력
- x/s $rsi -> 레지스터 $rsi가 가리키는 주소에서 문자열 출력
- x/s 0x602000 -> 주소 0x602000에서 문자열 출력
- x/10i $pc -> 프로그램 카운터 $pc부터 10개의 어셈블리 명령어 출력



⭐ Endiannes (엔디안)
메모리 안에 있는 바이트들을 해석하는 두 가지 방법을 의미한다.
예를 들어, 32 bits (4 bytes) 변수가 메모리 안에 저장되어 있을 때, 이를 해석하는 방법이 두 가지가 있다.
- 리틀엔디안: 낮은 주소에 낮은 바이트값
- 빅엔디안: 낮은 주소에 높은 자리수의 바이트가 채워짐

어셈블리
명령어
데이터 이동 명령어

산술 연산 명령어

비트 연산 명령어

제어 명령어
: 프로그램의 흐름을 제어하는 명령어
- cmp: 뺄셈 연산을 해보고 플래그 결정
- test: AND 연산을 수행해보고 플래그 설정

분기 명령어
: 프로그램의 흐름 전환을 결정 (e.g., if, for, while)
- jmp [address]]: 무조건 해당 주소로 옮겨 감
- jcc [address]: 조건부 코드(cc)에 따라 해당 주소로 옮겨 감
⭐ 레지스터

x86 범용 레지스터

x86 특수 레지스터

프로그램 카운터

기본명령: MOV

참고자료
엔디안이란?(빅엔디안, 리틀엔디안)
안녕하세요 오늘은 엔디안에 대해 알아보겠습니다.엔디안이란 데이터에 여러 바이트가 있는 경우 바이트 순서를 정하는 규칙입니다.빅 엔디안(big endian)과 리틀 엔디안(little endian)두가지 방법이
wowon.tistory.com
'CS > 소프트웨어보안' 카테고리의 다른 글
| 5-1. 소프트웨어 보안을 위한 리눅스 기초 (0) | 2025.10.17 |
|---|---|
| 4-3. 어셈블리 실습 (0) | 2025.10.17 |
| 4-2. GDB 실습 (0) | 2025.10.15 |
| 3. IDA 활용 및 리버싱 방법 (0) | 2025.10.13 |
| 1. 소프트웨어 보안이슈 소개 (0) | 2025.10.12 |