1. Reverse Engineering 개념
소프트웨어 분야에서 리버싱 (Reverse Engineering)은 역공학을 의미를 가지고 있으며 프로그램의 동작 구조, 기능, 동작 등을 분석하여 그 원리를 이해하는 것이다.
악성코드 분석할 때 악성코드의 작동방식,기능, 취약점 등을 파악하는데 사용된다.
2. IA - 32
명령어는 어셈블리를 한번이라도 본적이 있다면 알 수 있는 mov나 push 같은 것을 말하며, 고급진 표현으로는 옵코드 (opcode)라고 말한다. 그리고 인자는 명령어 다음에 "어떠 장소를 값으로 넣을 것인지" or " 명령어에 해당하는 값" 등이 된된다.
어셈블리는 주로 IA-32를 주로 사용하며 명령어와 인자로 구분된다.
- 기본 형태 : 명령어( opcode ) + 인자 ( operand 1~2 )
간단한 예시를 가지고 명령어 ( opcode ) 와 인자 ( operand )에 대해서 알아보자.
ex ) push 337
이 코드에서 opcode는 push가 되며 337은 operand이다.
push는 스택에 값을 넣으라는 명령어 이며 337은 넣을 값이다.
ex) mov eax, 1
명령어는 1개 인자는 1개 ~ 2개 정도 사용된다고 하였다.
이번에는 인자가 2개 사용된 경우이다.
opcode는 mov가 되며 operand는 eax와 1이 된다.
mov는 데이터를 옮기는 명령어, 또는 데이터를 저장하는 의미를 둔다.
mov eax, 1는 eax 레지스터에 값 1을 저장하라는 의미를 두고 있다.
3. 레지스터
레지스터는 총 EAX, EBX, ECX, EDX, ESI, EBP, ESP로 총 8개가 존재한다.
CPU 내부에 있는 작은 메모리 공간이며 cpu가 요청을 처리하는데 필요한 데이터를
일시적으로 저장하는 역할을 한다.
EAX, EBX, ECX는 32 bit 레지스터이며
RAX, RBX 는 64비트의 레지스터이다.
레지스터 | 역할 |
EAX ( Accumulator ) | 각종연산에 사용됨 가장 많이 사용되는 변수 주로 리턴 값을 저장하는데 사용된다. |
EDX ( Data ) | 각종 연산에 사용되는 변수 |
ECX ( Count ) | Fox 문에서의 i의 역할을 가지고 있으며 ECX는 미리 값을 정해두고 0이 될 때까지 진행된다. 변수로 사용해도 상관이 없다. |
EBX | 목적이 없는 레지스터 공간이 필요할 때 num으로 사용된다. |
ESI, FDI (source Index, destination Index) | 문자열이나 각종 반복데이터를 처리 또는 메모리를 옮기는데 사용된다. |
ESP | 스택 포인터 |
EBP | 베이스 포인터 |
EIP | 인스트럭션 포인터 |
레지스터의 단위
32 bit | 16 bit | 상위 8 bit | 하위 8bit |
EAX | AX | AH | AL |
EDX | DX | DH | DL |
ECX | CX | CH | CL |
EBX | BX | BH | BL |
4. 어셈블리 명령어
어셈블리에서 가장 기본적이며 필수적인 몇 개의 명령어 (opcode) 는 확실히 이해하고, 나머지는 필요할 때 찾아서 사용하는 방법으로 충분하다. 아래는 어셈블리에서 필수 명령어로 불리며 참고하고 기억하는 것이 중요하다.
1. PUSH , POP
Push = 스택에 값을 넣는 것
Pop = 스택에 있는 값을 가져오는 것
(Pushrand, Popad) 는 모든 레지스터를 Pus하고 Pop 하라는 명령어이다.
Oprand ( 인자 )는 push eax, push 1, push edx 등 1개만 있으면 된다.
2. MOV
ex) MOV EBX, ECX
mov는 데이터를 이동시키는 명령어, 값을 넣는 역할을 한다.
오른쪽에 있는 값 (ecx의 값)을 왼쪽에 있는 대상 ebx로 복사하여 넣는 것.
즉 MOV EBX, ECX는 ECX에 들어있는 값을 EBX에 복사하여 값을 넣는다.
ECX의 값은 변하지 않음.
3. LEA
LEA는 단순하게 주소를 가져오는 OPCODE이다.
MOV가 값을 가져오는 것이면 LEA는 주소를 가져오는 것이다.
따라서 LEA는 가져올 src OPERAND가 주소라는 의미로 대부분 []로 둘러싸여 있다.
ex) 레지스터와 메모리에는 다음과 같은 값이 저장되어 있다.
esi : 0x40100 (esi에는 0x401000 값이 저장되어 있다.)
*esi : 5640EC83 (esi가 가리키는 번지에는 5640EC83라는 값이 저장되어있음.)
esp+8 : 0X13FF40
*(esp+8) : 33
LEA eax, dword ptr ds:[esi]
→ esi가 0x401000이므로 eax에는 0x401000이 들어온다.
mov eax, dword ptr ds:[esi]
→ esi가 0x401000이므로 eax에는 0x401000 번지가 가르키는 5640EC83 값이 들어온다.
lea eax, dword ptr ss:[esp+8]
→ esp+8은 스택이며 eax에는 0x13FF40이라는 값이 들어온다.
mov eax, dword ptr ss:[esp+8]
esp+8은 스택이며, eax에는 0x13ff40가 가르키는 값인 33이 들어온다.
4. ADD, SUB
ex) add 예제
add는 값을 더하는 OPCODE이다.
eax에 값이 5가 저장되어있다고 가정하자
add, eax, 3을 할경우 eax에 값이 3을 더하여 eax값이 8이 된다.
ex) sub 예제
sub 예제 sub는 뺄셈의 OPCODE이다.
eax 값이 5가 저장되어 있다고 가정할 때,
sub eax, 4는 5에서 4를 빼서 eax의 값은 1이 된다.
5. INT
인터럽트를 호출하는 명령어로, 뒤에 OPERAND로 어떤 숫자가 나오는냐에 따라 각기 다른 처리가 일어난다.
인터럽트 : CPU가현재 수행중인 작업을 중단하고 다른작업(시스템 OR 하드웨어가 요청한 작업)을 처리하도록 하는 매커니즘
명령어의 형식
INT <인터럽트 번호>
ex)
운영체제에서 제공하는 특정 기능을 호출할 때 인터럽트를 사용하여 입출력 작업이나 시스템 호출을 실행할 수 있다.
6. CALL
CALL은 함수를 호출하는 명령어이다.
CALL 뒤에 OPERAND로 번지가 붙는다. 해당 번지를 호출하고 작업이 끝나면 CALL 다음 번지로 되돌아온다.
명령어 형식
CALL [호출할 함수]
7. INC, DEC
INC 와 DEC 명령어는 어셈블리언어에서 증가 (Increment) 또는 감소 (Decrement)하는데 사용된다.
프로그래밍 언어에서 i++; , i--; 와 같은 역할을 하며
INC는 지정된 레지스터나 메모리 위치의 값을 증가시킨다.
DEC는 지정된 레지스터나 메모리 위치의 값을 감소시킨다.
루프를 만들거나 특정 조건을 만족할 때 까지 값을 증가시키거나 줄여나가는 용도로 사용된다.
명령어 형식
INC : INC eax; DEC : DEC ebc;
8. NOP
NOP는 아무런 동작을 하지 말라는 명령어이며, 기계어로 "0X90"이다.
해킹이나 리버스 엔지리어링에서 가장 많이 사용하는 명령어이다.
명령어 형식
NOP;
9. CMP, JMP
CMP 명령어는 두 값을 비교하는데 사용된다.
일반적으로 두 레지스터나 메모리 값의 차이를 계산하여 플래그를 설정한다.
명령어 형식
CMP eax, ebx ; (EAX와 EBX를 비교)
CMP [value], 5 ; 메모리 위치 value의 값과 5와 비교
JMP 명령어는 조건 없이 지정하 주소로 프로그램의 흐름을 이동 시키는 것.
JMP를 사용하면 루프나 특정 블록으로 바로 이동 하 수 있다.
명령어 형식
JMP Label ; label로 무조건 점프