카테고리 없음
리버싱 드림핵 4 정리
미숫가루빙수
2024. 3. 24. 20:33
어셈블리어와 x86-64
x64 어셈블리 언어의 기본 구조
- 명령어 (Operation Code, Opcode): 어셈블리 언어의 명령어는 컴퓨터가 실행할 동작을 지시한다. 이것이 어셈블리 코드의 동사에 해당한다.
- 피연산자 (Operand): 명령어가 동작을 수행하는 대상이며, 어셈블리 코드의 목적어에 해당한다.
명령 코드
데이터 이동(Data Transfer) | mov, lea |
산술 연산(Arithmetic) | inc, dec, add, sub |
논리 연산(Logical) | and, or, xor, not |
비교(Comparison) | cmp, test |
분기(Branch) | jmp, je, jg |
스택(Stack) | push, pop |
프로시져(Procedure) | call, ret, leave |
시스템 콜(System call) | syscall |
피연산자
- 상수 (Immediate Value): 명령어가 직접적으로 사용하는 값으로, 상수로 지정된다. 예를 들어, mov eax, 10에서 10은 상수이다.
- 레지스터 (Register): CPU의 레지스터에 저장된 값을 가리킨다. 레지스터는 CPU가 사용하는 임시 저장 공간으로, 데이터를 빠르게 읽고 쓸 수 있다. 예를 들어, mov eax, ebx에서 ebx는 레지스터이다.
- 메모리 (Memory): 주소로 참조되는 데이터로, RAM에 저장된 값을 가리킨다. 메모리 피연산자는 []으로 둘러싸여 표현되며, 앞에 크기 지정자(Size Directive)인 TYPE PTR이 추가될 수 있다.
메모리 피연산자
QWORD PTR [0x8048000] | 0x8048000의 데이터를 8바이트만큼 참조 |
DWORD PTR [0x8048000] | 0x8048000의 데이터를 4바이트만큼 참조 |
WORD PTR [rax] | rax가 가르키는 주소에서 데이터를 2바이트 만큼 참조 |
데이터 이동
mov dst, src : 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
and dst, src: dst와 src의 비트가 모두 1이면 1, 아니면 0
[Register] | |
eax = 0xffff0000 | |
ebx = 0xcafebabe | |
[Code] | |
and eax, ebx | |
[Result] | |
eax = 0xcafe0000 |
or dst, src: dst와 src의 비트 중 하나라도 1이면 1, 아니면 0
[Register] | |
eax = 0xffff0000 | |
ebx = 0xcafebabe | |
[Code] | |
or eax, ebx | |
[Result] | |
eax = 0xffffbabe |
논리연산🤔 - xor & not
xor dst, src: dst와 src의 비트가 서로 다르면 1, 같으면 0
[Register] | |
eax = 0xffffffff | |
ebx = 0xcafebabe | |
[Code] | |
xor eax, ebx | |
[Result] | |
eax = 0x35014541 |
not op: op의 비트 전부 반전
[Register] | |
eax = 0xffffffff | |
[Code] | |
not eax | |
[Result] | |
eax = 0x00000000 |
비교
비교 명령어는 두 피연산자의 값을 비교하고, 플래그를 설정한다.
[Code]1: mov rax, 0xA2: mov rbx, 0xA3: cmp rax, rbx ; ZF=1
분기
분기 명령어는 rip를 이동시켜 실행 흐름을 바꾼다.
[Code]1: mov rax, 0x313372: mov rbx, 0x133373: cmp rax, rbx ; rax > rbx4: jg 1 ; jump to 1
요약
- 데이터 이동 연산자
- mov dst, src: src의 값을 dst에 대입
- lea dst, src: src의 유효 주소를 dst에 대입
- 산술 연산
- add dst, src: src의 값을 dst에 더함
- sub dst, src: src의 값을 dst에서 뺌
- inc op: op의 값을 1 더함
- dec op: op의 값을 1 뺌
- 논리 연산
- and dst, src: dst와 src가 모두 1이면 1, 아니면 0
- or dst, src: dst와 src중 한 쪽이라도 1이면 1, 아니면 0
- xor dst, src: dst와 src가 다르면 1, 같으면 0
- not op: op의 비트를 모두 반전
- 비교
- cmp op1, op2: op1에서 op2를 빼고 플래그를 설정
- test op1, op2: op1과 op2에 AND 연산을 하고, 플래그를 설정
- 분기
- jmp addr: addr로 rip 이동
- je addr: 직전 비교에서 두 피연산자의 값이 같을 경우 addr로 rip 이동
- jg addr: 직전 비교에서 두 피연산자 중 전자의 값이 더 클 경우 addr로 rip 이동
프로시저
특정 기능을 수행하는 코드 조각을 말한다.
ex. call, 반환 등