일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- tar
- Reversing
- ZIP
- Android
- 포렌식
- 디스크
- ctf-d
- swing
- disk
- crack
- 안티디버깅
- 리버싱핵심원리
- CodeEngn
- Mobile
- Interceptor
- SW에듀서포터즈
- Multimedia
- John the ripper
- upx
- Autoware
- 써니나타스
- 모바일프로그래밍
- 침해사고대응
- shadow
- Frida
- K-sheild Jr
- 케쉴주
- 파일해시생성
- K-shield Jr 10기
Archives
- Today
- Total
물먹는산세베리아
어셈블리 명령어 모음 본문
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]
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 |