일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 리눅스커널
- 리눅스
- 시스템해킹
- pwncollege
- 리눅스 커널
- C++
- 프로그래밍
- 리버싱
- pwn.college
- Pwnable.kr
- 컴퓨터구조
- C언어
- css
- 시그널
- Leviathan
- write up
- 어셈블리어
- wargame
- 커널
- kernel
- px4
- 시스템
- 시스템프로그래밍
- 취약점
- radare2
- 알고리즘
- Bandit
- 시스템 프로그래밍
- 워게임
- 드론
- Today
- Total
Computer Security
#2 어셈블리어 연산,비교,분기 본문
코드 <--> 어셈블리어 <--> 기계어
위와 같이 어셈블리어는 우리가 친 코드를 기계어로 치환해주는 역할을 수행한다.
어셈블리어는 명령어(Operation Code,Opcode)와 목적어에 해당하는 피연산자(Operand)로 구성된다.
인텔x64매우 많은 명령어가 존재하는데,
중요한 21개의 명령어를 살펴보자.
데이터 이동(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
피연산자에는 총 3가지 종류가 올 수있다.
1.상수(Immediate Value)
2.레지스터(Register)
3.메모리(Memory)
메모리 피연산자는 []로 둘러싸인 것으로 표현되고, 앞에 크기 지정자(Size Directive) TYPE PTR이 추가될 수 있다.
타입에는 BYTE, WORD, DWORD, QWORD가 올 수있으며, 각각 1바이트, 2바이트, 4바이트, 8바이트 크기를 지정한다.
메모리 피연산자 예시)
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 QWRD PTR[rdi],rsi : rsi의 값을 rdi가 가리키는 주소에 대입
mov QWRD 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에 대입
코드예시
[Register]
rbx = 0x401A40
=================================
[Memory]
0x401a40 | 0x0000000012345678
0x401a48 | 0x0000000000C0FFEE
0x401a50 | 0x00000000DEADBEEF
0x401a58 | 0x00000000CAFEBABE
0x401a60 | 0x0000000087654321
=================================
[Code]
1: mov rax, [rbx+8]
2: lea rax, [rbx+8]
위를 보면
1번: "값"을 대입 하는 것이기 때문에, rbx+8 같은경우 0x401a40 에서 +8 인 0x401a48의 값을
넣어주므로, 답은 : 0x0000000000C0FFEE 이 된다.
2번: "주소"를 대입 하는 것이기 때문에, 0x401A40 에서 8을 더한 0x401A48이 그대로 대입된다.
산술 연산
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¬
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
비교
비교 명령어는 두 피연산자의 값을 비교하고, 플래그를 설정한다.
cmp op1, op2: op1과 op2를 비교
cmp는 두 피연산자를 빼서 대소를 비교한다.
연산의 결과는 op1에 대입하지 않는다.
예를 들어, 서로 같은 두 수를 빼면 결과가 0이 되어 ZF플래그가 설정되는데, 이후에 CPU는 이 플래그를 보고 두 값이 같았는지 판단할 수 있다.
[Code]
1: mov rax, 0xA
2: mov rbx, 0xA
3: cmp rax, rbx ; ZF=1
test op1, op2: op1과 op2를 비교
test는 두 피연산자에 AND 비트연산을 취한다.
연산의 결과는 op1에 대입하지 않는다.
예를 들어, 아래 코드에서 처럼 0이된 rax를 op1과 op2로 삼아 test를 수행하면, 결과가 0이므로 ZF플래그가 설정된다.
이후에 CPU는 이 플래그를 보고 rax가 0이었는지 판단할 수 있다.
[Code]
1: xor rax, rax
2: test rax, rax ; ZF=1
분기
분기 명령어는 rip를 이동시켜 실행 흐름을 바꾼다.
jmp addr: addr로 rip를 이동시킨다.
[Code]
1: xor rax, rax
2: jmp 1 ; jump to 1
je addr : 직전에 비교한 두 피연산자가 같으면 점프한다.
[Code]
1: mov rax, 0xcafebabe
2: mov rbx, 0xcafebabe
3: cmp rax, rbx ; rax == rbx
4: je 1 ; jump to 1
jg addr: 직전에 비교한 두 연산자 중 전자가 더 크면 점프한다.
[Code]
1: mov rax, 0x31337
2: mov rbx, 0x13337
3: cmp rax, rbx ; rax > rbx
4: jg 1 ; jump to 1
'컴퓨터구조&어셈블리어' 카테고리의 다른 글
#6 컴퓨터구조와 명령어 (0) | 2022.05.16 |
---|---|
#5 컴퓨터 구조2 (0) | 2022.05.15 |
#4 컴퓨터 구조1 (0) | 2022.05.14 |
#3 어셈블리어 스택 (0) | 2022.05.13 |
#1 프로세스의 메모리 구조. 세그먼트(Segment) (0) | 2022.05.11 |