본문 바로가기

리버싱/리버싱기초

리버싱 백그라운드(x86)

1. Fetch 사이클과 Execution 사이클





 우리가 프로그램의 일부분을 수정하고 싶을 때 프로그램의 소스코드가 있다면 소스코드를 통해 프로그램의 실행구조를 확인하고 다시 컴파일 하면 된다. 하지만 소스 코드가 없다면 디버깅을 통해 어셈블 코드가 어떻게 실행되는 알아야만 한다. CPU의 60퍼센트는 ALU로 이루어져 있고 나머지는 주변장치로 이루어져 있고 시분할을 이용해 아주 작은 시간 안에는 반드시 하나의 코드만 실행된다 이 실행될 명령은 인스트럭션 큐에 들어가 있다.


 온리디버그와 같은 프로그램을 사용할 때 브레이크 포인트를 거는 것은 소프트웨어 인터럽트를 이용하는 것이다. (INT3 : HALT : 0xCC) 그리고 내부 레지스터의 값을 확인하는데 적절한 인터럽트의 위치와 시점은 연습을 통해 깨닫게 된다. 인터럽트 외에 H/W BP가 하나 더 필요하다. 바로 CPU DR0~DR3 이 필요한데(ARM은 온칩 브레이크) 이를 이용하면 메모리가 어디든지 하드웨어 브레이크를 설정하면 인터럽트가 발생된다. (Access, Write, Execute) 결국 이 2개를 얼마나 적절히 사용하느냐가 리버싱의 중요한 포인트가 된다. 또한 어셈블을 이해해야 정확한 포인트를 찍을 수 있다. 



2. 레지스터 용도


1) 범용 레지스터 (산술연산)

 - EAX : 함수 리턴 값으로 사용

 - EBX

 - ECX : 루프에서 카운트로 사용

 - EDX


2) 범용 레지스터 (메모리주소)

 - EBP : 함수 호출 시 스택구조 유지

 - ESP : 스택메모리주소

 - EDI : 그 외 메모리 작업

 - ESI : 그 외 메모리 작업


3) 세그먼트 레지스터

 - 메모리를 조각 내어 메모리를 보호

 - CS, SS, DS, ES, FS, GS


4) 플래그 레지스터

 - 연산을 도와주는 플래그 값

 - 방향플래그 : 스트링 문자를 이동하거나 비교할 때 방향을 결정

 - 인터럽트 플래그 : 외부인터럽트 처리 여부 결정

 - 캐리 플래그 : 연산 시 범위 초과를 도와주는 캐리 비트의 사용 여부

 - ...


5) EIP

 - CPU가 처리할 명령어의 주소



3. 데이터타입


타입

설명

BYTE

 8비트 부호 없는 정수

SBYTE

 8비트 부호 있는 정수

WORD

 16비트 부호 없는 정수

SWORD

 16비트 부호 있는 정수

DWORD

 32비트 부호 없는 정수

SDWORD

 32비트 부호 있는 정수

FWORD

 48비트 정수

QWORD

 64비트 정수

TBYTE

 80비트 정수



4. 피연산자(operand) 타입


피연산자

설명

r8, r16, r32

 8, 16, 32비트 범용 레지스터

Reg

 임의의 범용 레지스터 (레지스터)

Sreg

 16비트 세그먼트 레지스터

Imm

 8, 16, 32비트 즉시 (상수)

imm8, imm16, imm32

 8, 16 ,32비트 즉시 (상수)

r/m8, r/m16, r/m32

 8, 16, 32비트 범용 레지스터, 메모리

mem

 8, 16, 32비트 메모리 (메모리)

 표현방법 [메모리 주소 (+- 상수) ]

 Ex1) [EBP+0x08]

 Ex2) [EBP-0x08]

 Ex3) [0x0401000]

Label

 지정된 레이블

 표현방법 Label

 EX1) goto C_Dest;



5. 변환


변환 어셈블리어

설명

 PTR

 피연산자의 크기를 재설정한다.

 Ex) MOV eax, DWORD PTR value

 (위의 명령어는 value의 크기를 DWORD  크기로 재설정하여 eax 레지스터에 복사 하라는 의미이다.)

OFFSET

 세그먼트의 시작으로부터 변수가 위치한  거리까지의 상대적 거리를 리턴한다.

 Ex)MOV esi, OFFSET value

 (위 명령어는 value가 존재하는 위치를 

 세그먼트 시작 지점으로부터의 상대적 

  거리 로 구해서 esi 레지스터에 

 복사하라는 의미이다.)

 


 

6. 어셈블리명령어

 

6.1 단독 명령어


어셈블리 명령어

설명

MOVSB,

MOVSW,

MOVSD

(Move String)

 ESI 레지스터에 의해 지정된 메모리 주소의 내용을

 EDI 레지스터에 의해 지정되는 메모리 주소로 복사한다.

 (B : byte 단위, W : word 단위, D : dword 단위)

STC(Set Carry Flag)

 캐리 플래그(CF)1로 세트 한다.

CLC(Clear Carry Flag)

 캐리 플래그(CF)0으로 세트 한다.

STD(Set Direction Flag)

 방향 플래그(DF)1로 세트 한다.

CLD(Clear Direction Flag)

 방향 플래그(DF)0으로 세트 한다.

STI(Set Interrupt Flag)

 인터럽트 플래그(IF)1로 세트 한다.

