Dreamhack-system

x86 Assembly : Essential Part(1)

White_Bean 2023. 1. 17. 18:32

명령코드종류

데이터 이동(Data Transfer) mov, lea
산술 연산(Arithmetic) inc, dec, add, sub
논리 연산(Logical) and, or, xor, not
비교(Comparison) cmp, test
스택(Stack) push, pop
프로시져(Procedure) call, ret, leave
시스템 콜(System call) syscall

 

x64 어셈블리 언어는 우리가 사용하는 한국어보다는 훨씬 단순하다
이들의 문장은 동사에 해당하는 명령어(Operation Code, Opcode)와 목적어에 해당하는 피연산자(Operand)로 구성된다.

피연산자

피연산자에는 총 3가지 종류가 올 수 있다.
1. 상수(Immediate Value)
2. 레지스터(Register)
3. 메모리(Memory)

메모리 피연산자는 []으로 둘러싸인 것으로 표현되며, 앞에 크기 지정자(Size Directive) TYPE PTR이 추가될 수 있다.
여기서 타입에는 BYTE(1), WORD(2), DWORD(4), QWORD(8)가 올 수 있으며, 각각 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 QWORD PTR[rdi], rsi rsi의 값을 rdi가 가리키는 주소에 대입
mov QWORD PTR[rdi+8*rcx], rsi rsi의 값을 rdi+8*rcx가 가리키는 주소에 대입



산술 연산

산술 연산 명령어는 덧셈, 뺄셈, 곱셈, 나눗셈 연산을 지시한다.

add dst, srcdst에 src의 값을 더한다.

add eax 3 eax += 3
add ax, WORD PTR[rdi] ax+=(WORD)rdi

 

sub dst,srcdst에서 src의 값을 뺀다.

sub eax, 3 eax -= 3
sub ax, WORD PTR[rdi] ax -= (WORD)rdi

 

inc opop의 값을 1 증가시킴

inc eax eax += 1

 

dec opop의 값을 1 감소 시킴

dec eax eax -= 1

 

논리 연산 - and & or & xor & not

논리 연산 명령어는 and, or, xor, neg 등의 비트 연산을 지시

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 dst, src -> dst와 src의 비트가 서로 다르면 1, 같으면 0

[Register]
eax = oxffffffff
ebx = oxcafebabe

[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 rax, 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이동
je addr : 직전 비교에서 두 피연산자의 값이 같을 경우 addr로 rip이동
jg addr : 직전 비교에서 피연산자 중 전자의 값이 더 클 경우 addr로 rip이동