1. Hello World! 프로그램


- Release 모드로 빌드해서 실행 파일을 만든다.(Release 모드로 빌드하면, 코드가 좀 더 간결해져서 디버깅하기 편하다.)


2. HelloWorld.exe 디버깅

2-1. 목표

- HelloWorld.exe 실행 파일을 디버깅(Debugging)하여 어셈블리 언어로 변환된 main() 함수 찾기

- 기본적인 디버거의 사용법과 어셈블리 명령어 학습


2-2. 디버깅 시작

- OllyDbg: http://www.ollydbg.de

* 64bit 버전 사용


설명 

Code Window 

 disassembly code를 표시하여 각종 comment, label을 보여주며, 코드를 분석하여 loop, jump 위치 등의 정보를 표시 

Register Window 

 CPU register 값을 실시간으로 표시하며 특정 register들은 수정 가능

Dump Window 

 프로세스에서 원하는 memory 주소 위치를 Hex와 ASCII/유니코드 값으로 표시하며 수정도 가능 

Stack Window 

 ESP register가 가리키는 프로세스 stack memory를 실시간으로 표시하며 수정도 가능


2-3. EP(EntryPoint)

- 디버거가 멈춘 곳은 EP(EntryPoint) 코드로, 실행파일의 시작 주소이다.

 Address     Instruction     Disassembled code    comment

 --------------------------------------------------------------------------

 004011A0  E8 67150000  CALL 0040270C      ; 0040270C (40270C 주소의 함수를 호출)

 004011A5  E9 A5FEFFFF  JMP 0040104F       ; 0040104F (40104F 주소로 점프) 


 구분

설명 

Address 

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

Instruction 

 IA32(또는 x86) CPU 명령어 

Disassembled code 

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

comment 

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


3. OllyDbg 사용하기

3-1. OllyDbg 단축키

명령어 

단축키 

설명 

Restart 

Ctrl+F2 

 다시 처음부터 디버깅 시작(디버깅 중인 프로세스를 종료하고 재실행) 

Step Into 

F7 

 하나의 OP code 실행(CALL 명령을 만나면 그 함수 코드 내부로 따라 들어감) 

Step Over 

F8 

 하나의 OP code 실행(CALL 명령을 만나면 따라 들어가지 않고 그냥 함수 자체를 실행) 

Execute till Return 

Ctrl+F9 

 함수 코드 내에서 RETN 명령어까지 실행(함수 탈출) 

Go to

Ctrl+G 

 원하는 주소로 이동(코드/메모리를 확인할 때 사용, 실행되는 것은 아님) 

Execute till Cursor 

F4 

 cursor 위치까지 실행(디버깅하고 싶은 주소까지 바로 갈 수 있음) 

Comment 

 Comment 추가 

User-defined comment

 

 마우스 우측 메뉴 Search for User-defined comment 

Label 

 Label 추가 

User-defined label

 

 마우스 우측 메뉴 Search for User-defined label 

Set/Reset BreakPoint 

F2 

 BP 설정/해제 

Run 

$9

 실행(BP가 걸려있으면 그곳에서 실행이 정지됨) 

Show the current EIP 

 현재 EIP 위치를 보여줌 

Show the previous Cursor 

 직전 커서 위치를 다시 보여줌 

Preview Call/JMP address

Enter 

 커서가 CALL/JMP 등의 명령어에 위치해 있다면, 해당 주소를 따라가서 보여줌
            (실행되는 것이 아님, 간단히 함수 내용을 확인) 

3-2. 베이스캠프 설정하기

1) Goto 명령

- 베이스캠프 주소를 기억해 두었다가 Go to[Ctrl+G] 명령으로 베이스캠프로 이동

* Goto명령[Ctrl+G] 이후 주소 입력


2) BP(Break Point) 설치

- Break Point를 설치[F2]를 하고 실행[F9]

* BP 설정[F2]시 Address부분이 빨간색으로 변함


- BP 설정은 View - Breakpoints에서 확인 가능([Alt+B])

* 해당목록에서 더블클릭시 해당 주소로 이동


3) 주석

[;] 단축키로 주석(Comment)을 달고, 이 주석을 찾아가는 방법도 있다.


* BaseCamp라는 이름으로 주석 설정


* 설정 완료



* 오른쪽 마우스 > Search for > User comments에서 확인 가능


3-3. 원하는 코드 빨리 찾는 방법

1) 코드 실행하기

- 프로그램의 기능이 명확한 경우 명령어를 하나하나 실행(Step Over[F8])을 통해 원하는 위치를 찾아감

- 코드의 크기가 작고, 기능이 명확한 경우에 사용

- 코드의 크기가 크고 복잡한 경우에는 적절하지 못함


