리버싱 기초
- 리버싱은 통상적으로 컴파일된 바이너리(exe, dll, sys 등)를 디스어셈블(disassemble) 도구를 이용하여 어셈블리 코드로 변환하여 필요한 작업을 수행하는 것이다. 어셈블리 코드에서 소프트웨어의 동작 방식을 알아낸다거나 일정 부분만 수정하는 것도 리버싱이라 한다.
ex) 악성코드 분석은 해당 파일 또는 프로그램에서 악성 행위를 하는 부분을 분석한다. - 프로그램을 디스어셈블 하지 않고도 그 실행 파일이 만들어내는 데이터 파일이나 패킷 등을 분석하여 그 프로그램을 재현하는 것도 리버싱이라 볼 수 있다.
ex) 서버와 통신을 수행하는 기능이 있는 게임 프로그램이 디버거나 에디터를 활용하여 게임 프로그램을 조작하지 않고 패킷 분석 프로그램을 이용하여 패킷을 분석 및 동작을 흉내 내는 프로그램을 제작할 수 있다.
코드 계층
- 하드웨어(Hardware)
유일한 물리 계층으로 XOR, AND, OR, NOT 같은 복잡한 논리적 연산자 조합으로 구현된 전자회로로 구성
- 마이크로코드(Microcode)
설계된 것과 정확히 일치하는 회로만 동작, 펌웨어로 알려짐
- 기계어 코드(Machine Code)
옵코드(opcode)와 원하는 작업을 프로세서에 알려주는 16진수로 구성
- 저급 프로그래밍 언어(Low-level languages)
컴퓨터 아키텍처 명령어 집합 중 인간이 읽을 수 있는 버전, 어셈블리어(exe 파일을 디버깅한거)
- 고급 프로그래밍 언어(High-level languages)
기계 수준에 대한 강력한 추상화를 제공해 프로그래밍 논리나 흐름 제어 매커니즘을 이용하기 쉽게 함
- 인터프리터 언어(Interpreted languages)
최상위 계층, 기계어로 컴파일 하지 않고 바이코드로 변환, 파이썬, C#, Perl, 닷넷, 자바
x86 아키텍처
- 중앙 처리 장치(CPU)는 코드를 실행
- 시스템 주기억 장치(RAM)는 데이터와 코드를 저장
- 입출력 시스템은 하드디스크, 키보드, 모니터 같은 장치와 상호 작용
어셈블리 기초
- C/C++코드와 어셈블리 코드의 차이
- 어셈블리 코드는 한 가지 동작까지 세세하게 지정한다.
올리디버거(디버깅 프로그램중 하나이며, 디스어셈블리와 디버그가 모두 가능한 툴)를 사용하여 어셈블리어를 분석하는것이 리버싱이며, 각 어셈블리 코드를 통해 윈도우 API의 함수를 유추하여 악성코드의 행위를 분석한다.
리버싱: exe → 어셈블리어 → C언어
레지스터의 종류
- CPU가 사용하는 변수
레지스터 | 역할 |
EAX (Accumulator) |
- 논리연산에 쓰임 - 가장 많이 쓰이는 변수 - 함수의 반환값이 저장됨 |
EDX (Data) | - 각종 연산에 쓰이는 변수 - EAX와 같이 쓰이고 부호 확장 명령 등에 쓰인다. - 큰 수의 곱셈 또는 나눗셈 등의 연산이 이루어질때, EDX 레지스터가 사용되어 EAX 레지스터와 함께 쓰인다. |
ECX (Count) | - 카운터 레지스터, 주로 반복 명령어 사용 시 반복 카운터로 사용 - for문에서 i의 역할 - ECS는 미리 값을 정해놓고 0이 될 때까지 진행 - 변수로 사용해도 무방 |
EBX | - 목적이 없는 레지스터 - 공간이 필요할 때 덤으로 사용 |
ESI, EDI (Source Index, Destination Index) |
- 문자열이나 각종 반복 데이터를 처리 또는 메모리를 옮기는데 사용 - ESI: 데이터 조작 또는 복사시에 소스 데이터의 주소가 저장됨. - EDI: ESI 레지스터와 비슷하나, EDI 레지스터에는 복사 시의 목적지의 주소가 저장됨. |
ESP | - 스택 포인터 - 스택 프레임의 끝 지점 주소(스택의 가장 아랫부분, 스택의 마지막)가 저장됨 - PUSH, POP 명령에 따라 ESP 값이 4바이트씩 변한다. |
EBP | - 베이스 포인터 - 스택 프레임의 시작 지점 주소(스택의 가장 윗 부분, 스택의 처음)가 저장됨 - EBP 레지스터는 현재 사용되는 스택 프레임이 소멸되지 않는 이상 EBP 레지스터의 값은 변하지 않는다. |
EIP | 인스트럭션 포인터 |
레지스터의 단위
32bit | 16bit | 상위 8bit | 하위 8bit |
EAX | AX | AH | AL |
EDX | DX | DH | DL |
ECX | CX | CH | CL |
EBX | BX | BH | BL |
어셈블리의 명령 포맷
- 주로 IA-32를 사용
- 기본 형태: 명령어(옵코드, opcode) + 인자(오퍼랜드, operand 1 ~ 2)
명령 코드 분류
데이터 이동(Data Transfer) | mov, lea |
산술 연산(Arithmetic) | inc, dec, add, sub |
논리 연산(Logical) | and, or, xor, not |
비교(Comparison) | cmp, test |
분기(Branch) | jmp, je, jg |
스택(Stack) | push, pop |
프로시져(Procedure) | call, ret, leave |
시스템 콜(System call) | syscall |
어셈블리 명령어 참고 블로그
https://coding-factory.tistory.com/650
https://johyungen.tistory.com/229
2개의 인자를 사용하는 명령어 예시
명령어 | 설명 |
mov eax, ebx | EBX의 내용을 EAX 레지스터로 복사한다. |
mov eax, 0x42 | 값 0x42를 EAX 레지스터로 복사한다. |
mov eax, [0x4037C4] | 메모리 위치 0x4037C4에 있는 4바이트 값을 EAX 레지스터로 복사한다. |
mov eax, [ebx] | EBX 레지스터가 명시한 메모리 위치에 있는 4바이트 값을 EAX 레지스터로 복사한다. |
mov eax, [ebx_esi*4] | ebx+esi*4 연산 결과가 명시한 메모리 위치에 있는 4바이트 값을 EAX 레지스터로 복사한다. |
최소한으로 알아야 하는 어셈블리 명령어
명령어 | 설명 |
PUSHAD | 8개의 범용 레지스터의 값을 스택에 저장한다. |
POPAD | PUSHAD 명령으로 스택에 저장된 값을 다시 레지스터에 입력한다. |
PUSH A | A 값을 스택에 넣는다. |
POP 레지스터 | 스택에서 값을 꺼내 레지스터에 넣는다. |
INC A | A 값을 1 증가시킨다. |
DEC A | A 값을 1 감소시킨다. |
ADD A B | A 값과 B 값을 더해서 결과를 A에 저장한다. |
SUB A B | A 값에서 B 값을 빼고 결과를 A에 저장한다. |
IML A B | A 값과 B 값을 곱하고 결과를 A에 저장한다. |
LEA A B | A 값을 B 값으로 만든다. (레지스터에 주로 사용) |
MOV A B | B 값을 A로 복사한다. |
XCHG A B | A 값과 B 값을 바꾼다. |
TEST A B | A 값과 B 값을 AND연산한다. (연산 결과가 0이면 ZF가 1이 되고, 연산 결과가 0이 아니면 ZF는 0이 된다.) |
AND A B | A 값과 B 값을 AND연산한다. (연산 결과가 0이면 ZF가 0이 되고, 연산 결과가 0이 아니면 ZF는 0이 된다.) |
CMP A B | 비교구문으로 A와 B의 값이 같은지 판단한다. (같을 경우 ZE는 1이 되고 다를 경우 F는 0이 된다.) |
'보안 > 악성코드 분석' 카테고리의 다른 글
악성코드 동적 분석 도구 올리디버거 활용 (0) | 2024.08.12 |
---|---|
악성코드 동적 분석 도구 기능 및 사용법 (Process Monitor, Process Explorer) (0) | 2024.07.26 |
DLL 의존성 확인 도구 (Dependency Walker) & 리소스 확인 도구 (리소스 해커) 기능 및 사용법 (0) | 2024.07.24 |
PE 헤더 분석 도구 (PEview, pestudio) 기능 및 사용법 (4) | 2024.07.23 |
악성코드 분석 시 파일 내 문자열 확인 도구 (BinText, Strings) 기능 및 사용법 (3) | 2024.07.22 |