해보자고

[리버싱 핵심 원리] 1장 & 2장 일부 정리 본문

리버싱/리버싱 핵심 원리

[리버싱 핵심 원리] 1장 & 2장 일부 정리

초코맛동산 2023. 3. 16. 01:07

 

+)책과는 다른 디버깅툴을 사용하고 있으니 참고바란다. 다만 리버싱 초보라 언제든 툴이 바뀔 수 있다......

# 학습 목표

- 1장 : 리버싱을 시작하기에 앞서 어떠한 태도로 리버싱에 접근할 것인가?

- 2장: Hello Wordl! 리버싱 (문자열 패치 이전까지)

 

 

---------

 

# 리버싱 스토리

 

1.1. 리버스 엔지니어링 (RE:역공학)

- 기계장치, 시스템 등의 구조, 기능, 동작 등을 분석하여 원리를 이해하며, 단점은 보완하는 등의 일련의 작업

 

 

1.2 리버스 코드 엔지니어링 (RCE)

- 소프트웨어를 리버싱 관점에서 상세하게 분석한다는 의미. 

 

+) 딱히 정확한 용어가 통일되지 않아, RCE, RE, 역공학 등 혼용되고 있음. 

 

 

1.2.1 리버싱 방법

1) 정적 분석

파일을 실행시키지 않고, 파일의 겉모습을 관찰하여 분석하는 방법. 파일의 종류, 크기, 헤더(PE) 정보, Import/Export API, 내부 문자열, 실행 압축 여부, 등록 정보, 디버깅 정보, 디지털 인증서 등의 여러 내용을 확인하는 방법. 

 

 

2) 동적 분석 

파일을 실행시켜 실행되는 행위를 분석하고, 디버깅을 통해 코드 흐름과 메모리 상태 등을 자세히 분석하는 방법.

 

 

1.2.3 패치와 크랙 

1) 패치

프로그램의 파일 혹은 실행 중인 프로세스 메모리의 내용을 변경하는 작업

ex. 윈도우 업데이트 

 

 

2) 크랙

패치와 같은 개념이지만, 의도가 비합법적이고, 비도덕적인 경우

 

 

 

 

 

 

# Hello World! 리버싱

 

 

2.1 코드와 디버깅툴

#include<windows.h> 
#include<tchar.h>

int _tmain(int argc, TCHAR* argv[]) {
	MessageBox(NULL, L"Hello World!", L"www.reversecore.com", MB_OK);
// 첫 번째 인자: hWnd는 메시지 박스 오너 윈도우(메세지 박스를 소유한 윈도우) 특별한 경우가 없다면 NULL
// 두 번째 인자: 메시지 박스에 출력할 문자열
// 세 번째 인수: 메시지 박스 타이틀 바에 나타날 제목 문자열 
// 네 번째 인수: 메시지 박스의 버튼 종류를 지정할 플래그 
	return 0;
}

(HelloWorld.cpp)

 

 

 

해당 코드를 빌드하면 HelloWorld.exe 파일이 생성된다. 대부분 파일이 저장되는 기본 경로는 C:\Users\(사용자이름)\source\repos 이다.

 

HelloWorld.cpp -> HelloWorld.exe 의 의미는 사람이 이해하기 쉬운 언어가(C언어) 기계가 이해하기 쉬운 기계어로 변환된 것. 즉 인간이 이해하기 어려워졌기에 디버거 유틸리티를 사용할 것이다.

-> 디버거의 디스어셈블러 모듈이 기계어를 어셈블리 언어로 보여준다. 기계어일 때보다는 이해하기 당근 쉽다. 

 

+) 어셈블리어는 CPU에 종속되어 있어 일반 PC에서 사용되는 Intel x86 계열의 CPU와 모바일에서 주로 사용되는 ARM 계열의 CPU는 서로 어셈블리 명령어의 형태가 다르다고 한다. 신기방기.  

 

 

 

