-
[리버싱 핵심원리 study] 2장 Hello World! 리버싱Reverse Engineering 2020. 11. 22. 03:32
처음 프로그래밍 언어를 배웠을 때, 아마도 가장 먼저 Hello World!를 출력해보는 프로그램을 작성할 것이다. 마찬가지로 리버싱에서도 Hello World! 프로그램을 분석해보는 방식으로 시작한다. (코드 작성은 Microsoft Visual C++ 2010 Express을 기준으로 하였다.)
1. 프로그램 작성
먼저 다음과 같은 코드를 작성하여 Hello World! 문구를 출력하는 프로그램을 만들어보자.
#include "windows.h" #include "tchar.h" int _tmain(int argc, TCHAR *argv[]) { MessageBox(NULL, L"Hello World!", L"www.reversecore.com", MB_OK); return 0; }
(HelloWorld.cpp)
Release 모드에서 빌드(Debug 모드로 빌드할 시 프로그램에 Debugging 정보가 포함되어 프로그램 내용이 길어지고 복잡해진다.)를 하게 되면 .exe 파일이 생성될 것이다. 클릭하여서 실행해보자.
위와 같이 Hello World!라는 문구를 출력하는 메시지 박스가 출력되는 것을 확인할 수 있다. 이제 위 exe 파일을 디버거를 이용해 그 구조를 살펴보겠다.
2. Ollydbg를 이용한 분석(1)
Ollydbg를 처음 실행하면 다음과 같다.
여기서 File->Open(F3)를 이용해 HelloWorld.exe파일을 열어보자.
무언가 굉장히 복잡해 보이지만 크게 4가지 영역으로 나뉘는 것을 확인할 수 있다. 파란 펜으로 표기한 것과 같이 1번 영역은 프로그램의 어셈블리 코드를 나타낸다. 2번 영역은 코드의 진행 시점에서의 register value 및 flag value를 나타낸다. 3번 영역은 Dump 영역으로, data의 ASCII값을 확인할 수 있다. 4번 영역은 stack 영역으로 현재 esp, ebp가 어디에 위치하고 있는지 알 수 있다.
EP(entry point)에서 하나하나 코드를 실행시키면서 프로그램 내부 구조를 파악할 수 있는데, 생각했던 것 만큼 내부 구조가 단순하지는 않다. 각 컴파일러마다 추가적으로 붙게 되는 Stub Code 등이 있으며, 언뜻 보기에는 무의미해 보이는 assembly 연산도 존재한다. 우선 코드를 하나씩 실행시키기 위해 사용되는 기본적인 기능들로는 다음과 같은 것들이 있다.
기능(단축키)
설명
Debug->Restart (Ctrl+F2)
프로그램을 처음부터 restart 한다.
Debug->Step into (F7)
코드를 하나 실행시킨다.
Debug->Step over (F8)
코드를 하나 실행시킨다.(함수 내부로 들어가지 않음)
Debug->Run (F9)
프로그램을 bp까지 실행한다.
앞서 말했듯이, 프로그램에 앞에 Stub Code가 붙어있으므로, 우리가 원하는 main 함수를 찾아낼 때 까지 위와 같은 기능을 이용한다. 물론 다른 방법들도 존재하지만, 처음에는 위와 같은 방법이 익숙해지도록 하는 것이 좋다. 코드를 실행시키다보면 다음과 같은 코드를 볼 수 있을 것이다.
이 부분이 우리가 원하는 main 함수의 내부임을 알 수 있다.
3. Ollydbg를 이용한 분석(2)
언제나 항상 main 함수가 나올 때까지 F7, F8을 연타할 수는 없는 노릇이다. 사실 여러 다른 방법이 있는데 HelloWorld 프로그램의 경우 다음과 같은 방법으로 main 함수를 찾아낼 수 있다.
(1) 문자열 검색
HelloWorld 프로그램에서는 HelloWorld! 라는 문자열을 출력한다. 이에 착안하여 프로그램 내부에서 사용되는 문자열을 검색하면 보다 쉽게 main 함수를 찾을 수 있을 것이다. code창에서 마우스 우클릭->Search for->All referenced text strings를 선택하면 다음과 같은 화면이 나온다.
(2) API 검색
MessageBox API를 이용한 다는 점에 착안하여 어디서 호출되는지를 찾아볼 수도 있다. 마우스 우클릭->Search for->Name in all modules를 통해 프로그램에 사용된 모든 API 호출 목록을 찾아볼 수 있다. 아래 첨부사진과 같이 00FE100E 주소에서 MessageBoxW가 호출됨을 알 수 있다.
위에서 제시한 방법이외에도 다양한 방법으로 원하는 곳의 주소를 찾을 수 있다. 상황에 따라 적절한 방법을 이용하여 원하는 위치로 이동하는 것에 익숙해질 수 있도록 해야한다.
4. "Hello World!" 문자열 패치
이제 본격적으로 Hello World 프로그램의 내용물을 바꿔보도록 하겠다. 책에서 제시한 대로 아래와 같은 두 가지 방법을 생각해 볼 수 있다.
(1) 문자열 변경
위 코드를 보면 알 수 있듯이, "Hello Word!"라는 문자열이 0FE211C라는 주소에 있음을 알 수 있다. Dump창에서 Ctrl+G를 통해 0FE211C로 이동해보면 다음과 같은 창을 확인할 수 있다.
원하는 영역만큼 드래그 하여 Ctrl+E(Edit)을 이용하여 내용을 다음과 같이 수정해보았다.
F9를 통해 프로그램을 실행시켜보자.
(2) 다른 메모리에 문자열을 추가하고 해당 주소를 push하도록 변경
위 첨부 사진에서 00FE213C영역에는 빈 공간이 있음을 알 수 있다. 여기에 변경하고 싶은 문자열을 추가하고 해당 문자열의 주소를 main 함수에서 push 하는 방식을 이용할 수도 있다.
F9를 통해 프로그램을 실행시켜보자.
위와 같이 정상적으로 패치가 이뤄졌음을 확인할 수 있다.
반응형'Reverse Engineering' 카테고리의 다른 글
[리버싱 핵심원리 study] 8장 abex' crackme#2 분석(1) (1) 2020.12.02 [리버싱 핵심원리 study] 7장 Stack Frame (0) 2020.12.01 [dreamhack.io study] x64dbg로 hello world 디버깅해보기 (0) 2020.11.26 [리버싱 핵심원리 study] 6장 abex' crackme #1 분석 (0) 2020.11.25 Debugging Tools (0) 2020.11.20