물먹는산세베리아

어셈블리 명령어 모음 본문

Waregame & CTF/Reversing

어셈블리 명령어 모음

suntall 2021. 9. 26. 02:03

1. 데이터 이동

MOV : 데이터복사

MOV 목적지, 소스 소스 내용을 목적지에 복사
MOV EAX, ECX

MOVZX : 0확장하여 데이터 복사

MOVZX 목적지(32bits/16bits), 소스(16bits/8bits) 소스 목적지에 복사, 목적지 남은 부분은 0으로 채우기
MOVZX EAX, CX
연산 전: EAX(89ABCDEF), ECX(12345678)
연산 후: EAX(00005678), ECX(12345678)

* 목적지가 32bits면 소스는 16 bits, 목적지가 16bits면 소스는 8bits 레지스터가 옴

* CX는 ECX 레지스터의 하위 16비트 값(즉, 5678)을 의미한다.

MOVSX : 부호 확장하여 데이터 복사

MOVSX 목적지(32bits/16bits), 소스(16bits/8bits) 소스 목적지에 복사, 목적지의 남은 부분은 소스의 맨 처음 비트로 채움
MOVSX EAX, CX
연산 전: EAX(89ABCDEF), ECX(12345678)
연산 후: EAX(00005678), ECX(12345678)

CX는 '5678', 바이너리로 변환하면 '0101 0110 0111 1000'이므로 최상의 1비트는 0

LEA : 주소 복사

LEA 목적지(only 레지스터), 소스 소스의 주소를 목적지로 복사
LEA EAX, [ESP-4]
연산 전: EAX(89ABCDEF), ESP(0018FF88)
연산 후: EAX(0018FF84), ECX(0018FF88)

* mov, lea 차이

mov는 좌변에 우변(혹은 상수)의 입력, 주소가 가리키는 데이터가 레지스터에 들어감
예) mov eax, dword ptr ss:[ebp-4];
mov dword ptr ss:[esp-4], 12345;
mov dword ptr ds:[0x00560033], 12345;
lea는 좌변(레지스터만 가능)에 우변의 주소값을 입력
예) lea eax, dword ptr ss:[ebp-4]

https://debugjung.tistory.com/entry/%EC%96%B4%EC%85%88-%EB%AA%85%EB%A0%B9%EC%96%B4-mov%EC%99%80-lea-%EC%B0%A8%EC%9D%B4

 

2. 산술 연산자

ADD : 덧셈

ADD 목적지, 소스 목적지 = 목적지 + 소스
ADD EAX, ECX
연산 전: EAX(00000002), ECX(00000001)
연산 후: EAX(00000003), ECX(00000001)

SUB : 뺄셈

SUB 목적지, 소스 목적지 = 목적지 - 소스
SUB EAX, ECX
연산 전: EAX(00000004), ECX(00000001)
연산 후: EAX(00000003), ECX(00000001)

MUL : 부호 없는 곱셈

MUL 소스 EAX = EAX *  소스 (값이 너무 커서 목적지에 다 못들어가면 EDX에 상위 비트 값을 저장)
MUL ECX
연산 전: EAX(00077777), ECX(00077777), EDX(00000000)
연산 후: EAX(C041D951), ECX(00077777), EDX(00000037)

IMUL : 부호 있는 곱셈

① IMUL 목적지
② IMUL 목적지, 소스
③ IMUL 목적지, 소스, 정수
① MUL과 같음
② 목적지 = 목적지 * 소스
③ 목적지 = 소스, 정수
*공통: 값이 커서 목적지에 다 들어가지 못하면 EDX네 상위 비트 값 저장
IMUL ECX, EBX, -4(6BCB FC)
연산 전: ECX(00000003), EBX(00000004)
연산 후: ECX(FFFFFFF0), ECX(00000004)

ECX = EBX * (-4)

윈도우에서는 2의 보수로 음수를 표현한다. -4를 표현하고 싶을 경우 4에 NOT 연산을 한 후 1을 더해주면 된다.

4 0 4
2진수 0000 0100
NOT 연산 1111 1011
+1 1111 1100
-4 F C

따라서 -4가 메모리에는 FC로 저장된다. 이때 IMUL ECX, EBX는 메모리에 6BCB FC가 저장된다는데 아직 이해 못함

어쨌든 FC와 EBX 값인 4를 곱하면 3F0가 된다. 레지스터는 모두 32비트가 들어가기 때문에 나머지는 부호 비트로 채워져 ECX 레지스터엔 FFFFFFF0이 저장된다.

DIV : 부호 없는 나눗셈

DIV 소스(레지스터) EAX의 값/소스 → 몫: EAX에 저장, 나머지: EDX에 저장 *EDX 미리 0으로 변경하기
DIV ECX
연산 전: EAX(0000000A), ECX(00000003), EDX(00000000)
연산 후: EAX(00000003), ECX(00000003), EDX(00000001)

IDIV : 부호 있는 나눗셈

① IDIV 소스(8bits 레지스터)
② IDIV 소스(16bits 레지스터)
③ IDIV 소스(32bits 레지스터)
① AX의 값 / 소스 → 몫: AL, 나머지: AH에 저장
② DX, AX 값 / 소스 → 몫: AX, 나머지 DX에 저장 (*크기가 커서 AX 못담는 수 DX에 나누어 저장) 
③ DEX, DAX / 소스 → 몫: EAX, 나머지: EDX에 저장
*공통: 값이 커서 목적지에 다 들어가지 못하면 EDX네 상위 비트 값 저장
IDIV ECX
연산 전: EAX(FFFFFFF7), ECX(00000002), EDX(00000000)
연산 후: EAX(7FFFFFFB), ECX(00000002), EDX(00000001)

