본문 바로가기

리버싱

[리버싱]X86 Assembly

X64 어셈블리 언어

기본구조는 명령어와 피연산자로 구성됩니다

ex)

move eax, 3

여기서 move가 명령어, eax와 3가 각각 피연산자1, 2 입니다.

 move는 피연산자1에 피연산자2의 값을 대입하라는 명령어입니다.

 

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

메모리 피연산자는 []로 둘러싸인 것으로 표현되며 앞에 크기 지정자(Size Directive) TYPE PTR이 추가될 수 있습니다.

 

타입의 종류

BYTE 1바이트
WORD 2바이트
DWORD 4바이트
QWORD 8바이트

 

 

 

 

 

 

X86-64 어셈블리 명령어

데이터 이동

move dst, src src의 값을 dst에 옮김
lea dst, src src의 유효주소를 dst에 저장

 

 

산술연산

add 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 두 피연산자를 빼서 대소를 비교
test op1, op2 두 피연산자에 AND 비트 연산을 취하여 op1과 op2를 비교

두 방식 다 연산의 결과가 op1에 대입되지는 않습니다.

 

 

분기

jmp addr addr로 rip을 이동시
je addr 직전에 비교한 두 연산자가 같으면 점프
jg addr 직전에 비교한 두 연산자 중 전자가 더 크면 점프

여기서 rip이란 현재 명령을 실행하고 있는 주소를 말합니다.

 

 

스택

push val val을 스택 최상단에 쌓음 rsp -= 8
[rsp] = val
 pop reg 스택 최상단의 값을 꺼내서 reg에 대입 rsp += 8
reg = [rsp-8]

 

프로시저

프로시저(procedure)란 특정 기능을 수행하는 코드조각을 말합니다.

이를 이용해 반복되는 연산을 프로시저 호출로 대체할 수 있습니다.

call addr addr에 위치한 프로시저 호 push return_address
jmp addr
leave  스택프레임 정리 mov rsp, rbp
pop rbp
ret return address로 반환 pop rip