study/보안

x64 어셈블리 언어 - 주요 명령어 정리 (1)

lucykorea414 2023. 9. 8. 10:37
728x90

데이터 이동

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에 대입

 

 

퀴즈!

[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. Code 1까지 실행 후 rax에 저장되는 값은?
    0xC0FFEE
  2. Code 2까지 실행 후 rax에 저장되는 값은?
    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

 

 

퀴즈!

[Register]
rax = 0x31337
rbx = 0x555555554000
rcx = 0x2
=================================
[Memory]
0x555555554000| 0x0000000000000000
0x555555554008| 0x0000000000000001
0x555555554010| 0x0000000000000003
0x555555554018| 0x0000000000000005
0x555555554020| 0x000000000003133A
==================================
[Code]
1: add rax, [rbx+rcx*8]
2: add rcx, 2
3: sub rax, [rbx+rcx*8]
4: inc rax
  1. Code 1까지 실행 후 rax에 저장된 값?
    0x3133A  (rax의 값은 rbx+0x10(0x555555554010) 에 저장된 0x3 만큼 증가합니다.)

  2. Code 3까지 실행 후 rax에 저장된 값?
    (rax의 값은 rbx+0x20에 저장된 0x3133A 만큼 감소합니다.)

  3. Code 4까지 실행 후 rax에 저장된 값?
    1  (rax의 값은 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

 

 

퀴즈!

[Register]
rax = 0xffffffff00000000
rbx = 0x00000000ffffffff
rcx = 0x123456789abcdef0
==================================
[Code]
1: and rax, rcx
2: and rbx, rcx
3: or rax, rbx
  1. Code 1까지 실행 후, rax에 저장된 값?
    0x1234567800000000

  2. Code 2까지 실행 후, rbx에 저장된 값?
    0x000000009abcdef0

  3. Code 3까지 실행 후, rax에 저장된 값?
    0x123456789abcdef0

 

 


논리 연산 - 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

 

 

퀴즈!

[Register]
rax = 0x35014541
rbx = 0xdeadbeef
==================================
[Code]
1: xor rax, rbx
2: xor rax, rbx
3: not eax
  1. Code 1까지 실행 후 rax에 저장되는 값?
    0xebacfbae

  2. Code 2까지 실행 후 rax에 저장되는 값?
    0x35014541  (xor연산을 동일한 값으로 두 번 실행할 경우, 원래 값으로 돌아감. XOR cipther 참고: https://en.wikipedia.org/wiki/XOR_cipher)

  3. Code 3까지 실행 후 rax에 저장되는 값?
    0xcafebabe  (참고로 [Code]의 3번에서 rax가 아닌 eax를 not 해도 괜찮은 이유는 eax가 rax의 하위 32비트를 가리키는 부분이기 때문. 만약 not rax를 수행했다면 답은 0xffffffffcafebabe가 됨.)

 

 

 


비교

cmp op1, op2: op1과 op2를 빼서 대소 비교 후 같으면 ZF=1 -> 완전히 같은지 판단

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를 AND 비트연산 비교 후 모두 0 이면 ZF=1 -> 모두 0인지 판단

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: 직전에 비교한 두 피연산자가 같으면 점프 (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

 

 

 


요약

  1. 데이터 이동 연산자
    • mov dst, src: src의 값을 dst에 대입
    • lea dst, src: src의 유효 주소를 dst에 대입
  2. 산술 연산
    • add dst, src: src의 값을 dst에 더함
    • sub dst, src: src의 값을 dst에서 뺌
    • inc op: op의 값을 1 더함
    • dec op: op의 값을 1 뺌
  3. 논리 연산
    • 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의 비트를 모두 반전
  4. 비교
    • cmp op1, op2: op1에서 op2를 빼고 플래그를 설정
    • test op1, op2: op1과 op2에 AND 연산을 하고, 플래그를 설정
  5. 분기
    • jmp addr: addr로 rip 이동
    • je addr: 직전 비교에서 두 피연산자의 값이 같을 경우 addr로 rip 이동
    • jg addr: 직전 비교에서 두 피연산자 중 전자의 값이 더 클 경우 addr로 rip 이동

 

728x90