일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- x-pack
- 보안양파
- 한글가이드
- endpoint security
- Kibana
- PlayBook
- freebsd
- docker
- ssh key 배포
- Proxy
- macos
- pfsense
- XCP-ng
- proxycfg
- ansible
- GitLab
- Windows
- Kibana server is not ready yet
- elastic stack
- hardening
- centos 8
- xe guest utilities
- ELASTIC
- 로그인불가
- G-suite
- miniconda
- bash
- Elasticsearch
- application security
- Today
- Total
선 밖에 선 자유인
리버스 엔지니어링 준비 운동 본문
최근들어 리버스 엔지니어링(역공학)에 관심을 많으신분들이 늘어났습니다.
하지만 역공학은 해보고 싶은데 어떻게 준비해야될지 모르시는 분들을 위해 어떻게 준비해나가야 하는지를 서술할 예정입니다.
물론 제가 실력이 뛰어난 편이 아니기 때문에 잘못된 정보 혹은 더 좋은 설명 방식이 있으시면 적극적으로 리플 혹은 메일을 보내주시면. 참고 하여 고치겠습니다.
(메일은 머릿말 아래 '더보기'를 누르시면 있습니다.)
--------------------------------------------------------------------------------------------------------
리버스 엔지니어링을 준비하기 이전에 선행 이해도가 필요합니다.
1. 기본적인 프로그래밍 지식 (절차 지향, 객체 지향 언어)
2. PE구조, ELF구조
3. 분석 방법론
4. 알고리즘
5. 어셈블리어 이해
6. 운영체제
7. 악성코드
8. API 함수
9. etc.
반드시 위의 목록들을 모두 알고 있어야만 역분석을 할 수 있다는것은 아닙니다. 얼마나 많은 지식을 이해하고 알고 있는지에 따라 개개인의 분석 방법이 달라지고, 분석 시간과 분석 정확성이 결정되는 부분이라 생각합니다.
하지만 여기서 몇가지 꼭 집어서 알고 있어야 하는 내용은 기본적인 프로그래밍 지식, 어셈블리어 이해, 분석 방법론 정도 입니다.
프로그래밍 지식 :
사실 처음 역분석을 시작하면 프로그래밍 하는 일이 많지 않습니다. 오히려 없는 경우도 있으며, 단순히 눈치껏 어셈블리 코드 값을 보면서 끼워 맞춰도 CrackMe 문제 한두개는 해결할 수 있습니다. 물론 그 이상의 분석방법 역시 한계가 있으므로 C언어 혹은 그 이상의 고급언어들의 프로그래밍 지식을 미리 준비해 두시는것이 좋습니다. 이미 나와 있는 책들로 충분히 준비 하실 수 있습니다.
어셈블리어 이해 :
다른 언어를 이용한 프로그래밍이 어셈블리 언어로 바꾸어 놓기 때문에 어셈블리 언어를 이용하여 프로그래밍할 정도의 실력까지는 요구하지 않습니다. 하지만 이 어셈블리 언어를 보고 이해할 수 있는 수준까지는 되어야 합니다.
약 40개의 어셈블리 명령어와 조건 점프 명령어를 참조 하면, 분석에 크게 지장이 없습니다.
어셈블리 명령어:(스크롤이 길어 '더보기'로 해두었습니다.
1. 명령어 정리
명 령 어 |
설 명 | |
Data Transfer | ||
MOV |
Move |
데이터 이동 (전송) |
PUSH |
Push |
오퍼랜드의 내용을 스택에 쌓는다 |
POP |
Pop |
스택으로부터 값을 뽑아낸다. |
XCHG |
Exchange Register/memory with Register |
첫 번째 오퍼랜드와 두 번째 오퍼랜드 교환 |
IN |
Input from AL/AX to Fixed port |
오퍼랜드로 지시된 포트로부터 AX에 데이터 입력 |
OUT |
Output from AL/AX to Fixed port |
오퍼랜드가 지시한 포트로 AX의 데이터 출력 |
XLAT |
Translate byte to AL |
BX:AL이 지시한 데이블의 내용을 AL로 로드 |
LEA |
Load Effective Address to Register |
메모리의 오프셋값을 레지스터로 로드 |
LDS |
Load Pointer to DS |
REG←(MEM), DS←(MEM+2) |
LES |
Load Pointer ti ES |
REG←(MEM), ES←(MEM+2) |
LAHF |
Load AH with Flags |
플래그의 내용을 AH의 특정 비트로 로드 |
SAHF |
Store AH into Flags |
AH의 특정 비트가 플래그 레지스터로 전송 |
PUSHF |
Push Flags |
플래그 레지스터의 내용을 스택에 쌓음 |
POPF |
Pop Flags |
스택으로부터 플래그 레지스터로 뽑음 |
Arithmetic | ||
ADD |
Add |
캐리를 포함하지 않은 덧셈 |
SBB |
Subtract with Borrow |
캐리를 포함한 뺄셈 |
DEC |
Decrement |
오퍼랜드 내용을 1 감소 |
NEG |
Change Sign |
오퍼랜드의 2의 보수, 즉 부호 반전 |
CMP |
Compare |
두 개의 오퍼랜드를 비교한다 |
ADC |
Add with Carry |
캐리를 포함한 덧셈 |
INC |
Increment |
오퍼랜드 내용을 1 증가 |
AAA |
ASCII adjust for Add |
덧셈 결과 AL값을 UNPACK 10진수로 보정 |
DAA |
Decimal adjust for Add |
덧셈 결과의 AL값을 PACK 10진수로 보정 |
SUB |
Subtract |
캐리를 포함하지 않은 뺄셈 |
AAS |
ASCII adjust for Subtract |
뺄셈 결과 AL값을 UNPACK 10진수로 보정 |
DAS |
Decimal adjust for Subtract |
뺄셈 결과의 AL값을 PACK 10진수로 보정 |
MUL |
Multiply (Unsigned) |
AX와 오퍼랜드를 곱셈하여 결과를 AX 또는 DX:AX에 저장 |
IMUL |
Integer Multiply (Signed) |
부호화된 곱셈 |
AAM |
ASCII adjust for Multiply |
곱셈 결과 AX값을 UNPACK 10진수로 보정 |
DIV |
Divide (Unsigned) |
AX 또는 DX:AX 내용을 오퍼랜드로 나눔. 몫은 AL, AX 나머지는 AH, DX로 저장 |
IDIV |
Integer Divide (Signed) |
부호화된 나눗셈 |
AAD |
ASCII adjust for Divide |
나눗셈 결과 AX값을 UNPACK 10진수로 보정 |
CBW |
Convert byte to word |
AL의 바이트 데이터를 부호 비트를 포함하여 AX 워드로 확장 |
CWD |
Convert word to double word |
AX의 워드 데이터를 부호를 포함하여 DX:AX의 더블 워드로 변환 |
Logic | ||
NOT |
Invert |
오퍼랜드의 1의 보수, 즉 비트 반전 |
SHL/SAL |
Shift logical / arithmetic Left |
왼쪽으로 오퍼랜드만큼 자리 이동 (최하위 비트는 0) |
SHR |
Shift logical Right |
오른쪽으로 오퍼랜드만큼 자리 이동 (최상위 비트 0) |
SAR |
Shift arithmetic Right |
오른쪽 자리이동, 최상위 비트는 유지 |
ROL |
Rotate Left |
왼쪽으로 오퍼랜드만큼 회전 이동 |
ROR |
Rotate Right |
오른쪽으로 오퍼랜드만큼 회전 이동 |
RCL |
Rotate through Carry Left |
캐리를 포함하여 왼쪽으로 오퍼랜드만큼 회전 이동 |
RCR |
Rotate through Carry Right |
캐리를 포함하여 오른쪽으로 오퍼랜드만큼 회전 이동 |
AND |
And |
논리 AND |
TEST |
And function to Flags, no result |
첫 번째 오퍼랜드와 두 번째 오퍼랜드를 AND하여 그 결과로 플래그 세트 |
OR |
Or |
논리 OR |
XOR |
Exclusive Or |
배타 논리 합 (OR) |
String Manipulation | ||
REP |
Repeat |
REP 뒤에 오는 스트링 명령을 CX가 0이 될 때까지 반복 |
MOVS |
Move String |
DS:SI가 지시한 메모리 데이터를 ES:DI가지시한 메모리로 전송 |
CMPS |
Compare String |
DS:SI와 ES:DI의 내용을 비교하고 결과에 따라 플래그 설정 |
SCAS |
Scan String |
AL 또는 AX와 ES:DI가 지시한 메모리 내용 비교하고 결과에 따라 플래그 설정 |
LODS |
Load String |
SI 내용을 AL 또는 AX로 로드 |
STOS |
Store String |
AL 또는 AX를 ES:DI가 지시하는 메모리에 저장 |
Control Transfer | ||
CALL |
Call |
프로시저 호출 |
JMP |
Unconditional Jump |
무조건 분기 |
RET |
Return from CALL |
CALL로 스택에 PUSH된 주소로 복귀 |
JE/JZ |
Jump on Equal / Zero |
결과가 0이면 분기 |
JL/JNGE |
Jump on Less / not Greater or Equal |
결과가 작으면 분기 (부호화된 수) |
JB/JNAE |
Jump on Below / not Above or Equal |
결과가 작으면 분기 (부호화 안 된 수) |
JBE/JNA |
Jump on Below or Equal / not Above |
결과가 작거나 같으면 분기 (부호화 안 된 수) |
JP/JPE |
Jump on Parity / Parity Even |
패리티 플레그가 1이면 분기 |
JO |
Jump on Overflow |
오버플로가 발생하면 분기 |
JS |
Jump on Sign |
부호 플레그가 1이면 분기 |
JNE/JNZ |
Jump on not Equal / not Zero |
결과가 0이 아니면 분기 |
JNL/JGE |
Jump on not Less / Greater or Equal |
결과가 크거나 같으면 분기 (부호화된 수) |
JNLE/JG |
Jump on not Less or Equal / Greater |
결과가 크면 분기 (부호화된 수) |
JNB/JAE |
Jump on not Below / Above or Equal |
결과가 크거나 같으면 분기 (부호화 안 된 수) |
JNBE/JA |
Jump on not Below or Equal / Above |
결과가 크면 분기 (부호화 안 된 수) |
JNP/JPO |
Jump on not Parity / Parity odd |
패리티 플레그가 0이면 분기 |
JNO |
Jump on not Overflow |
오버플로우가 아닌 경우 분기 |
JNS |
Jump on not Sign |
부호 플레그가 0이면 분기 |
LOOP |
Loop CX times |
CX를 1감소하면서 0이 될 때까지 지정된 라벨로 분기 |
LOOPZ/LOOPE |
Loop while Zero / Equal |
제로 플레그가 1이고 CX≠0이면 지정된 라벨로 분기 |
LOOPNZ/LOOPNE |
Loop while not Zero / not Equal |
제로 플레그가 0이고 CX≠0이면 지정된 라벨로 분기 |
JCXZ |
Jump on CX Zero |
CX가 0이면 분기 |
INT |
Interrupt |
인터럽트 실행 |
INTO |
Interrupt on Overflow |
오버플로우가 발생하면 인터럽트 실행 |
IRET |
Interrupt Return |
인터럽트 복귀 (리턴) |
Processor Control | ||
CLC |
Clear Carry |
캐리 플레그 클리어 |
CMC |
Complement Carry |
캐리 플레그를 반전 |
CLD |
Clear Direction |
디렉션 플레그를 클리어 |
CLI |
Clear Interrupt |
인터럽트 플레그를 클리어 |
HLT |
Halt |
정지 |
LOCK |
Bus Lock prefix |
|
STC |
Set Carry |
캐리 플레그 셋 |
NOP |
No operation |
|
STD |
Set Direction |
디렉션 플레그 셋 |
STI |
Set Interrupt |
인터럽트 인에이블 플레그 셋 |
WAIT |
Wait |
프로세서를 일지 정지 상태로 한다 |
ESC |
Escape to External device |
이스케이프 명령 |
2. 8086 어셈블러 지시어(Directive)
지시어 |
내 용 |
형 식 |
SEGMENT |
어셈블리 프로그램은 한 개 이상의 세그먼트들로 구성된다. SEGMENT 지시어는 하나의 세그먼트를 정의한다. |
segname SEGMENT ; 세그먼트 시작 |
PROC |
매크로 어셈블리에서는 프로그램의 실행 부분을 모듈로 작성할 수 있다. 이 모듈을 프로시저(Procedure)라 부르며, PROC 지시어가 이를 정의한다. |
procname PROC ; 프로시저의 시작 |
ASSUME |
어셈블러에게 세그먼트 레지스터와 사용자가 작성한 세그먼트의 이름을 연결시킨다. |
ASSUME SS:stack_segname, |
END |
전제 프로그램의 끝을 나타냄 |
END |
데이터 정의 지시어 : 프로그램에서 데이터를 저장할 기억 장소를 정의, 초기값 부여 | ||
DB |
Define Byte |
name DB 초기값 |
DW |
Define Word |
name DW 초기값 |
DD |
Define Double Word |
name DD 초기값 |
DQ |
Define Quad Word |
name DQ 초기값 |
DT |
Define Ten Bytes |
name DT 초기값 |
EQU |
변수 이름에 데이터값이나 문자열 정의 |
name EQU 데이터값/문자열 |
= |
EQU와 달리 정의된 값을 변경 가능 |
|
EVEN |
어셈블리시 이 지시어가 사용되는 곳의 주소가 짝수로 되도록 함 |
|
PAGE |
어셈블리 리스트의 형식을 결정 |
PAGE [length][,width] |
TITLE |
어셈블리 리스트의 각 페이지에 제목 출력 |
TITLE text |
출처 : http://securecode.tistory.com/30
분석 방법론 :
분석 방법론이라 함은 상당히 범위가 넓습니다. 그중 ollydbg같은 디버거를 이용하는 방법, Wireshark와 같은 네트워크 모니터링 툴을 이용한 패킷 분석 방법, Filemon 같은 시스템 모니터링 툴을 이용한 프로그램 행동양식 분석 방법 등 이 있습니다.
이중 많은 분들이 공부하고 계시는 것중 하나가 ollydbg 툴 사용방법이 아닐까 합니다. (대부분 분석 자료들은 이 툴을 이용하고 있습니다.)
ollydbg : http://www.ollydbg.de
Wireshark : http://www.wireshark.org
Filemon : http://technet.microsoft.com/en-us/sysinternals/bb896642.aspx
--------------------------------------------------------------------------------------------------------
CrackMe 문제를 풀면서 위 목록들을 조금씩 공부해 나가는것도 좋은 방법입니다.
이전 문제 파일들에 대한 풀이 자료들이 이미 충분할 만큼 나와 있으며, 쉽게 따라 할 수 있는 자료들도 존재 하고 있기때문에 문제를 하나씩 풀어보면서 부족한 지식을 보충하는 방법과 검색을 활용을 하면 좋은 청취율을 얻으실 수 있습니다.
역공학을 위한 분석 대상들을 얻기 위해 아래 링크에서 문제 파일을 얻을 수 있습니다.
심플스 : http://simples.kr
crackstore : http://www.crackstore.com