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) |
Destination에 Source의 값을 더해서 Destination에 저장한다. |
SUB(Subtract) |
Destination에 Source의 값을 빼서 Destination에 저장한다. |
IMUL (Integer Multiplication) |
Source에 eax의 값을 곱해서 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) |
BYTE나 WORD 크기의 Source를 WORD나 DWORD 크기로 확장하고 부호는 그대로 유지하여 Destination 으로 저장 (한마디로 크기 확장) |
MOVZX (Move with Zero-Extended) |
MOVSX와 똑같은데 남은 비트를 0으로 채움 |
TEST(Test) |
두 피연산자 사이에 논리적인 AND 연산을 수행하여 결과값은 저장하지 않고 플래그 레지스터만 변경 |
AND(Logical AND) OR(Inclusive OR) XOR(Exclusive OR) |
Destination과 Source 피연산자의 각 비트가 AND, OR, XOR 연산된다. |
XCHG(Exchange) |
Destination과 source 내용이 서로 교환된다 |
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 |
'리버싱 > 리버싱기초' 카테고리의 다른 글
DLL(Dynamic-link library) 동적 분석 방법 (2) | 2016.03.07 |
---|---|
리버싱 예제 2 (정적분석 vs 동적분석) (0) | 2015.10.14 |
PE파일 데이터 암호화 (0) | 2015.10.05 |
PE파일 구조 (0) | 2015.09.23 |
리버싱 예제 1 (라이센스 우회) (1) | 2015.09.15 |