촉촉한초코칩

시스템 스터디 정리 본문

Study/System

시스템 스터디 정리

햄친구베이컨 2024. 3. 17. 20:15

ISA (Instruction Set Architecture, 명령어 집합 구조)

  • CPU가 처리할 수 있는 명령어 집합
  • CPU를 만들 때 특정 ISA를 기반으로 제작한다. 

 

ISA x86-64 아키텍서 레지스터

- 크기 : 8바이트 (64비트)

1) 범용 레지스터

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

2) 세그먼트 레지스터 (크기 : 16비트)

이름 주용도
cs 코드 영역
ss 스택 메모리 영역
ds 데이터 영역
es 범용
fs 범용
gs 범용

3) 명령어 포인터 레지스터

  • rip (instruction pointer) : 크기 8바이트, CPU가 어느 부분의 코드를 실행할 지 가리킨다.

플래그 레지스터 (RFLAGS)

  • 크기 : 64비트
  • 한 플래그의 크기 : 1비트
플래그 의미
CF(Carry Flag) 부호 없는 수의 연산 결과가 비트의 범위를 넘을 경우 설정
ZF(Zero Flag) 연산의 결과가 0일 경우 설정
SF(Sign Flag) 연산의 결과가 음수일 경우 설정
OF(Overflow Flag) 부호 있는 수의 연산 결과가 비트 범위를 넘을 경우 설정

* 64비트 : rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp
* 32비트(하위 32비트) : eax, ebx, ecx, edx, esi, edi, esp, ebp
* 16비트(하위 16비트) : ax, bx, dx, si, di, sp, bp
* 다시 상/하위 8비트로 나뉜다.

ex) rax = 0x0123456789abcdef 일 때, eax의 값은?
eax = 0x89abcdef

ex) rax = 0x0123456789abcdef 일 때, ax의 값은?
ax = 0xcdef

 

세그먼트

  • 적재되는 메모리의 용도별로 메모리 구획을 나눈다.
  • 세그먼트마다 CPU의 권한이 다르다. 
  • 권한 : read, write, execute

 

 

 

 

세그먼트 역할 일반적인 권한 사용 예시
코드 세그먼트 실행 가능한 코드가 저장된 영역 읽기, 실행 main() 등의 함수 코드
데이터 세그먼트 초기화된 전역 변수 또는 상수가 위치하는 영역 읽기와 쓰기 또는 읽기 전용 초기화된 전역 변수, 전역 상수
BSS 세그먼트 초기화되지 않은 데이터가 위치하는 영역 읽기, 쓰기 초기화되지 않은 전역 변수
스택 세그먼트 임시 변수가 저장되는 영역 읽기, 쓰기 지역 변수, 함수의 인자 등
힙 세그먼트 실행중에 동적으로 사용되는영역 읽기, 쓰기 malloc, calloc() 등으로 할당 받은 메모리

* 읽기 전용 데이터(rodata) : 초기화된 전역 변수의 값? (상수, 상수형 문자열, printf의 중괄호 부분 등)

 

x64 어셈블리어 주요 명령어

데이터 이동 (Data Transfer) mov, lea 
ex) lea dst, src : src의 유효 주소 (Effective Address, EA)를 dst에 저장한다. 
산술 연산 (Arithmetic) inc, dec, add, sub
논리 연산 (Logical) and, or, xor, not
ex) xor dst, src : dst와 src의 비트가 서로 다르면 1, 같으면 0
ex) not op : op 비트 전부 반전
비교 (Comparison) cmp, test (두 피연산자에 AND 비트 연산을 취한다.) 
> 연산 후 플래그를 보고 판
분기 (Branch) jmp, je(Jump if equal), jg(Jump if greater, 직전에 비교한 두 연산자 중 전자가 더 크면 점프)
스택 (Stack) push (피연산자를 스택 최상단에 쌓는다)
pop (스택 최상단의 값을 꺼내서 피연산자에대입한다.) 
프로시져 (Procedure)
: 특정 기능을 수행하는 코드 조각 
반복되는 연산을 프로시저 호출로 대체하여 전체 코드 크기를 줄이고, 기능별로 코드 조각에 이름을 붙일 수 있게 되어 코드의 가독성을 크게 높일 수 있게 된다. 
call : 프로시저 부르는 행위 / return : 프로시저에서 돌아오는 행위 (반환)
> 프리시저 실행 후 원래의 실행 흐름으로 돌아와야 하므로 call 다음의 명령어 주소르 스택에 저장하고 프로시저로 rip을 이동시킨다. 


ret : return address로 반환



leave : 스택 프레임 정리 
시스템 콜 (System call) 리눅스 계층 : 커널 모드 / 사용자 모드 / 시스템 콜
syscall : 유저모드에서 커널 모드의 시스템 소프트웨어에게 어떤 동작을 요청할 때 사용

 

* 스택 연산

  • 스택 : 높은 주소에서 낮은 주소로 자란다. 
  • rsp 에서 어떤 값을 뺀다 : 주소 공간 마련
  • rsp 에서 어떤 값을 더한다 : 주소 공간 비움 

 

