x64 어셈블리 언어는 동사에 해당하는 명령어(Operation Code, Opcode)와 목적어에 해당하는 피연산자(Operand)로 구성됩니다.
명령어들을 크게 분류하면 이렇습니다.
피연산자에는 3가지 종류가 올 수 있습니다. 상수, 레지스터, 메모리입니다.
메모리 피연산자는 []으로 둘러싸인 것으로 표현됩니다. 앞에 크기 지정자인 TYPE PTR이 추가될 수 있습니다. 타입에는 BYTE, WORD, DWORD, QWORD가 올 수 있으며 각각 1, 2, 4, 8바이트의 크기를 지정합니다.
데이터 이동 명령어는 어떤 값을 레지스터나 메모리에 옮기도록 지시한다.
mov dst, src에 들어있는 값을 dst에 대입
mov rdi, rsi | rsi의 값을 rdi에 대입 |
mov QWORD PTR[rdi], rsi | rsi의 값을 rdi가 가리키는 주소에 대입 |
mov QWORD PTR[rdi+8*rcx], rsi | rsi의 값을 rdi+8*rcx가 가리키는 주소에 대입 |
lea dst, src : src의 유효 주소(Effective Address, EA)를 dst에 저장
lea rsi,[rbx+8*rcx] | rbx+8*rcx를 rsi에 대 |
산술 연산
산술 연산 명령어는 덧셉,뺄샘,곱셈,나눗셈 연산을 지시한다.
add dst, src: dst에 src의 값을 더한다.
add eax, 3 | eax += 3 |
add ax, WORD PTR[rdi] | ax += *(WORD*) rdi |
sub dst, src : dst에서 src의 값을 뺀다
sub eax, 3 | eax -= 3 |
sub ax, WORD PTR[rdi] | ax -= *(WORD *)rdi |
inc op:op의 값을 1 증가시킴
inc eax | eax += 1 |
dec op:op의 값을 1 감소시킨다
dec eax | eax -= 1 |
논리 연산 명령어는 and, or, xor, neg등의 비트 연산을 지시한다.
and dst, src | dst와 src의 비트가 모두 1이면 1, 아니면 0 |
or dst, src | dst와 src의 비트 중 하나라도 1이면 1, 아니면 0 |
xor dst, srcd | dst와 src의 비트가 서로 다르면 1,같으면 0 |
not op | op의 비트 전부 반 |
비교 명령어는 두 피연산자의 값을 비교하고, 플래그를 설정한다.
cmp op1, op2:op1과 op2를 비교한다. cmp는 두 피연산자를 빼서 대소비교를 하며 연산 결과는 op1에 대입하지 않는다.
test op: op2:op1과 op2를 비교한다. test는 두 피연산자에서 AND비트연산을 취한다. 연산의 결과는 op1에 대입하지 않는다.
분기 명령어는 rip를 이동시켜 실행 흐름을 바꾼다.
jmp addr | addr로 rip를 이동시킨다 |
je addr | 직전에 비교한 두 피연산자가 같으면 점프한다 |
jd addr | 직전에 비교한 두 연산자 중 전자가 더 크면 점프 |
push val: val을 스택 최상단에 쌓는다.
pop reg:스택 최상단의 값을 꺼내서 reg에 대입한다.
Opcode:프로시저
특정 기능을 수행하는 코드 조각을 말합니다. 프로시저를 사용하면 반복되는 연산을 프로시저 호출로 대체할 수 있어서 전체 코드의 크기를 줄일 수 있으며, 기능별로 코드 조각에 이름을 붙일 수 있게 되어 코드의 가독성을 크게 높일 수 있습니다
프로시저를 부르는 행위:호출(call)
" 돌아오는 것:반환(return)
프로시저를 호출할 때는 프로시저를 실행하고 나서 원래의 실행 흐름으로 돌아와야 한다. call 다음 명령어의 주소(return address, 반환 주소)를 스택에 저장하고 프로시저로 rip를 이동시킨다.
call addr:addr에 위치한 프로시져 호출한다.
Opcode: 시스템 콜
해킹으로부터 막강한 권한을 보호하기 위해 커널 모드와 유저 모드로 권한을 나눈다.
커널 모드: 운영체제가 전체 시스템을 제어하기 위해 시스템 소프트웨어에 부여하는 권한이다.
유저 모드: 운영체제가 사용자에게 부여하는 권한이다. 유튜브를 시청하는 것, 게임을 하고 프로그래밍을 하는 것 등은 모두 유저 모드에서 이루어진다.
시스템 콜: 유저 모드에서 커널 모드의 시스템 소프트웨어에게 어떤 동작을 요청하기 위해 사용된다. 소프트웨어 대부분은 커널의 도움이 필요하다.
Q1. 레지스터, 메모리 및 코드가 다음과 같다. Code를 1까지 실행했을 때, rax에 저장된 값은?
A. 0x4oaa40+8을 한 0xC0FFEE이다.(로드)
Q2. Code를 2까지 실행했을 때, rax에 들어있는 값은?
A. 0x4oaa40+8(저장)
Q3. 레지스터, 메모리 및 코드가 다음과 같다. Code를 1까지 실행했을 때, rax에 저장된 값은?
rbx + rcx*8 = 0x555555554000 + 0x2*8 = 0x555555554000 + 0x10 = 0x555555554010
0x555555554010의 메모리값은 0x0000000000000003
rax에 더할 시:ax3133A
Q4. Code를 3까지 실행했을 때, rax에 저장된 값은?
rbx + rcx*8와 rax가 같으므로 0이 된다.
Q5. Code를 4까지 실행했을 때, rax에 저장된 값은?
0에서 1을 증가시켰으므로 1이 된다.
Q6. 레지스터, 메모리 및 코드가 다음과 같다. Code를 1까지 실행했을 때, rax에 저장된 값은?
rax와 rcx를 각각 이진수로 바꿔서 계산합니다. 0x1234567800000000가 나옴을 알 수 있습니다.
각각 이진수로 바꿔서 계산합니다. 0x000000009ABCDEF0가 나옴을 알 수 있습니다.
Q8. Code를 3까지 실행했을 때, rax에 저장된 값은?
Q9. 레지스터, 메모리 및 코드가 다음과 같다. Code를 1까지 실행했을 때, rax에 저장된 값은?
각각 이진수로 변환하여 계산해줍니다. 0xEBACFBAE 가 나옴을 알 수 있습니다.
Q10. Code를 2까지 실행했을 때, rax에 저장된 값은?
각각 이진수로 변환하여 계산해줍니다. 0x35014541가 나옴을 알 수 있습니다.
Q11. Code를 3까지 실행했을 때, rax에 저장된 값은?
이진수로 변환합니다. 0xCAFEBABE가 나옴을 알 수 있습니다.
답:Welcome to assembly world!
gdb
설치가 된 것을 확인합니다.
entry
실행파일의 형식으로 ELF (Executable and Linkable Format)를 규정한다. ELF는 크게 헤더 와 여러 섹션 들로 구성되어 있다.
Context
실행 상황을 이와 같이 부른다. 크게 REGISTERS, DISASM, STACK, BACKTRACE으로 나뉜다.
REGISTERS: 레지스터의 상태를 보여줍니다
DISASM: rip부터 여러 줄에 걸쳐 디스어셈블된 결과를 보여줍니다
STACK: rsp부터 여러 줄에 걸쳐 스택의 값들을 보여줍니다
BACKTRACE: 현재 rip에 도달할 때까지 어떤 함수들이 중첩되어 호출됐는지 보여줍니다.
break & continue
break는 특정 주소에 중단점(breakpoint)을 설정하는 기능이고, continue는 중단된 프로그램을 계속 실행시키는 기능입니다.
run
단순히 실행만 시킵니다.
navigate
관찰하고자 하는 함수의 중단점에 도달했으면, 그 지점부터는 명령어를 한 줄씩 자세히 분석해야 한다. 이때 사용하는 명령어로 ni와 si가 있다
step into
필요한 부분으로 들어가 분석할 때 사용합니다.
finish
함수의 규모가 커서 ni로는 원래 실행 흐름으로 돌아가기 어려울 수 있습니다. 이럴 때는 finish라는 명령어를 사용하여 함수의 끝까지 한 번에 실행할 수 있습니다.
pwntools
설치를 완료합니다
process | 익스플로잇을 로컬 바이너를 대상으로 함 |
remote | 원격 서버를 대상으로 함 |
send | 데이터를 프로세스에 전 |
recv | 프로세스에서 데이터를 받 |
packing & unpacking | 어떤 값을 리틀 엔디언의 바이트 배열로 변경하거나 역의 과정 |
interactive | 셸을 획득했거나 익스플로잇의 특정 상황에 입력을 주며 출력 확 |
ELF | 익스플로잇에서 사용될 수 있는 각종 정보 기 |
context.log | 익스플로잇에 버그가 발생하면 익스플로잇도 디버깅한다 |
context.arch | 셸코드를 생성하거나, 코드를 어셈블, 디스어셈블하는 기능 등을 가지며, 이들은 공격 대상의 아키텍처에 영향을 받습니다 |
shellcraft | 공격에 필요한 셸 코드를 쉽게 꺼내 쓸 수 있게 해준다. |
asm | 어셈블 기능을 제공한다. |