In Computer/Dreamhack

[Hack] 어셈블리어와 x86-64 Part.1

팽이리 2023. 4. 8. 20:41

어셈블리어 | Assembly Language

컴퓨터의 기계어와 치환되는 언어

명령어(Opcode)와 피연산자(Operand)로 구성된다.

명령어(Opcode)

x64의 중요한 21개의 명령어

명령 코드
데이터 이동(Data Transfer) mov, lea
산술 연산(Arithmetic) inc, dec, add, sub
논리 연산(Logical) and, or, xor, not
비교(Conmparison) cmp, test
분기(Branch) jmp, je, jg
스택(Stack) push, pop
프로시져(Procedure) call, ret, leave
시스템 콜(System call) syscall

피연산자(Operand)

피연산자에는 총 3가지 종유가 올 수 있다.

상수(Immediate Value)

레지스터(Register)

메모리(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 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에 대입

*mov는 주소의 값을 대입, lea는 주소를 저장 하는 것

산술 연산

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 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 = 0xffffffff
ebx = 0xcafebabe

[Code]
xor eax, ebx

[Result]
eax = 0x35014541

*xor연산을 동일한 값으로 두 번 실행할 경우, 원래 값으로 돌아갑니다.

not op: op의 비트 전부 반전

[Register]
eax = 0xffffffff

[Code]
not eax

[Result]
eax = 0x00000000

비교

두 피연산자 값을 비교하고, 플래그를 설정한다.

cmp op1, op2: op1과 op2를 비교

[Code]
1: mov rax, 0xA
2: mov rbx, 0xA
3: cmp rax, rbx ; ZF=1

test op1, op2: op1과 op2를 비교

[Code]
1: xor rax, rax
2: test rax, rax ; ZF=1

분기

분기 명령어는 rip를 이동시켜 실행 흐름을 바꾼다.

jmp addr: addr로 rip를 이동시킵니다.jmp addr: addr로 rip를 이동시킵니다.

[Code]
1: xor rax, rax
2: jmp 1 ; jump to 1

je addr: 직전에 비교한 두 피연산자가 같으면 점프 (jump if equal)

[Code]
1: mov rax, 0xcafebabe
2: mov rbx, 0xcafebabe
3: cmp rax, rbx ; rax == rbx
4: je 1 ; jump to 1

jg addr: 직전에 비교한 두 연산자 중 전자가 더 크면 점프 (jump if greater)

[Code]
1: mov rax, 0x31337
2: mov rbx, 0x13337
3: cmp rax, rbx ; rax > rbx
4: jg 1  ; jump to 1