2) 문자열 검색 방법

- OllyDbg가 디버깅할 프로그램을 처음 로딩할 때 사전 분석 과정을 통해 참조되는 문자열과 호출되는 API들을 뽑아내서 따로 목록으로 정리

- 오른쪽마우스 > Search for > All referenced text strings


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

- 오른쪽마우스 > Search for > All intermodular calls


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

- 오른쪽마우스 > Search for > Names


- OllyDbg가 모든 실행 파일에 대해서 API 함수 목록을 추출할 수 있는 것은 아니다.

- Packer/Protector를 사용하여 실행 파일을 압축(또는 보호)해버리면, 파일 구조가 변경되어 OllyDbg에서 API 호출 목록이 보이지 않음


 용어

설명 

Packer(Run Time Packer) 

 - 실행 압축 유틸리티, 실행 파일의 코드, 데이터, 리소스 등을 압축

 - 일반 압축 파일과 다르게 실행 압축된 파일 그 자체도 실행 파일임 

Protector

 - 실행 압축 기능 외에 파일과 그 프로세스를 보호하려는 목적으로

 - anti-debugging, anti-emulating, anti-dump 등을 추가

 - Protector를 상세 분석하기 위해서는 높은 수준의 리버싱 지식이 요구


- 해당 파일을 리버깅하기 위해서는 프로세스 메모리에 로딩된 라이브러리(DLL 코드)에 직접 BP를 걸어보아야 한다.

- API는 OS에서 제공한 함수이고, 실제로 API는 C:\Windows\system32 폴더에 *.dll 파일 내부에 구현되어 있다.

- 프로그램이 OS에서 실행되기 위해서는 OS에서 제공하는 API를 사용해서 OS에 요청을 해야 하고, 그 API가 실제로 구현된 시스템 DLL 파일들은

  프로그램의 프로세스 메모리에 로딩되어야 한다.

- OllyDbg에서 확인하는 방법은 View > Memory map[Alt+M]


* KERNEL32에 로딩되는 것을 확인 할 수 있다.


- KERNEL32에서 .text 부분에 들어가서 printf를 확인할 수 있다.


- 해당부분에 breakpoint를 걸고 확인해 보면 잘 되는 것을 확인 할 수 있다.


4. 문자열 패치하기

- 문자열 버퍼를 직접 수정

- 다른 메모리 영역에 새로운 문자열을 생성하여 전달

4-1. 문자열 버퍼를 직접 수정

- Dump window에서 "Hello World!"가 저장된 메모리인 '012A573C'로 이동


- 해당부분을 선택하고 Enter를 누르면 수정 창이 뜬다.

- 유니코드는 알파벳 하나당 2Byte의 크기를 차지한다.

* 원본 문자열에 덮어씌울 경우 그 뒤의 데이터가 훼손 되지 않게 조심하여야 한다. 훼손시 메모리 참조 에러가 발생할 위험이 있다.


* 유니코드 문자열은 2Byte 크기의 NULL로 끝나야 한다.


* 수정된후 실행화면

- 해당 방법은 수정후 프로그램을 다시 저장하지 않으면 프로그램 종료후 원상 복구 된다.


4-2. 다른 메모리 영역에 새로운 문자열을 생성하여 전달

- 적당한 메모리 영역에 패치하고자 하는 긴 문자열을 적어 놓고 printf 함수에게 그 주소를 파라미터로 넘겨 준다.


- Hello World!가 저장된 주소 '012A573C' 에서 조금만 내리다 보면 NULL로 덮여 진 부분이 나타난다.

- 이부분은 프로그램에서 사용하지 않는 NULL padding 영역이라고 한다.

- 프로그램이 메모리에 로딩될 때 최소 기본 단위(보통 1000)가 있다. 이 때문에 100의 크기만큼 메모리를 사용한다고 하면 나머지 900 크기는 NULL로 채워진다.


- 해당 부분에 문자열을 입력한다.


- printf 함수에서 Hello World가 있는 주소를 참조하는 부분에서 코드를 수정[space]를 통해 임의로 작성한 문구가 있는 주소로 바꿔준다.



- 잘 실행되는 것을 확인 할 수 있다.

- 하지만 수정된 코드로 파일을 저장후 실행한다면 제대로 동작하지 않을 수 있다.

- 파일이 그대로 메모리로 로딩되는 것이아니라 특정한 규칙에 의해서 올라가기 때문에 파일에 해당 offset이 존재하지 않을 수 있기 때문이다.

'SECURITY > 리버싱(역공학)' 카테고리의 다른 글

리버싱 4장  (0) 2015.08.20
리버싱 3장  (0) 2015.08.20
리버싱 1장  (0) 2015.08.19
Posted by OnewayK
,