아무것도 모르는데 시스템 보안 수업 듣고 후회하며 작성하는 공부 기록...!
📚시스템보안을 위한 사전지식..?
1. 시스템의 구조
로더의 입장에서 바라본 세그먼트!! bss를 데이터 영역이라고 볼 수 도 있음 일단 따로 씀
세그먼트는 코드, 데이터, bss, stack, heap 으로 나뉨
- Text segment : 코드가 올라감 ㄹㅇ 코드
- Data segment: 초기화 된 전역변수들
- BSS : 초기화 되지않은 전역변수들
- stack : 함수, 지역변수들 ***스택은 밑으로 자라남! (높은 주소에서 낮은 주소로 자란다는 뜻, 스택에서 가장 많은 취약점이 발견됨)
- heap : 동적할당되는 변수들

참고자료
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=thechizko&logNo=20129533828
+ 교수님 강의
2. 레지스터의 종류 및 역할 정리
👀64bit 컴퓨터의 범용 레지스터 16개
: rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp, r8 ~ r15
r로 시작하는 레지스터는 64비트임. e로 시작하면 32비트 (rax -> eax)
+ 플래그 레지스터, rip(==pc 레지스터)
1. 범용 레지스터
- rax : 산술/논리 연산, *함수의 리턴값 저장, 시스템 콜 함수 호출 시 rax에 시스템콜 주소를 담아둠
- rbx : 메모리 주소 지정
- rcx : 반복문에 많이 사용
- rdx : 여분, rax와 같이 사용될 때가 많음
2. 인덱스 레지스터
- rsi : 메모리 이동하거나 비교할 때 출발주소를 가리킴
- rdi : 메모리 이동하거나 비교할 때 도착주소를 가리킴
3. 포인터 레지스터
- rsp (stack pointer) : 스택의 가장 위를 가리킴
- rbp (base pointer) : 스택의 가장 바닥
4. 플래그 레지스터
- ZF (Zero Flag) : 연산 결과가 0이면 1
- CF (Carry Flag) : 부호 없는 수의 연산 결과가 비트의 범위를 넘을 경우
- SF(Sign Flag) : 연산결과가 음수
- OF(Overflow Flag) : 부호 있는 수의 연산결과가 비트 범위를 넘을 때
이외에도 많음
5. 파라미터 전달 시 사용하는 레지스터 (리눅스 기준)
- RDI : 첫번째 인자
- RSI : 두번째 인자
- RDX : 세번째 인자
- RCX : 네번째 인자
- R8 : 다섯번째 인자
- R9 : 여섯번째 인자
- 그 이상은 스택 활용
6. 기타 등등
- rip : 앞으로 수행할 명령어의 주소 (program counter; pc 랑 같은 거인듯?)
[참고자료]
https://com24everyday.tistory.com/223
https://blog.sonagi.dev/os_day02/
+강의
3. 스택 프레임
1.
스택프레임은 함수의 호출과 함께 할당된다.
sp는 스택의 가장 위를 가리키는 값 (=rsp 레지스터)
bp는 스택의 가장 아래를 가리킴 (=rbp 레지스터)

2. 함수 프롤로그, 에필로그 과정
함수 시작 시 이전 함수의 sp값을 bp에 저장
rsp의 값을 빼주면서 스택 프레임의 크기를 늘려감(스택은 높은 주소 -> 낮은 주소로 자라기 때문에 rsp 값이 작아지면 스택이 커짐)
함수 끝나면 sp값에 bp 값을 넣음
rbp와 rsp 가 같은 위치에 있게 됨. pop rbp로 rbp에 sfp(stack frame pointer)값을 넣음
sfp는 이전 함수의 bp 값임
그 다음 pop rip로 다음에 실행해야 할 instruction 주소를 rip에 담음.
3. 함수 프롤로그 ~ 에필로그 과정 자세히 (어셈블리어 먼저 보고 오기!)






leave 는
mov rsp, rbp
pop rbp

ret 는 pop rip임

