반응형

리버서들이 가장 많이 사용하는 도구인 디버거(Debugger)에 대해 이야기 해보도록 하겠습니다.


리버싱 현업에서 사용되는 Debugger 들을 간략히 정리해 보겠습니다. 


1. OllyDbg



OllyDbg 는 사용이 편리하고 가볍고 빠른 무료 Debugger 입니다. 도저히 무료라고 보기 힘든 다양한 기능과 많은 Plugin 을 통한 확장성으로 인하여 수 많은 리버서들의 열광적인 지지를 얻고 있습니다. 

OllyDbg 는 리버싱 초보부터 전문가까지 폭넓게 사용되는 가장 인기 있는 디버거입니다.


<그림 1 - OllyDbg>

OllyDbg 의 장점으로는 가볍고 빠르며 상당히 다양한 기능과 많은 옵션을 제공한다는 것입니다. 또한 PlugIn 기능을 통한 확장성을 제공합니다. 가장 사용자가 많고 OllyDbg 를 이용한 리버싱 강좌가 많이 있기 때문에 초보자도 쉽게 배울 수 있습니다. 그리고 무료로 제공된다는 점도 큰 장점입니다.

단점으로는 개인이 혼자서 개발한 거라 업데이트와 후속 제품의 개발 주기가 늦다는 것입니다. 다행히 최근에 OllyDbg 2.0 Final 버전이 릴리즈 되었습니다. 비록 겉모습은 이전 버전과 동일하지만 내부 코드는 완전히 새롭게 프로그래밍 하여 속도와 정확성 등이 크게 향상되었다고 하네요.


2. IDA Pro



Hex-rays 사의 IDA Pro 는 현재 최고의 Disassembler & Debugger 라고 말할 수 있습니다. 과거에는 Disassembler 성격이 강했으나, 수많은 업데이트를 통해 Debugger 기능 또한 막강해 졌습니다. 

수 많은 다양한 기능들을 설명하는 전문 서적이 따로 존재할 정도로 엄청난 기능을 자랑합니다. 또한 Decompiler Plugin 등을 추가로 장착하면 리버싱이 말할 수 없이 편리해 집니다. 그만큼 가격도 비싸지요.

많은 리버싱 전문가들이 IDA Pro 를 주력으로 삼으면서 리버싱 전문 툴로써의 입지를 탄탄히 굳히고 있습니다.

장점으로는 다 써보지도 못할 정도로 다양한 기능과 충실한 업데이트를 들 수 있습니다. 다만 가격이 비싸고 사용법이 비교적 복잡하며 초기 로딩 시간이 좀 걸린다는 것을 단점으로 들 수 있겠습니다. 


<그림 2 – IDA Pro>


3. WinDbg



WinDbg 는 DOS 시절 16 bit 디버거인 debug.exe 의 Windows 버전입니다. 


<그림 3 – Debug.exe>

콘솔 화면에서 키보드만으로 디버깅을 하는 debug.exe 의 사용자 인터페이스를 그대로 가져왔습니다. 저는 이런 스타일의 프로그램을 매우 좋아하지만 반대로 거부감을 갖는 분들도 상당수 계십니다.

유저 모드 디버깅(User Mode Debugging) 분야에서는 사용자 편리성이 뛰어난 OllyDbg 나 IDA Pro 가 꽉 잡고 있습니다. 따라서 WinDbg 는 주로 커널 모드 디버깅(Kernel Mode Debugging)에 주로 사용됩니다. 전설적인 커널 디버거인 SoftICE 의 후속 제품 개발이 중단된 이후 커널 디버깅 분야에서 사실상 독보적인 존재가 되어 버렸습니다. (경쟁 제품이 없는 상태입니다.)

역사가 오래 된 만큼 기능도 다양하고 사용 방법에 대한 전문 서적이 여러 권 나와 있습니다.


<그림 4 - WinDbg>