1) Code window: 기본적으로 disassembly code를 표시하여 각족 comment, label을 보여주며 loop, jump 위치 등의 정보 표시

2) Register Window: CPU register 값 실시간으로 표시하며 특정 register들은 수정도 가능하다. 

3) Dump Window: 프로세스에서 원하는 memory 주소 위치를 Hex와 ASCII/ 유니코드 값으로 표시하고 수정도 가능. 범죄자들이 시그니처나 특징들을 남길 때 덤프에 대부분 표시된다고 한다. 신기방기 

4) Stack Window: *ESP register가 가리키는 프로세스 stack memory를 실시간으로 표시하고 수정도 가능 

 

*ESP register: 스택의 크기를 조정할때 사용되는 레지스터로 스택의 최상단주소값을 지녔다. 즉 스택의 크기를 나타낸다고 할 수 있다. 

 

 

 

2.2 디버깅 시작

2.2.1 EP

Entry Point(EP): 프로그램이 시작하는 지점으로, 모든 프로그램에는 EP가 존재한다. CPU가 Entry Point를 통해 해당 프로그램을 시작하기 때문이다. 흔히 main() 함수를 Entry Point로 사용한다. 

Address Instruction Disassembled code comment

1) Address: 프로세스의 가상 메모리 내의 주소

2) Instruction: IA32(또는 x86) CPU 명령어

3) Disassembled code: OP code를 보기 쉽게 어셈블리로 변환한 코드

4) comment: 디버거에서 추가한 주석(옵션에 따라 약간씩 다르게 보임)

 

-> 디버깅한 주소 0040126C의 의미는 HelloWord.__ ~ 를 호출하고 아랫줄로 넘어가 HelloWor.__~로 점프라하는 내용.

 

 

+) EP를 확인하는 방법

 

해당 코드로 PEviewer(윈도우용 실행 파일인 PE(Portable Executable)의 구조를 분석할 수 있다)를 확인해보면 여러 항목이 존재하고, PE 구조를 확인해볼 수 있다. 이때 EP는 Image Base + Address of Entry Point 값이다. 

 

Image Base: PE 파일이 메모리에 로드될 때의 시작 주소를 가리킨다. 

Address of Entry Point: 프로그램이 메모리에서 실행되는 시작 지점

 

 

+) Immunity Debugger 명령어

명령어 단축키  설명
Restart Ctrl + F2 시작지점부터 다시 디버깅 
Step Into  F7 하나의 명령어 실행, CALL 명령어를 만나면 함수 코드 내부로 들어감
Step Over F8 하나의 명령어 실행, CALL 명령어를 만나도 그냥 함수 자체 실행
Execute till Return Ctrl + F9 함수 코드 내에서 RETN 명령어까지 실행(함수 탈출 목적)
Goto Ctrl + G 특정주소로 이동
Break Point F2 / F9 F2[설치] / F9[실행]
Comment ; 주석 추가
*레이블 : 주소 대체
(*레이블: 주소에 특정 이름을 붙여주는 기능)

pop up -> Search for -> User defined labels -> ;
레이블: 주소 대체

 

 

2.2.2 main() 함수 찾기

1) F8로 하나씩 명령어 실행 

2) CALL 함수 F7로 내부 확인 (함수에서 사용한 API 호출 코드 등 확인)

3) 함수가 아니면 Ctrl + F9 로 RETN 명령어까지 빠르게 진행

4) RETN 명령어 F7로 Step Into 후 다음 명령어 실행

 

책에서는 초보자는 이 4가지 스텝을 계속해서 하기를 권했다. ollydbg보다 친절한 immunity debugger 툴을 써서인지 꽤.... 책보다는 수월한 과정이었다. 코드가 짧아서 더 개이득..

 

 

위 4가지 과정을 계속 하다보면 수상한 호출 함수를 확인 할 수 있다. F7로 해당 함수 속으로 들어가보면...

 

 

 

MessageBox를 호출하고 인자로 넣은 4개의 값들을 확인할 수 있었다. 이를 보아 확실한 main함수임을 알 수 있다. 

 

 

 

 

