데이터 타입


BYTE : 8비트 부호 없는 정수

SBYTE : 8비트 부호 있는 정수

WORD : 16비트 부호 없는 정수

SWORD : 16비트 부호 있는 정수

DWORD : 32비트 부호 없는 정수

SDWORD : 32비트 부호 있는 정수

FWORD : 48비트 정수

QWORD : 64비트 정수

TBYTE : 80비트 정수

 


연산자(operand) 타입


r8 : 8비트 범용 레지스터

r16 : 16비트 범용 레지스터

r32 : 32비트 범용 레지스터

Reg : 임의의 범용 레지스터

Sreg : 16비트 세그먼트 레지스터

Imm : 8, 16, 32비트 상수

imm8 : 8비트 상수

imm16 : 16비트 상수

imm32 : 32비트 상수

r/m8 : 8비트 범용 레지스터 또는 8비트 메모리

r/m16 : 16비트 범용 레지스터 또는 16비트 메모리

r/m32 : 32비트 범용 레지스터 또는 32비트 메모리

mem : 8, 16, 32 비트 메모리


 

명령어 (Command Destination,Source ) 



- ADD(add) : destination과 source를 더해 destination에 저장한다.

 

- SUB(Subtract) : destination에서 source값을 뺀 뒤 destination에 저장한다.

 

- SBB(Subtract with Borrow) : 하위 자리의 수계산 중에 빌림수를 가져갔다면 그것을

                                           감안해 뺄셈을 한다.

dst = dst - src - CF 식으로 생각하면 된다.

 

- MUL(Unsigned Integer Multiply) : 부호 없는 al, ax, eax의 값을 피연산자와 곱한다.

피연산자가 8비트 이면 al과 곱해서 ax에 저장되고 16비트이면 ax와 곱해서 dx:ax에 저장된다.

피연산자가 32비트 이면 EAX와 곱해서 EDX:EAX에 저장된다.

 

- IMUL(Integer Multiplication) : 부호 있는 al, ax, eax의 값을 피연산자와 곱한다.

결과에 따라 CF, OF가 달라질 수 있다.

피연산자가 8비트 이면 al과 곱해서 ax에 저장되고 16비트이면 ax와 곱해서 dx:ax에 저장된다.

피연산자가 32비트 이면 EAX와 곱해서 EDX:EAX에 저장된다.

결과에서 사용되는 비트 이외에 남은 비트를 부호비트로 채운다.

 

- DIV(Unsigned Integer Divide) : 8, 16, 32비트 부호 없는 값의 나눗셈을 한다.

ax/8bit 값 -> al:ah (몫:나머지)

dx:ax/16bit 값 -> ax:dx

edx:eax/32bit 값 -> eax:edx

결과에 따라 CF, OF, ZF가 세트될 수 있다.

 

- IDIV(Integer Divide) : 8, 16, 32비트 부호 있는 값의 나눗셈을 한다.

ax/8bit 값 -> al:ah (몫:나머지)

dx:ax/16bit 값 -> ax:dx

edx:eax/32bit 값 -> eax:edx

나눌 대상은 나눌 값보다 커야 한다. 부호 없는 경우는 xor연산을 해 0으로 초기화시키면서

확장을 시키고 부호 있는 경우 movsx 동작을 하는 CBW, CWD, CDQ로 부호비트로 채우면서

초기화 시켜서 나눗셈 연산을 수행한다.

 

- INC(Increase) : 피 연산자에 1을 더한다.

연산 결과에 따라 ZF나 OF가 세트 될 수 있다.

- DEC(decrease) : 피 연산자에 1을 뺀다.

연산 결과에 따라 ZF나 OF가 세트 될 수 있다.

 

- LEA(Load Effective Address) : source 의 주소값을 destination에 복사한다.

다시말해 간단히 source 주소값을 알아내서 destination에 복사하는 명령어라고 보면된다.

 

- MOV(Move data) : source 데이터를 destination으로 복사한다.

 

- MOVS(Move String) : source에서 destination으로 복사한다.

                                 문자열을 다루기 때문에 ESI와 EDI를 다룬다.

                                 따라서 ESI 안의 주소가 가리키는 문자열을 EDI 안의 주소가

                                 가리키는 곳으로 복사한다.

MOVS destination, Source

(MOVSB, MOVSW, MOVSD, MOVSQ : BYTE, WORD, DWORD, QWORD)