장점은 커널 디버깅이 가능하다는 것과 Microsoft 에서 직접 만든 디버거라는 점입니다. 시스템 파일에 대한 심볼(Symbol)을 직접 다운 받을 수 있어서 시스템 내부 구조체(Undocumented 포함) 및 API 에 대한 정보를 얻을 수 있습니다. 또한 Windows OS 의 덤프 파일을 읽어 들여 분석할 수 있기 때문에 시스템 크래쉬(Crash)가 발생했을 때 원인을 분석해 낼 수 있습니다. 

단점으로는 다른 디버거들에 비해 좀 떨어지는 사용자 환경과 편의성을 꼽을 수 있겠습니다. (예를 들어 코드에 직접 주석을 입력할 수 없고, Disassembly 코드에서 호출되는 API 이름도 잘 표시되지 않는 등의 불편함이 있습니다.)

그래도 커널 드라이버 개발과 유지보수에 필수적으로 사용되는 디버거 입니다. 리버싱에서는 커널 드라이버 파일 분석에 주로 사용됩니다. 최근에는 대부분 WinDbg 와 VirtualPC(또는 VMWare) 조합으로 커널 디버깅을 수행합니다. 향후 여러분들의 리버싱 실력이 쌓인 후 커널 드라이버(예: Rootkit) 등을 분석할 때 자주 사용될 것입니다.

+---+

지금까지 리버싱 현업에서 사용되는 대표적인 디버거들에 대해서 간략히 살펴보았습니다.

제 경우에는 유저 모드 디버깅에 OllyDbg 1.10 를 사용하고, 커널 모드 디버깅에는 WinDbg 를 사용합니다.

ReverseCore
반응형

'tool' 카테고리의 다른 글

PEView.exe  (21) 2013.01.27
HxD.exe 기능 추가!  (12) 2012.06.14
InjDll.exe – DLL Injection/Ejection 전용 도구  (43) 2010.03.15
Process Explorer - 최고의 작업 관리자  (1) 2009.05.03
www.virustotal.com  (3) 2009.03.20
www.google.com  (2) 2009.03.06
반응형

#0. prologue

분야를 막론하고 기술자(특히 엔지니어)들은 자신만의 작업환경과 손에 익은 도구(장비)가 있습니다.

기술자(특히 엔지니어) 란 특정 업무를 위해서 필요한 도구를 아주 능숙하게 다룰 줄 아는 사람들입니다.

같은 도구를 사용하더라도 기술자의 능력에 따라서 전혀 다른 결과를 보여줍니다.
(더 나아가서 필요한 도구를 직접 만들어 내기도 합니다.)

또한 기술자들은 각자 자신만의 도구를 가지고 있으며
한번 손에 익힌 도구를 되도록 오래 쓰고 왠만해서는 바꾸려 하지 않습니다.
(바꿀 때도 될 수 있으면 같은 회사의 후속 제품으로 바꾸려고 하지요.)

남의 도구, 남의 작업환경에서 일을 하면 아무래도 불편하다고 생각합니다.

즉, 자신만의 작업환경과 자신만의 도구가 갖춰져야 그 기술자의 진정한 실력이 100% 발휘 된다고 할 수 있습니다.



#1. Reverse Code Engineer (Reverser)

리버서들은 어떨까요?

리버서도 역시 IT 엔지니어 범주에 들어가기 때문에 위에서 언급한 일반적인 기술자의 성향과 다를 바가 없습니다.

리버싱을 하기 위한 도구의 종류만도 수십 가지가 넘으며, 각 종류별로 다양한 제품들이 존재합니다.
또한 IT 분야의 특성상 계속해서 새로운 도구가 개발되고 있습니다.

도구의 종류만도 아래와 같이 매우 많습니다. (언급하지 못한 것도 많을 것입니다.)

disassembler
debugger - PE, script, etc
development tool - assembly, C/C++, etc
editor(viewer) - text, hex, resource, retistry, string, PE, etc
monitoring tool - process, file, registry, network, message, etc
memory dump
classifier
calculator - hex, binary
compare tool - text, hex
packer/unpacker
encoder/decoder
virtual machine
decompiler - VB, Delphi, etc
emulator
...