* 스택 프레임 : 특정 함수가 사용하는 스택 영역 

 

* x64 syscall 테이블

syscall rax arg0 (rdi) arg1 (rsi) arg2 (rdx)
read 0x00 unsigned int fd char *buf size_t count
write 0x01 unsigned int fd const char *buf size_t count
open 0x02 const char *filename int flags umode_t mode
close 0x03 unsigned int fd    
mprotect  0x0a unsigned long start size_t len unsigned long prot
connect 0x2a int sockfd struct sockaddr * addr int addrlen
execve 0x3b const char *filename const char *const *argv const char *const *envp

 

x64 어셈블리어의 피연산자

  • 피연산자 종류 : 상수, 레지스터, 메모리
  • 메모리 피연산자 표현법 : TYPE PTR [주소값 또는 레지스터]
    • Byte - 1 byte
    • Word - 2 bytes
    • Dword - 4 bytes
    • Qword - 8 bytes
메모리 피연산자  
QWORD PTR [0x8048000] 0x8048000의 데이터를
8바이트 만큼 참조
DWORD PTR [0x8048000] 0x8048000의 데이터를
4바이트 만큼 참조
WORD PTR [rax]  rax가 가리키는 주소에서 
데이터를 2바이트 만큼 참조 

 

* 참고) https://cnu-cse-pgs.tistory.com/9, https://streetdeveloper.tistory.com/95

rcx * 8 = 10 (16진수)

rbx + rcx = 0x555555554010 = 0x00...03

rax = rax + rbx = 0x31337 + 0x00...03 = 3133A

 

Code 2 rcx : 4

rbx + rcx * 8 = 0x555555554010 + 4 * 8  = 0x555555554020 (0x00...3133A)

rax = rax - 0x000000000003133A = 0 (Code 1에서 계산한 rax 값이 3133A이므로)

 

gdb : 리눅스 디버거

pwndbg

  • gdp의 플러그인
  • 바이너리 분석 용도
  • entry(ELF 파일에서 프로그램이 실행되는 시작점), context(프로그램이 실행되고 있는 맥락), break&continue, start, run, disassemble(함수 전체를 어셈블리 코드로 보여준다.), navigate(다음 명령어로 rip 이동), examine(특정 주소에서 원하느 길이만큼의 데이터 인코딩해서 보기), telescope(메모리가 참조하고 있는 주소를 재귀적으로 탐색하여 값을 보여줌), vmmap(가상 메모리의 레이아웃, 어떤 파일이 매핑 된 영역일 경우, 해당 파일의 경로까지 보여준다.)

pwntools 

  • 파이썬 모듈
  • 익스플로잇할 때 자주 구현하게 되는 기능들을 파이썬 모듈로 만들어 제공
  • pwntools API 함수 : process(로컬 바이너리 테스트, 디버깅용), remote(원격 서버 실제 공격용),send(데이터 보내기), revc(데이터 받기), packing&unpacking(바이트배열을 리틀앤디언으로 변경 혹은 반대), interactive(터미널에서 프로세스에 데이터 입출력하기), ELF(헤더에 기록된 각종 정보 보기), asm(주어진 코드를 기계어로 어셈블) 
  • 객체 : context.log (디버깅의 편의를 돕는 로그 기능), context.arch(공격 대상의 아키텍처 정보 설정), shellcraft (자주 사용되는 셀코드를 모아놓은 객체)

 

Bomb Lab

  • 폭탄을 터뜨리지 않고 안전하게 해체한다. 
  • 6가지 phase 함수가 있으며 각 phase마다 read_line(사용자 입력값받음), phase(입력값 검증), phase_defused(폭탄해체)가 반복된다. 

 

Calling Convention 함수 호출 규약

  • 함수의 호출 및 반환에 대한 규약
  • Caller(호출자), Callee(피호출자)
  • 호출 시 Caller 상태 저장 > return address 저장 > callee가 요구하는 인자(rdi, rsi, rdx, rcx, r8, r9, 더 많은 인자 사용해야 할 때는 스택 사용) 전달
  • 반환 시 Callee의 return 값 저장
  • x86-64아키텍처용 함수 호출 규약 : system v(sysv)
    > 인자 전달, 반환 주소 저장, (Caller의) 스택 프레임 저장, (Callee에게) 스택 프레임 할당, 반환값 전달, 반환 
  • x86아키텍처용 함수 호출 규약 : cdecl
    마지막 인자부터 첫번째 인자까지 거꾸로 스택에 push

 

Stack Overflow

  • 스택 영역 자체가 넘친 것

Stack Buffer Overflow

Stack Buffer Overflow 취약점이 있는 함수들

'Study > System' 카테고리의 다른 글

[Dreamhack] basic_exploitation_001  (0) 2024.03.31
[Dreamhack] basic_exploitation_000  (0) 2024.03.31
[Dreamhack] Return Address Overwrite  (1) 2024.03.31
Bomb Lab Phase 1-3  (0) 2024.03.24
[DreamHack] Quiz: x86 Assembly 2, Quiz: x86 Assembly 3  (0) 2024.03.17