INC : 1증가

IMC 목적지 목적지에 있는 값 +1
INC ECX

DEC : 1감소

DEC 목적지 목적지에 있는 값 -1
DEC ECX

NEG : 부호 반전

NEG 목적지 목적지의 데이터 부호 바꿈. 2의 보수 취하기
NEG ECX
연산 전: ECX(FFFFFFFC) - 4
연산 후: ECX(00000004)

 

3. 부울 연산자

AND

AND 목적지, 소스 목적지 = 목적지 AND연산 소스
AND EAX, ECX
연산 전: EAX(FFFFFFF0), ECX(11100033)
연산 후: EAX(11100030), ECX(11100033)

OR

OR 목적지, 소스 목적지 = 목적지 OR연산 소스
OR EAX, ECX
연산 전: EAX(FFFFFFF0), ECX(11100033)
연산 후: EAX(FFFFFFF3), ECX(11100033)

XOR

XOR 목적지, 소스 목적지 = 목적지 배타적 OR연산(다르면 1, 같으면 0) 소스
ㅌOR EAX, ECX
연산 전: EAX(FFFFFFF0), ECX(FFF000FF)
연산 후: EAX(000FFF0F), ECX(FFF000FF)

 

4. 분기 명령어

CMP

CMP 인자1, 인자2 인자가 서로 같으면 CF=0, ZF=1
CF가 0일 때 인자가 서로 다르면 CF는 그대로
CMP EAX, ECX
연산 전: EAX(00000001), ECX(00000001), C(1), Z(0)
연산 후: EAX(00000001), ECX(00000001), C(0), Z(1)

결과에 있어 CF는 항상 0인가?

JMP : 점프

JMP 목적지 목적지 주소로 이동, 복귀 주소 백업X
JMP 00401018

JE : 같으면 점프

JE 목적지 ZF=1이면 점프 *CMP에서 인자1과 인자 2가 같으면 ZF는 1
JE 00401048

JNE : 다르면 점프

JNE 목적지 ZF=0이면 점프 *CMP에서 인자1과 인자 2가 같으면 ZF는 1
JE 00401048

JZ : 0이면 점프

JZ 목적지 ZF=1 또는 앞의 연산 결과가 0이면 점프
JZ 00401049

JNZ : 0이 아니면 점프

JNZ 목적지 ZF=0 또는 아프이 연산결과가 0이 아니면 점프
JNZE 00401049

JA : 앞이 크면 점프

CMP 인수1, 인수2
JA 목적지
인수1 > 인수2이면 목적지로 점프
CMP EAX, ECX
JA 00401018

JB : 뒤가 크면 점프

CMP 인수1, 인수2
JB 목적지
인수1 < 인수2이면 목적지로 점프
CMP EAX, ECX
JB 00401018

 

5. 시프트 연산자

SHL: 왼쪽으로 비트 이동

SHL 목적지, 비트 수 목적지 데이터를 비트 수만큼 왼쪽으로 이동
SHL EAX, 2
연산 전: EAX(00000FFF)
연산 후: EAX(00003FFC)

SHR : 오른쪽으로 비트 이동

생략 (SHL 참고) 

 

6. 스택 연산자

PUSH : 스택에 입력

PUSH 데이터 데이터에 스택 저장, ESP를 4만큼 감소시킴
함수에 인수 전달 또는 데이터를 백업하고 지역 변수를 위한 공간을 할당할 때 사용
PUSH 0

POP : 스택에서 출력

POP 목적지 데이터를 스택에서 꺼내 목적지에 저장, ESP 4만큼 증가
POP 0

PUSHAD : 레지스터 백업

PUSHAD EAX→ECX→EDX→EBX→ESP→EBP→ESI→EDI 순서대로 스택에 PUSH, ESP레지스터는 32비트 감소
PUSHAD

POPAD: 레지스터 복구

POPAD 스택에 있는 값을 EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP 레지스터에 POP, ESP레지스터는 32비트 증가
POPAD 

 

7. 기타 연산자

CALL: 서브루틴(함수) 호출 

CALL 목적지 복귀 주소(EIP 값)를 스택에 백업한 후 목적지 주소에 있는 서브루틴으로 이동
CALL 00403050

RETN: 복귀

RETN
RETN 바이트 수
백업된 복귀 주소로 이동 (=POP EIP)
바이트 수는 스택 사용 후 반환해야 하는 수
RETN 4

TEST : 테스트

TEST 인수1, 인수2 인수1 AND연산 인수2 = 0이면 ZF=1, 보통 NULL 체크할 때 사용
TEST EAX, ECX
연산 전: EAX(0000FFFF), ECX(FFFF0000), ZF(0)
연산 후: EAX(0000FFFF), ECX(FFFF0000), ZF(1)

 

POP 없이 스택 데이터 읽기

MOV EAX, DWORD PTR SS:[ESP + 4]

ESP 주소에서 4바이트 떨어진 곳의 스택 값을 EAX에 4바이트 복사

 

메모리에서 데이터 읽기

MOV EAX, DWORD PTR DS:[00402000]

ESP 주소에서 4바이트 떨어진 곳의 스택 값을 EAX에 4바이트 복사

 

 

 

 

참고

리버싱 입문, 조성문 저

 

 

 

 

 

 

 

 

 

 

 

 

'Waregame & CTF > Reversing' 카테고리의 다른 글

32bit IAT, EAT 로딩 과정  (0) 2021.10.02
PE 파일 구조 : PE 헤더  (0) 2021.09.28
64bit 레지스터 / 32bit, 64bit 함수호출규약  (0) 2021.09.11
[dreamhack.io]rev-basic-1  (0) 2021.09.11
[dreamhack.io] rev-basic-0  (0) 2021.09.11