본문으로 바로가기

리버싱을 하기 위한 기본 어셈블리어

어셈블리어(Assembly Language)

- 기계어와 1:1로 대응되는 프로그래밍의 저급언어

어셈블리어 형태

- 명령어(opcode)와 피연산자(operand) 두 가지로 구성되어 있다. [ex. MOV eax]

데이터형식

타입

설명

타입

설명

타입

설명

BYTE

부호없는 1바이트 정수(8bit)

WORD

부호없는 2바이트 정수(16bit)

DWORD

부호없는 4바이트 정수(32bit)

SBYTE

부호있는 1바이트 정수(8bit)

SWORD

부호있는 2바이트 정수(16bit)

SDWORD

부호있는 4바이트 정수(32bit)

FWORD

6바이트 정수(48bit)

QWORD

8바이트 정수(64bit)

TBYTE

10바이트 정수(80bit)

REAL4

IEEE표준 4바이트 실수(32bit)

REAL8

IEEE표준 8바이트 실수(64bit)

REAL10

IEEE표준 10바이트 실수(80bit)

C언어로 어셈블리 코드를 짜는 방법

예제
 #include <stdio.h>

int main(void)
{
    __asm
    { 
        //어셈블리 코드 작성
    }
}


어셈블리어 명령어

PUSH

 스택에 값을 저장 (용도 : 함수인자값 전달 , 지역변수 공간할당, 단순 백업)

POP

 스택 안의 값을 EAX에 저장 ( 안에 있던 값은 삭제)

CALL

 함수 호출 시 사용(돌아올 리턴주소를 스택에 저장)

RET

 콜을 했던 지점으로 돌아간다

 RET은 의미상 POP EIP와 동일함 (POP EIP는 존재하는 명령어는 아니다)
 RET n은 RET에 ADD ESP, n 이 추가된 것과 동일함

LEAVE

 스택 프레임을 해제, MOV ESP, EBP / POP EBP 명령과 동일함.
 EBP 주소값을 ESP에 옮기고, 스택의 마지막 값을 EBP에 return 함


1. 부호확장

CBW
(Convert Byte to Word)

 BYTE크기를 WORD로 확장

CWD
(Convert Word to Dword)

 WORD크기를 DWORD로 확장

CDQ
(Convet Dword to Qword)

 DWORD크기를 QWORD로 확장


2. 데이터 복사

LEA
(Load Effective Address)

 Source operand(두번째)의 주소값
 Destination operand(첫번째)로 데이터 복사

 LEA EAX, [EDX+4]

 EAX = &(EDX+4);

MOV
(MOVe data)

 Source operand(두번째)의
 Destination operand(첫번째)로 데이터 복사

 MOV EBX, EAX

 EBX = EAX;

MOVS
(MOVe String)

 ESI가 가르키는 데이터를 EDI가 가르키는 주소로 복사
 (방향 플래그(DF)가 1이면 ESI와 EDI는 감소, 0이면 증가)

 LEA ESI, DWORD PTR [str]
 MOV ECX, 0x06
 REP MOVS BYTE PTR [EDI] BYTE PTR[ESI]

 ESP = &str
 ECX = 0x06
 *EDI=(char)(*ESI)
 ECX의 값만큼 반복

MOVSX
(MOVe with Sign eXtention)

 MOV작업 수행 후 나머지 비트 값을 부호확장 / 부호있는 정수에 사용
 (빈 공간을 최상위 비트로 채움(음수 1이면 1, 양수 0이면 0) )

MOVZX
(MOVe with Zero eXtention)

 MOV작업 수행 후 나머지 비트 값을 0(zero)로 채움 / 부호 없는 정수에 사용


3. 수식 연산

ADD

 덧셈

 ADD EAX, 2

 EAX = EAX + 2;

SUB

 뺄셈

 SUB EAX, 2

 EAX = EAX - 2;