복사하는 단위마다 명령어가 다르다.

MOVSQ : 64비트에서 사용 가능한 명령어.

 

- MOVZX(Move with zero-Extend) : BYTE나 WORD크기의 피 연산자를 WORD나 DWORD

                                                   크기로 확장하고 남은 비트는 0으로 채운다.

 

- MOVSX(Move with Sign eXtend) : BYTE나 WORD 크기의 피연산자를 WORD나 DWORD

                                                    크기로 확장하고 부호는 그대로 유지한다.

                                                    다시 말해 나머지 공간을 부호비트로 채운다.

* movzx와 movsx의 차이점은 확장시 부호비트에 따라 값이 달라지기 때문에

확장시 확장된 공간을 부호비트로 채우거나 0으로 채우기 위해 두가지로 나뉘어 진다.

movxz - unsign , movsz - sing

 

- rep(repeat string) : ECX가 0이 될 때 까지 문자열 관련 명령을 반복시킨다.

                             문자열 관련 명령어는 MOVS, SCAS, STOS 등이 있다.

 

- repne(repeat until Not Equal) : 보통 SCAS명령어와 함께 쓰인다.

지정된 데이터 타입별로 문자열을 구분하고 한번 구분할 때마다 ECX를 -1 시킨다.

ZF가 1이거나 ECX가 0이 되기 전까지 반복한다.

시작 하는 순간 ECX를 -1 하고 시작한다.

 

- SCAS(Scan String) : 보통 REPNE REPE와 같이 사용된다.

                               Register와 Memory의 데이터 비교한다.

AL 또는 AX, EAX와 ES:(E)DI가 지시한 메모리 내용 비교 후 같은 값이면 ZF가 1로 세트된다.

scasb, scasw, scasd로 사용 한다.

자동으로 DF에 따라 EDI값이 달라진다.

 

- STOS(Store String) : AL, AX, EAX 안의 값을 EDI가 가리키는 곳으로 문자열을 저장시킨다.

Stosb, stosw, stosd로 사용되며 rep명령어와 함께 사용될 수도 있다.

DF에 따라 EDI 값이 + 또는 - 된다.

 

- LOOP : ECX가 0이 될 때 까지 정해진 라벨로 goto 한다.

디스 어셈블리 되면 라벨은 주소가 된다. 다시말해 라벨은 주소다.

또 loop label 을 디스 어셈블리 하면 loopd short 주소 이런 형식으로 나오는데

Loop를 사용하면 CX를 사용한다는 이야기이고 loopd는 ECX값을 사용한다는 이야기이다.

Short은 가까운 라벨을 찾겠다는 의미인데 별 뜻은 없다라고 난 생각한다.

 

- AND : 논리연산자 중 하나로 마스크 비트를 씌우는 동작을 한다.

예를 들면 네트워크에서 서브넷 마스크를 설정하면 네트워크 이름이 나오게 되는게

하나의 예이다.

 

- SAR(Shift Arithmetic Right) : SHR 명령을 사용하면 부호 비트가 변화하기 때문에 값이

                                            일정하게 바뀌지 않는다.

이때 사용 하는 것이 SAR인데 SHR은 무조건 오른쪽으로 비트를 밀어버리는 반면에

SAR은 오른쪽으로 비트를 밀고 기존의 부호 비트를 다시 MSB에 적용시킨다.

예를 들어 10110110 (-74)라는 비트를 SHR하면 01011011(91)이 되는데

만약 SAR하면 11011011(-37)이 된다.

neg : 음수값을 양수로 양수값을 음수로 바꿀때 사용

 

- TEST : 두 오퍼랜드값을 AND연산을 수행한다.

하지만 결과는 저장하지 않고 플래그 레지스터에만 영향을 준다.

대체적으로 TEST 명령 후 jmp 구문이 온다.

TEST는 CMP와 비교할 수 있는데 둘 다 비교 후 결과는 저장하지 않고

플레그 레지스터만 바꾼다.