CLI(Clear Interrupt Flag)

 인터럽트 플래그(IF)0로 세한다.

 

어셈블리 명령어

설명

PUSHAD(Push All)

EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP 레지스터의 값을 스택에 PUSH한다.

레지스터의 값을 보관해야 할 필요가 있을 때 사용한다.

PUSHFD(Push Flags)

플래그 레지스터를 스택에 PUSH한다. 플래그 레지스터의 값을 보관해야 할 필요가 있을 때 사용한다.

POPAD

(Pop All from Stack)

스택에 존재하는 값을 EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP 레지스터로 POP한다.

PUSHAD 명령어로 스택에 보관해 놓은 레지스터 정보를 다시 이용하려고 할 때 사용한다.

POPFD

(Pop Flags from Stack)

스택에 존재하는 값을 플래그 레지스터로 POP한다. PUSHFD 명령어로 스택에 보관해 놓은 레지스터 정보를 다시 이용하려고 할 때 사용한다.

 

 

6.2  명령어 + dest

 

어셈블리 명령어

설명

INC(increase)

피연산자에 1을 더한다

DEC(Decrease)

피연산자에서 1을 빼는 명령이다

MUL

(Multiply Unsigned Integer)

부호 없는 eax의 값을 피연산자와 곱한다.

IMUL

(Integer Multiplication)

부호 있는 eax의 값을 피연산자와 곱한다.

DIV

(Divide Unsigned Integer)

8, 16, 32비트 부호 없는 정수의 나눗셈을 수행한다.

INT(Interrupt)

소프트웨어 인터럽트를 발생시켜 운영체제의 서브루틴을 호출한다.

NEG(Negate)

피연산자의 2의 보수를 계산하여 결과를 피연산자에 저장한다.

 

 

어셈블리 명령어

설명

PUSH(Push on Stack)

스택에 값을 넣는다. ESP의 값이 4만큼 줄어들고 이 위치에 새로운 값이 채워진다.

POP(Pop from Stack)

ESP 레지스터가 가리키고 있는 스택 공간에서 4Byte 만큼을 Destination 피연산자에 복사하고 ESP 레지스터의 값에 4를 더한다.

 

 

6.3  명령어 + dest + src

 

어셈블리 명령어

설명

ADD(Add)

DestinationSource의 값을 더해서

Destination에 저장한다

SUB(Subtract)

DestinationSource의 값을 빼서

Destination에 저장한다.

 IMUL

(Integer Multiplication)

Sourceeax의 값을 곱해서

Destination에 저장한다.

MOV(Move)

Source에서 Destination으로 데이터를 복사한다.

(mov lea와 달리 도중에 주소연산이 불가능 하다.)

MOVS(Move String)

Source에서 Destination으로 데이터를 복사한다.

SHL(Shift Left)

Destination 피연산자를 Source 피연산자의 크기만큼 왼쪽으로 각 비트를 시프트 시킨다.

SHR(Shift Right)

Destination 피연산자를 Source 피연산자의 크기만큼 오른쪽으로 각 비트를 시프트 시킨다

 

 

어셈블리 명령어

설명

MOVSX

(Move with Sign-Extended)

BYTEWORD 크기의 Source

WORDDWORD 크기로 확장하고

부호는 그대로 유지하여 Destination 으로 저장

(한마디로 크기 확장)

MOVZX

(Move with Zero-Extended)

MOVSX와 똑같은데 남은 비트를 0으로 채움

TEST(Test)

피연산자 사이에 논리적인 AND 연산을 수행하여

결과값은 저장하지 않고 플래그 레지스터만 변경

AND(Logical AND)

OR(Inclusive OR)

XOR(Exclusive OR)

DestinationSource 피연산자의 각 비트가

AND, OR, XOR 연산된다

XCHG(Exchange)

Destinationsource 내용이 서로 교환된다

LEA

(Load Effective Address)

Source의 유효 주소를 계산하여 Destination 에 복사한다.  (lea mov와 달리 주소만 입력 가능)

 

 

6.4  명령어 + dest + src1 + src2

 

어셈블리 명령어

설명

IMUL

(Integer Multiplication)

Source 끼리 곱해서 Destination에 저장한다.

 

 

6.5 명령어(기타)

 

어셈블리 명령어

설명

IMUL

(Integer Multiplication)

Source 끼리 곱해서 Destination에 저장한다.

 

어셈블리 명령어

설명

CMP(Compare)

피연산자를 비교하는 작업을 한다. 피연산자의 값이 같다면 제로 플래그(ZF)1로 세트 된다. 다르다면 제로 플래그(ZF)0으로 세트 된다.

Ex)

CMP reg, reg                CMP reg, imm

CMP mem, reg              CMP mem, imm

CMP reg, mem

NOP(No Operation)

아무 일도 하지 않는 명령어이다. 리버싱 작업에서 목적에 따라 유용하게 사용될 수 있다.

 

 

6.6 조건점프 명령어

 

참고 : CF : carry      SF : sign      ZF : zero      CX,ECX : 연산레지스터

 

 

어셈블리 명령어

설명

플래그

A

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 (signed) greater or equal

SF=OF

 

어셈블리 명령어

설명

플래그

JL

Jump if (signed) less

SF!=OF

JLE

Jump if (signed) less or equal

ZF=1 and SF!=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 is 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 if zero flag is set

ZF=1