MUL / IMUL

 부호없는 곱셈 /부호있는 곱셈

 MUL EAX, 2

 EAX = EAX * 2;

DIV / IDIV

 부호없는 나눗셈 / 부호있는 나눗셈

 DIV EAX, 2

 EAX = EAX / 2;

IDIV

 부호있는 나눗셈
 (나눗셈 전 CBW, CWD, CDQ를 통해 EDX로 부호비트 확장)

 MOV EAX, -20
 CDQ
 IDIV 2

 EAX = - 20
 EDX=FFFFFFFF(부호비트확장)
 EDX:EAX = EAX / 2

INC

 단일 증가. a++;와 동일

 INC EAX

 EAX++;

DEC

 단일 감소. a--;와 동일

  DEX EAX

 EAX--;


4. 논리 연산 (이진수 사용)

AND

 주로 레지스터 값 존재 여부 확인에 사용.
  둘 다 1 이면 1, 그외는 0

 AND EAX, EAX

 EAX 값이 존재하면 1, 없으면 0

OR

 둘 다 0 이면 0, 그외는 1

 

 OR EAX, EBX

XOR

 특정 변수의 값을 지우고 싶을 때 사용. 다르면 1, 같으면 0

 XOR EAX, EAX

 서로 같은 값이므로 EAX에 0 반환
 (비우기)

NOT

 피연산자의 값을 반대로 바꿈

 MOV EAX, 0x7
 NOT AL

 0111 → 1000 (8)

SHL
(SHift Left)

 피연산자의 비트를 왼쪽으로 이동(*2)

 MOV EAX, 0x06
 SHL EAX, 2

 // 6 * 2 * 2 = 24
 110를 왼쪽으로 2번 이동
 (11000이므로 24)

SHR
(SHift Right)

 피연산자의 비트를 오른쪽으로 이동(/2)

 MOV EAX, 0x06
 SHR EAX, 1

 // 6 / 2 = 3
 110를 오른쪽으로 1번 이동
 (11이므로 3)

SAL

 SHL과 SHR은 부호비트가 변하지만
 SAL과 SAR은 부호비트가 변하지 않는다.

 MOV AL, 0xFD
 SAL AL, 3

  // (-3) * 2 * 2 * 2 = -24
 1111 1101 → 1110 1000이므로 -24

SAR
(Shift Arithmetic Right)

 MOV AL, 0xB8
 SAR AL, 1

 // (-72) / 2 = -36
 1011 1000 → 1101 1100이므로 -36
 ※SHR이라면, 0101 1100(92)가 되버림


5. 그 외

NOP

 아무 일도 하지 않는다.나중에 코드를 추가로 삽입할 때를 위한 빈공간 확보용으로 사용가능

TEST

  AND연산을 이용해 주로 참, 거짓 판별
 OF와 CF는 0 / 결과값이 0이면 ZF=1

 TEST EAX, EAX
 TEST EAX, EBX

 EAX값이 존재하지 않으면 ZF=1
 연산결과가 0이면 ZF=1, 아니면 ZF=0

CMP
 (CoMPare)

 첫번째 값에서 두번째 값을 빼서 비교
  두 같이 같다면 결과는 0이므로 ZF=1

 CMP EAX, 0x05

 EAX == 5 일 경우, ZF=1
 EAX != 5 일 경우, ZF=0

OFFSET

 세그먼트 시작부터 변수까지의 거리 리턴

 LEA EDI, OFFSET a

 세그먼트부터 a의 거리를 EDI에 저장

LOOP

 ECX가 0이 될 때까지 정해진 라벨로 GOTO
  LOOP는 CX사용 / LOOPD는 ECX사용

 LOOPD SHORT

 SHORT라벨로 이동


SCAS
 (SCAn String)

 ES:EDI가 가르키는 곳에 저장된 값을 비교.
 같은 값이면 ZF=1 지정
 (DF값에 따라 EDI값이 + 또는 - 됨)

 SCASB
 SCASW
 SCASD

 (BYTE) AL값 비교
 (WORD) AX값 비교
 (DWORD) EAX값 비교