[참고자료]
dreamhack.io
https://hg2lee.tistory.com/entry/%EC%8B%9C%EC%8A%A4%ED%85%9C-Prologue-%ED%94%84%EB%A1%A4%EB%A1%9C%EA%B7%B8-%EA%B3%BC%EC%A0%95?category=1240865
http://www.tcpschool.com/c/c_memory_stackframe
4. plt와 got
[시스템] PLT 와 GOT [초급]
시스템 해킹(포너블)을 하다보면 PLT, GOT 어디선가 들어봤고, plt, got 라고 불리우는것들을 막 호출하고 변조하고 할겁니다. 이번에는 이러한 plt와 got가 뭔지에 대해 알아보도록 하겠습니다. 보통
hg2lee.tistory.com
📚어셈블리어
인텔문법 사용할 것!
👀리눅스에서 실행파일 인텔 문법 어셈블리어로 보는 법
objdump -d -M intel 실행파일이름
👀어셈블리어 기본 구조
opcode operand1 operand2
📍어셈블리어 알아보기
주석은 ; 임
✅ operand의 종류
1. 상수 : 숫자
2. 레지스터 : rax, rbx 등등
3. 메모리 : []로 둘러싸임. 앞에 크기지정자(TYPE PTR)가 추가 될 수 있음.
TYPE : QWORD(8바이트), DWORD(4), WORD(2), BYTE(1)
✅ opcode의 종류
1. 데이터 transfer 명령어
push ; 스택에 값을 넣는다.
pop ; 스택에서 값을 빼냄
mov rdi rsi ;rsi의 값을 rdi에 대입
mov QWORD PTR[rdi], rsi ; rsi의 값을 rdi가 가리키는 주소에 대입
lea rsi, [rbx+8*rcx] ; rbx+8*rcx를 rsi에 대입
2. 조작 명령어
call ; 함수호출
ret ; call로 호출된 함수 종료, 그 다음 명령줄로 이동
nop ; 아무것도 안함
jmp addr; 분기 명령어 addr로 rip를 이동시킴
je addr; 직전에 비교한 두 피연산자가 같으면 점프
jg addr; 직전에 비교한 두 피연산자 중 전자가 더 크면 점프
3. 논리 연산
; 비트연산자
and dst, src ;둘 다 1이면 1 아니면 0
or dst, src ; 둘 중 하나만 1이면 1
xor dst, src ; 서로 다른 비트면 1 같으면 0
not op ; 비트 반전
4. 산술 연산
inc op; 인자의 값을 1 증가
dec op; 인자의 값을 1 감소
add dst, src; 인자2 값을 인자1에 더함
sub dst, src; 인자2 값을 인자1에서 뺌
cmp op1 op2; 인자 1과 인자 2 비교 op1 - op2로 대소 비교
; 0일경우 zf=1, 음수일 경우 sf = 1
test op1, op2 ; op1과 op2에 and 연산을 취함 연산의 결과를 op1에 저장하지는 않음
;test 예시, 0인지 확인하는데 자주 사용
xor rax, rax ;rax가 0이됨
test rax, rax ; 연산결과 0이 나옴, zf=1
5. 프로시저, 스택
call addr ; addr에 위치한 프로시저 호출
; 프로시저를 호츨하기 위해 돌아와야 하는 return address를 push한 후 jmp addr함
leave ; 스택 프레임 정리
; mov rsp, rbp
; pop rbp
ret ; return address로 반환
; pop rip
pop reg ; 스택 최상단의 값을 reg에 담음
push val ; 스택 최상단에 쌓기
6. 시스템 콜
rax로 시스템 콜 요청 (syscall table을 통해 몇번인지 알 수 있음)
read는 0, write는 1, open은 2 등등~
execve는 0x3b
write(1, "Hello World", 11);
<registers>
rax = 0x1
rdi = 0x1 ; 첫번째 argument
rsi = hello world가 저장되어있는 주소 ; 두번째 argument
rdx = 0xb ; 세번째 argumnet
<code>
syscall
📚GDB 사용법
gdb기능 너무 많아..
https://dining-developer.tistory.com/13
gdb - 간단한 명령어/사용법/단축어 정리(cheat sheet)
GDB를 이용해 간간히 디버깅 하긴 했지만, 자주 사용하지 않아서 익숙하지 않았다. 앞으로 사용할 때마다 검색시간을 줄이기 위해 내가 사용하는/했던 gdb 명령어를 정리해놓기로 했다. 명령어를
dining-developer.tistory.com
https://bpsecblog.wordpress.com/2016/04/04/gdb_memory_2/
우리집에 GDB 있는데… 메모리 보고갈래?(2)
season 1. 우리집에 GDB 있는데… 메모리 보고 갈래?(2) Day #2. 애프터 신청 (너 gdb 사용법, 갖고싶다.. 너란 stack ) in09@ubuntu:~/bpsecblog/day2$ gcc -fno-stack-protector -o tomato tomato.c -fno-stack-protector 옵션을 포
bpsecblog.wordpress.com
1. 실행파일(elf파일) 분석하기!
- elf file의 헤더정보 출력
readelf -h 실행파일이름
Entry point addr(EP)은 진입점 : 프로그램 실행 시 이 주소부터 시작
2. gdb 명령어
set disassembly-flavor intel : 인텔문법으로 바꾸기
b 함수이름 : 함수에 breakpoint 걸기
b *주소 : 주소에 breakpoint 걸기
r (run) : 실행 argument 넣을 때는 r 옆에 쓰면 됨
disas main : main 함수 disassemble
- 한줄씩 실행
si : 한줄씩 실행 함수 만날 시 함수 내부로 들어감
ni : 함수내부로 안들어감
-특정 주소의 뭔가를 출력
x/원하는길이원하는format
format 예시
o : 8진법으로 보여줌
x : 16진법으로 보여줌
u : 10진법으로 보여줌
t : 2진법으로 보여줌
b : 1 byte 단위로
h : 2 byte
w: 4 byte
g : 8 byte 단위로
i : 역어셈블된 명령어
c : 문자
s : 문자열
예시)
x/5i $rip : rip 부터 5줄 어셈블리어
x/s 0x주소 : 주소의 값을 문자열로
x/10gx $rsp : rsp부터 8바이트 단위로 10줄 총 80바이트를 16진수로 출력
-레지스터 출력
info reg : 레지스터 정보 출력
info reg rsi : rsi 출력
📚pwntools 사용법
1. 로컬 바이너리를 대상으로 익스플로잇 할 때
from pwn import *
p = process("./test")
2. send, recv
from pwn import *
p = process('./test')
p.send('A') # ./test에 'A'를 입력
p.sendline('A') # ./test에 'A'+'\n'을 입력
p.sendafter('hello','A') # ./test가 'hello'를 출력하면, 'A'를 입력
p.sendlineafter('hello','A') # ./test가 'hello'를 출력하면, 'A' + '\n'을 입력
data = p.recv(1024) #p가 출력하는 데이터를 최대 1024바이트까지 받아서 data에 저장
data = p.recvline() #p가 출력하는 데이터를 개행문자를 만날 때까지 받아서 data에 저장
data = p.recvn(5) #p가 출력하는 데이터를 5바이트만 받아서 data에 저장
data = p.recvuntil('hello') #p가 출력하는 데이터를 'hello'가 출력될 때까지 받아서 data에 저장
data = p.recvall() #p가 출력하는 데이터를 프로세스가 종료될 받아서 data에 저장
ㅎㅋㅎㅋ...
1. 메모리 보호 기법
- Stack Canary : 스택 버퍼 오버플로 취약점을 방지하기 위한 메모리 보호 기법 중 하나임
sfp(stack frame pointer) 버퍼 사이에 임의의 데이터를 넣음
많은 공격들은 아래 그림의 ret 값을 변경하려고 함. sfp 위에 canary값을 넣어놓고 버퍼오버플로를 통해 ret 값을 조작하려 하면 canary가 변경되어 경고가 뜸

ㅎㅋㅎㅋ...ㅎㅋ.ㅎㅋㅎ..