#2. 좋은 분석 도구 선택의 5 가지 기준

아래에 ReverseCore 만의 도구 선택 기준(가이드)을 제시합니다. (참고만 하세요~)


첫째, 도구 개수를 최소화시킨다.

남들이 쓴다고 해서 기능을 알지도 못하는 도구를 잔뜩 가지고 있어봐야 도움이 되지 않습니다.
자신에게 필요한 도구만을 각 종류별로 하나씩만 사용하는 것이 좋습니다.

자신의 실력에 맞는 것만을 고르고 차츰 하나씩 늘려나가시면 됩니다.

또한 중복된 기능의 도구들은 하나로 정리하는 것이 좋습니다.


둘째, 도구는 기능이 단순하고 사용방법이 편리한 것이 좋다.

실력이 늘어날 수록 사용해야 할 도구의 개수도 늘어납니다.
기능이 단순하고 인터페이스가 직관적일 수록 사용하기에 편리합니다.

여기서 기능이 단순하다는 말은 리버싱 도구치고는 단순하다는 말입니다.
(Windows 의 계산기, 메모장 수준을 생각하시면 안됩니다. ^^)

따라서 아무리 단순한 리버싱 도구를 하나 익히는 데만도 어느 정도 시간이 필요합니다.


셋째, 기능을 철저히 익힌다.

아무리 좋은 도구라도 사용할 줄 모르면 무용지물 입니다.

자신이 이미 가지고 있는 도구에서 제공되는 기능인데도,
그걸 알지 못하고 다른 도구를 찾는 분들이 많습니다.

일단 도구를 선택한 후에는 제공되는 메뉴얼을 한번 정독해보시는 것이 좋습니다.
자주 사용하는 기능의 단축키 정도는 외워 두시면 작업이 훨씬 수월합니다.
(단축키를 잘 쓰면 확실히 자타공인 전문가처럼 느껴집니다.)


넷째, 꾸준히 업데이트 한다.

리버싱도 IT 범주에 속하기 때문에 기술 발전 속도가 매우 빠릅니다.

새로운 기술에 대응하기 위해 도구들도 빠르게 변화하기 때문에
사용하는 도구의 업데이트는 매우 중요한 일입니다.

따라서 꾸준히 업데이트를 지원하는 도구를 선택하는 것이 좋습니다.


다섯째, 도구의 핵심 동작 원리를 이해한다.

도구를 더 잘 사용하기 위해서 동작 원리를 이해하는 것이 좋습니다.
더 나아가 테스트용 프로토타입을 만들 수 있다면 금상첨화 입니다.

이 부분을 간과하시는 분들이 매우 많습니다.
하지만 높은 수준의 리버싱 실력을 쌓기 위해서는 필수적인 사항입니다.

예를 들어 debugger 의 동작원리를 이해하고 있으면,
anti-debugging 기법을 잘 회피할 수 있습니다.

원리를 이해하지 못하고 도구에만 의존하면,
간단한 트릭도 해결하지 못하고 다른 도구를 찾아 나서야 합니다.
소위 말하는 "도구의 노예"가 되는 것이지요. (이것만은 꼭 경계해야 겠습니다.)



#3. epilogue

debug.exe 라는 프로그램을 아시나요?
MS-DOS 시절부터 존재하던 16-bit debugger 입니다. (XP 에도 존재합니다.)

커맨드 창에서 debug.exe 를 실행하고 '?' 명령으로 도움말을 보겠습니다.


위에 보이는 명령어가 전부입니다.

단순하지요?

제가 아는 어떤 분이 debug.exe 로 16 bit DOS 프로그램을 분석하시는 걸 본 적이 있습니다.