STOS
 (STOre String)

 EDI가 가르키는 곳으로 문자열을 저장
 (DF값에 따라 EDI값이 + 또는 - 됨)

 STOSB
 STOSW
 STOSD

 (BYTE) AL값을 EDI가 가르키는 곳에 저장
 (WORD) AX값을 EDI가 가르키는 곳에 저장
 (DWORD) EAX값을 EDI가 가르키는 곳에 저장

OFFSET
 

 세그먼트 시작부터 변수까지의 거리 리턴

 LEA EDI, OFFSET a

 세그먼트부터 a의 거리를 EDI에 저장

LOOP
 

 ECX가 0이 될 때까지 정해진 라벨로 GOTO
  LOOP는 CX사용 / LOOPD는 ECX사용

 LOOPD SHORT

 SHORT라벨로 이동

REP
 (REPeat string)

 ECX가 0이 될 때까지 반복

 MOV ECX, 0x03
 REP SCASB /p>

 SCASB명령을 3번 반복

REPNE
 (REPeat until Not Equal)

 문자열을 같지않으면 EDI++, ECX--
 ZF=1 이거나 ECX=0 이면 반복종료

 MOV ECX, 0x05
 REPNE SCAS BYTE PTR [str]

 str이 가르키는 곳의 byte 크기만큼
 AL의 값 00과 비교 5번 반복


7. JMP (조건 점프 명령어 : CMP결과인 플래그 레지스터를 이용해 조건을 만족하면 점프)

- 부등호

JE (Jump if equal)

 ZF = 1

JZ (Jump is zero)

 ZF = 1

JNE (Jump if not equal)

 ZF = 0

JNZ (Jump if not zero)

 ZF = 0

JA (Jump if (unsigned) above)

 CF = 0 and ZF = 0

JAE (Jump if (unsigned) above or equal)

 CF = 0

JNA (Jump if (unsigned) not above)

 CF = 1 or ZF = 1

JNAE (Jump if (unsigned) not above or equal)

 CF = 1

JG (Jump if (signed) greater)

 ZF = 0 and SF = 0

JGE (Jump if (signed) greater or equal)

 SF = OF1

JNG (Jump if (signed) not greater)

 ZF = 1 or SF != OF

JNGE (Jump if (signed) not greater or equal)

 SF != OF

JL (Jump if (signed) less)

 위치

JLE (Jump if (signed) less or equal)

 ZF = 1 and SF != OF

JNL (Jump if (signed) not less)

 위치

JNLE (Jump if (signed) not less or equal)

 ZF = 0 and SF = OF

JB  (Jump if (unsigned) below)

 CF = 1

JBE (Jump if (unsigned) below or equal)

 CF = 1 or ZF = 1

JNB (Jump if (unsigned) not below)

 CF = 0

JNBE (Jump if (unsigned) not below or equal)

 CF = 0 and ZF = 0


- 플러그 세팅 여부

JC  (Jump if carry flag set)

 CF = 1

JCXZ (Jump if CX is 0)

 CX = 0

JNC (Jump if carry flag not set)

 CF = 0

JECXZ  (Jump if ECX is 0)

 ECX = 0

JO (Jump if overflow flag set)

 OF = 1

JS (Jump if sign flag is set)

 SF = 1

JNO (Jump if overflow flag not set)

 OF = 0

JNS (Jump if sign flag is not set)

 SF = 0

JP (Jump if parity flag set)

 PF = 1

JPE (Jump if parity is equal)

 PF = 1

JNP (Jump if parity flag not set)

 PF = 0

JPO (Jump if parity is odd)

 PF = 0



'정보보안 > Reversing' 카테고리의 다른 글

리버스 엔지니어링 기초  (4) 2018.03.27