예를 들어 if문을 사용할 때 비교 대상이 있을경우(if(a<10) 와 비교 대상이 없을경우(if(a))

가 있는데 비교 대상이 있을 경우는 cmp를 쓰고 비교 대상이 없을 경우는

현재 상태를 모르기 때문에 값이 뭔지 알아내기 위해서 TEST 명령어를 이용해 AND연산을

이용해 자신이 어떤 값인지 알아낸다.

보통 참인지 거짓인지를 알아내기 위해 사용한다.

OF와 CF는 항상 0으로 세트되고 TEST 연산 결과값이 0이면 ZF가 1로 세트되고

아니면 0으로 해제된다.

 

- CALL : 함수 호출 시 사용된다.

Jmp와 같이 프로그램의 실행 흐름을 변경 시키지만 jmp명령어와 다른 점은

돌아올 리턴 어드레스를 스택에 저장한다는 것이다.

 

-CMP : 두 오퍼랜드를 비교한다.

Destination 에서 source 를 묵시적으로 값을 빼서 비교한다.

두 피연산자의 값이 같다면 결과는 0이 되고 ZF가 1로 세트된다.

 

- OFFSET : 세그먼트 시작부터 변수가 위치한 거리까지 상대적인 거리를 리턴한다.

예를 들어 lea edi, offset value 하면 세그먼트로부터 value의 위치를 edi에 저장한다.

 

- NOP(No Operation) : 아무일도 하지 않는다.

필요에 따라 유용하게 사용하는데 예를 들면 추가적인 코드를 삽입시키고자 할 때

중간에 바로 삽입이 안되기 때문에 공간을 만들어야 한다.

이럴 때 필요없는 코드를 nop하면 그만큼의 공간을 확보할 수 있다.

 

조건 점프 명령



 JMP는 플래그 래지스터 값들을 이용해 조건이 만족하면 점프를 수행하게 되는 명령어이다.


JA(Jump if (unsigned) above) : CF = 0 and ZF = 0

JAE(Jump if (unsigned) above or equal) : CF = 0

JB(Jump if (unsigned) below) : CF = 1

JBE(Jump if (unsigned) below or equal) : CF = 1 or ZF = 1

JC(Jump if carry flag set) : CF = 1

JCXZ(Jump if CX is 0) : CX = 0

JE(Jump if equal) : ZF = 1

JECXZ(Jump if ECX is 0) : ECX = 0

JG(Jump if (signed) greater) : ZF = 0 and SF = 0

JGE(Jump if (singed) greater of equal) : SF = OF

JL(Jump if (signed) less) : SF != OF

JLE(Jump if (signed) less or equal) : ZF = 1 and OF != OF

JNA(Jump if (unsigned) not above) : CF = 1 or ZF = 1

JNAE(Jump if (unsigned) not above or equal) : CF = 1

JNB(Jump if (unsigned) not below) : CF = 0

JNBE(Jump if (unsigned) not below or equal) : CF = 0 and ZF = 0

JNC(Jump if carry flag not set) : CF = 0

JNE(Jump if not equal) : ZF = 0

JNG(Jump if (signed) not greater : ZF = 1 or SF != OF

JNGE(Jump if (signed) not greater or equal) : SF != OF

JNL(Jump if (signed) not less) : SF = OF

JNLE(Jump if (signed) not less or equal) : ZF = 0 and SF = OF

JNO(Jump if overflow flag not set) : OF = 0

JNP(Jump if parity flag not set) : PF = 0

JNS(Jump if sign flag not set) : SF = 0

JNZ(Jump if not zero) : ZF = 0

JO(Jump if overflow flag set) : OF = 1

JP(Jump if parity flag set) : PF = 1

JPE(Jump if parity is equal) : PF = 1

JPO(Jump if parity is odd) : PF = 0

JS(Jump if sign flag is set) : SF = 1

JZ(Jump is zero) : ZF = 1


 

부호 확장 명령어


부호 있는 나눗셈 연산을 할 시 나눌 대상이 되는 값은 나눌 값보다 커야 하기 때문에 확장을

시켜줘야 하는데 부호 있는 확장을 할 시 사용하는 명령어가 부호 확장 명령어 이다.

- CBW(Convert Byte to Word) : byte크기를 word 크기로 확장시킴

- CWD(Convert Word to Dword) : word크기를 dword 크기로 확장시킴

- CDQ(Convert Dword to Qword) : dword 크기를 qword 크기로 확장시킴

*동작은 movsx와 같고 개념은 초기화 개념으로 본다.

'Reversing > Theory' 카테고리의 다른 글

RVA to RAW 쉽게 생각해보기  (1) 2015.03.20
범용 CPU 레지스터  (1) 2015.03.04
PE File Format 0x04  (0) 2015.01.13
IDA PRO 단축키  (0) 2015.01.13
PE FILE Format 0x03  (0) 2015.01.10