뭔가를 실행시키더니 키보드를 다다다다 두들기면서 화면이 번쩍 번쩍 넘어가는데,
바로 옆에서 지켜보면서도 무슨 작업을 하는지 도저히 알 수 없었습니다.
(눈이 그분의 작업 속도를 따라가지 못한 거죠.)

처음에는 실행되는 프로그램이 debug.exe 인지 조차도 몰랐었습니다.
(전 그때 당시 이미 debug.exe 를 한달 정도 써본 경험이 있었음에도 불구하고 말이죠.)

그리고는 다 됐다면서 결과를 넘겨 주시더군요.
그때 그분이 사용하신 프로그램이 debug.exe 라는 걸 알고 충격에 휩쌓였었죠.

'저 단순한 debug.exe 만으로 이 일을 이렇게 빨리 해냈단 말인가?' 하고 말이죠.

그 이후로 제가 어떤 도구를 고를 때 나름대로의 기준을 세우게 되었습니다.

그리고 하나의 깨달음을 얻었습니다.

"평범한 도구라도 극한까지 연마하면 천하에 다시 없는 비범한 도구가 된다."

마치 무림고수(武林高手)가 수련에 수련을 거듭해서 검(劍)을 버리고
결국에는 초(草)/목(木)/죽(竹)/석(石)을 모두 검처럼 사용할 수 있듯이 말이죠.


여러분은 어떻게 생각하시나요? ^^


반응형
반응형

HelloReversing.exex




문자열 패치

목표 달성이 눈앞에 다가왔습니다.

MessageBoxW 호출하는 부분을 찾았으니 이제 "Hello World!" 문자열을 "Hello Reversing!" 으로 패치시킬 차례입니다.

디버깅을 재실행[Ctrl+F2] 시키고, main 함수 시작 부분까지 실행합니다.
(401000 에 BP 를 설정[F2]하고 실행[F9] 하세요. - 이 주소를 2 번째 베이스 캠프라고 하겠습니다.)




문자열을 패치하는 2 가지 방법

가장 쉬운 2 가지 방법을 소개합니다.

  • 문자열 버퍼를 직접 수정
  • 다른 메모리 영역에 새로운 문자열을 생성하여 전달



1) 문자열 버퍼를 직접 수정

MessageBoxW 함수의 전달인자 4092A4 의 메모리 주소 내용("Hello World!\)을 직접 수정해 버리는 것입니다.

메모리 윈도우에서 4092A4 로 갑니다 [Ctrl+G].
그리고 주소를 마우스로 선택한 후 [Ctrl+E] 단축키로 에디트 윈도우를 띄웁니다.


<Fig. 16>


'UNICODE' 항목에 "Hello Reversing!" 을 입력합니다.

변경된 코드는 아래와 같습니다.


<Fig. 17>


명령어는 그대로
이지만 MessageBoxW 함수에 전달되는 파라미터의 내용 자체가 변경되었습니다.
(파라미터의 주소도 그대로 입니다. 주소의 내용이 변경된 것입니다.)

이처럼 문자열 버퍼 내용을 직접 수정하는 방법은 사용하기에 가장 간단한 방법입니다.

* 하지만 기존 문자열 버퍼 크기를 잘 고려해서 수정해야만 프로그램이 에러 없이 잘 동작할 수 있습니다.
  즉, 기존 문자열 버퍼 크기 이상의 문자를 입력할 수 없다는 제약 조건이 있습니다.

변경된 내용을 영구히 보존하려면 파일로 만들어야 합니다.
<Fig. 16> 의 dump 윈도우에서 변경된 내용 ("Hello Reversing!" 문자열)을 선택하여
마우스 우측 버튼의 Copy to executable file 메뉴를 선택하면 아래와 같이 hexa 윈도우가 나타납니다.


<Fig. 18>


다시 마우스 우측 버튼의 Save file 메뉴를 선택하고 파일 이름을 HelloReversing.exe 로 해줍니다.

실행해보면 문자열이 성공적으로 변경되었습니다!


<Fig. 19>




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

1) 방법은 MessageBoxW 함수의 파라미터인 문자열 버퍼의 내용을 직접 수정하는 방법이었습니다.