2.3 베이스캠프

2.3.1 베이스 캠프 설치하는 4가지 방법 

 

+) 베이스 캠프: 디버거를 재실행할 때마다 EP에서 시작하는 불편함을 해소하기 위해 중간중간 코드에서 분석을 원하는 중간 포인트(주소)를 지정한 후 빠르게 이동할 수 있도록 하는 작업. 

 

 1) Goto 명령 

- 단축키: Ctrl + G 

 

2) BP 설치

- 설치: F2

- 실행: F9

 

3) 주석

- 단축키: ;

- Search for -> User defined comment

+) 빨간 글씨가 커서 위치

 

4) 레이블

- 단축키: :

-  Address와 Instruction 사이를 펼치면 등록된 label 확인 가능

- Initial CPU selection은 현재 커서 위치를 나타냄.

 

 

 

2.4 원하는 코드 빨리 찾아내는 방법

1) 코드 실행 방법

- 코드를 실행하면서 API 등의 정보를 통해 코드 찾기

- 코드의 크기가 작고, 기능이 명확한 경우에 편리함.

 

2) 문자열 검색 방법

-  Search for -> All referenced text strings 를 통패 프로그램 코드에서 참조되는 문자열 확인. 더블 클릭하면 해당 주소로 이동.

-> 401002 주소에 PUSH ~ 명령어가 있고, 이 명령어에서 참조되는 402100 주소에는 www.reverscore.com  라는 문자열이다.

-> Ctrl + G로 덤프창에서 이동하면 문자열 그대로 존재함.

 

3) API 검색 방법(1) - 호출 코드에 BP

- 프로그램이 화면에 무언가를 출력했다 -> 프로그램 내부에서 Win32 API 사용(Windows일때)

- 프로그램의 기능을 통해 예측 가능한 Win32 API 확인 

- Search for -> All intermodular calls 통해 코드에서 사용된 API 호출 목록만 확인 가능

위 이미지 더블 클릭시 MessageBoxW로 이동

4) API 검색 방법(2) - API 코드에 직접 BP

- Packer/Protector를 사용할 경우 파일 구조가 변경되어 디버깅이 어려워지거나 API호출 목록이 안 보일 수도 있음. -> 프로세스 메모리에 로딩된 라이브러리(DLL코드)에 직접 BP 걸어보기

- OS에서 제공한 함수가 API -> API는 .dll파일 내부에 구현.

- 즉 프로그램이 어떤 의미 있는 일을 하려면

1) OS에서 제공한 API를 사용해서 OS에 요청

2) DLL 파일들은 우리 프로그램의 프로세 메모리에 로딩

- Search for -> Name in all modules -> Name 정렬 -> 찾고자 하는 기능?(책에선 MessageBoxW) / 

BP 설정

- USER32 모듈의 MessageBoxW 더블 클릭 -> 이동 후 BP (+Ctrl +F2 이후 BP 초기화됨)  -> 실행 -> main -> F9 -> 다시 77221B70임. 

- ESP는 0019FF18이고 이는 프로세스 스택의 주소

MessageBoxW는 0040100E에서 호출되었고, 함수 실행이 종료되면 00401014로 리턴함.

- 0019FF18의 리턴 주소는 HelloWorld.exe의 main 함수 내의 MessageBoxW 함수 호출 바로 다음의 코드. 

=> 이해는 가는데, 헷갈리는 것 같음

 

 

 

참고:

https://unabated.tistory.com/entry/PEPortable-Executable-%EA%B5%AC%EC%A1%B0

 

PE(Portable Executable) 구조

Win32의 기본적인 파일 형식 PE(Portable Executable) 구조 오늘은 PE(Portable Executable)에 대해서 알아보도록 하겠습니다. PE라는 말을 들어보신 적이 있나요? 아마 이 글을 보고 계시는 분들 중에 리버싱 경

unabated.tistory.com