간단하지만 그만큼 단점도 존재합니다.
가령 훨씬 긴 문자열로 수정하고 싶을때 해당 버퍼 크기가 작다면
인접한 다른 메모리 영역을 침범하는 buffer overflow 가 발생할 것입니다.

이럴때 사용할 수 있는 방법이 바로 다른 버퍼 주소를 전달하는 것입니다.
적당한 메모리 주소에 변경하고자 하는 긴 문자열을 적어 놓고
MessageBoxW 함수에게 그 주소를 파라미터로 넘겨주는 것입니다.

즉, 버퍼 자체를 변경하는 것이죠.

아이디어가 좋긴 한데 한가지 고려해야 할 사항은 "메모리 어느 영역에 문자열을 써도 되는가?" 입니다.

자세한 설명은 PE header가상 메모리 구조를 알고 계셔야 하므로 나중에 자세히 다루도록 하고,
여기서는 임의로 적절한 영역을 선택하도록 하겠습니다.

우리가 방법 1) 에서 수정한 버퍼는 408000 ~ 40A000 영역 (.rdata section) 입니다.
이 부분을 다시 dump 윈도우로 살펴보죠. dump 윈도우에서 408000 주소로 갑니다. [Ctrl+G]

스크롤을 밑으로 내리다보면 .rdata section 은 아래와 같이 끝이 납니다.


<Fig. 20>


끝부분에 NULL 로 채워진 영역이 보입니다.

* 이곳은 보통 프로그램에서 사용되지 않는 NULL padding 영역입니다.
  프로그램이 메모리에 로딩될 때 최소 기본 단위(보통 1000)가 있습니다.
  비록 프로그램내에서 메모리를 100 크기만큼만 사용한다고 해도 실제로는 최소 기본 단위인 1000 크기가 잡히는 것입니다.
  (나머지 F00 크기의 사용되지 않는 영역은 그냥 NULL 로 채워집니다.)

이곳을 문자열 버퍼로 사용해서 MessageBoxW 함수에 넘겨주면 좋을 것 같습니다.
끝부분의 적당한 위치 409F50 에 출력하고 싶은 문자열을 써주면 됩니다. [Ctrl+E]


<Fig. 21>


버퍼를 새로 구성하였으니 그 다음에 할 일은 MessageBoxW 함수에게 새로운 버퍼 주소를 전달하는 것입니다.

그러기 위해서는 코드를 수정해야 하는데,
이번에는 Code 윈도우에서 Assemble 명령을 사용해서 코드를 수정해 보겠습니다.

아래 그림처럼 cursor 를 401007 주소위치에 놓고 Assemble 명령(단축키 [Space])을 내리면
아래와 같은 Assemble 윈도우가 나타납니다.


<Fig. 22>


새로운 버퍼주소인 409F50 을 입력합니다.

* 디버깅의 강력한 기능중의 하나가 바로 위와 같이 실행중인 프로세스의 코드를 동적으로 패치 시킬 수 있다는 것입니다.

* 향후 실습해 볼 crackme 샘플에서 serial key 검사 코드를 건너뛰는 방법도 코드를 동적으로 패치하는 것입니다.

OllyDbg 에서 MessageBoxW 함수를 실행하면 결과는 <Fig. 19> 와 같습니다.

그런데 위 수정된 코드를 파일로 만들면 제대로 동작하지 않을 것입니다.
이유는 409F50 메모리 주소 때문입니다.

실행 파일이 메모리에 로딩되어 프로세스로써 실행될 때 그대로 1:1 로 로딩되는 것이 아니라,
어떤 규칙에 의해서 올라가게 되며, 보통은 파일과 메모리가 1:1 로 매칭 되지도 않습니다.

즉, 메모리 409F50 에 대응되는 파일 offset 이 존재하지 않는 것이죠.

방법 2)를 파일로 저장하기 위해서는 아래 2가지 방법중에 하나를 사용하시면 됩니다.

  • PE header 를 분석하여 파일에 존재하지만 프로그램에서 사용되지 않는 공간을 버퍼영역으로 선정
  • 파일 끝을 버퍼 영역 만큼 확장하고, PE header 를 수정하여 그 부분을 메모리에 로딩시킴


역시 PE header 를 알아야 하기에 여기서는 설명을 생략하였습니다.

* 앞으로 작성하게 될 PE header 강좌도 기대해 주세요~



배운내용

- OllyDbg 기초 사용법

Step Into [F7] : 하나의 OP code 실행 (CALL 명령을 만나면, 그 함수 코드 내부로 따라 들어감.)
Step Over [F8] : 하나의 OP code 실행 (CALL 명령을 만나면, 따라 들어가지 않고 그냥 함수자체를 실행함.)
Execute till Return [Ctrl+F9] : 함수 코드 내에서 RETN 명령어 까지 실행 (함수 탈출 목적)
Restart [Ctrl+F2] : 다시 처음부터 디버깅 시작. (디버깅 당하는 프로세스를 종료하고 재실행 시킴.)
Go to [Ctrl+G] : 원하는 주소를 찾아감. (코드를 확인할 때 사용. 실행되는 것은 아님.)
Execute till Cursor [F4] : cursor 위치까지 실행함 (디버깅 하고 싶은 주소까지 바로 갈 수 있음.)
Comment [;] : Comment 추가
User Defined Comments [마우스 우측 메뉴 -> Search for -> User defined Comment] : 사용자가 입력한 comment 목록 보기
Set/Reset BreakPoint [F2] : BP 설정/해제
Run [F9] : 실행 (BP 가 걸려있으면 그곳에서 실행이 정지됨.)
All referenced text strings [마우스 우측 메뉴 -> Search for -> All referenced text strings] : 코드에서 참조되는 문자열 보기
All intermodular calls [마우스 우측 메뉴 -> Search for -> All intermodular calls] : 코드에서 호출되는 모든 API 함수 보기
Name in all modules [마우스 우측 메뉴 -> Search for -> Name in all modules] : 모든 API 함수 보기
Edit data [Ctrl+E] : 메모리 수정
Assemble [Space] : Assembly 코드 작성
Copy to executable file [마우스 우측 메뉴 -> Copy to executable file] : 파일의 복사본 생성 (변경사항 반영됨)

- Assembly 기초 명령어

CALL XXXX : XXXX 주소의 함수를 호출
JMP XXXX : XXXX 주소로 점프
PUSH XXXX : 스택에 XXXX 저장
RETN : 스택에 저장된 복귀주소로 점프

- 프로세스 data/code 패치 방법

OllyDbg 의 ‘Edit data’와’Assemble’기능 이용

- 용어

VA (Virtual Address) : 프로세스내의 가상 메모리
OP code (OPeration code) : CPU 명령어 (byte code)
PE (Portable Executable) : Windows 실행 파일(EXE, DLL, SYS)




배워야할 내용

Virtual memory
PE header
Stack frame
OP code (advanced)
OllyDbg (advanced)



Epilogue

여기까지 따라 오시느라고 수고 하셨습니다.

위에 나온 모든 내용을 한번에 이해하기는 어렵습니다.
2 ~ 3번 반복해서 읽고, 직접 실습해 보시기 바랍니다.

C 프로그래밍에서 Hello World! 는 가장 간단한 프로그램이었습니다.
마찬가지로 Hello World! 디버깅 또한 가장 간단한 디버깅입니다.

Hello World! 를 시작으로 C 프로그래밍을 정복하셨듯이 디버깅 역시 정복하시기 바랍니다.

리버싱에서 디버깅이 차지하는 비중은 매우 큽니다. 또한 가장 재미있습니다.

부디 제 글이 디버깅의 재미를 조금이나마 전달해 드렸으면 좋겠습니다.

감사합니다.

반응형

+ Recent posts