발자취

[Reverse Engineering] #07-3. patch 풀이 본문

Dreamhack Study/Reverse Engineering

[Reverse Engineering] #07-3. patch 풀이

해린 2024. 7. 1. 01:41

본 게시물은 Dreamhack의 Reverse Engineering 로드맵 과정을 학습한 기록이다.

 

#01. 서론

1. 서론

https://dreamhack.io/wargame/challenges/49/

위 링크의 워게임을 풀이한다.

 

이 문제의 프로그램은 플래그를 이미지로 출력해 주지만, 일부가 가려져 있어 확인할 수 없는 상태다.

플래그를 그리는 루틴을 분석하여 가려진 플래그를 알아내보도록 하겠다.

 

 

#02. 실행

1. 파일 실행

이 프로그램은 GUI 프로그램이므로 프로그램 아이콘을 더블클릭하여 바로 실행할 수 있다.

프로그램을 실행해보면 위와 같은 이미지가 나타난다.

플래그 부분이 마스킹 처리되어 있어 내용을 확인할 수 없다.

 

따라서 이 프로그램을 직접 패치해서 선을 그리는 찾아 제거하도록 할 것이다.

 

 

#03. 정적 분석

1. IDA로 파일 열기

"OK"

(다크 모드가 눈에 익지 않아서 화이트 모드 테마로 변경해 줬다 ^_^)

 

 

2. WinMain 함수 찾기

Patch 문제는 WinAPI를 이용하여 만들어진 GUI 프로그램이므로, WinMain 함수를 찾아야 한다.

WinMain 함수에서는 보통 윈도우를 생성하고 관련된 초기화 작업을 한다. 따라서 이와 관련된 API를 상호참조하는 방식으로 찾을 수 있다.

 

IDA가 자동으로 WinMain으로 찾아주지만 이번에는 함수 상호 참조를 이용해 찾아보도록 하겠다.

프로그램이 DLL로부터 임포트해 사용하는 함수의 목록은 기본 IDA 화면에서 Import 탭에 존재한다.

 

보통 윈도우를 생성할 때 사용하는 함수는 CreateWindowExW이다. 더블클릭하여 함수가 임포트 되는 곳으로 가보도록 하겠다.

 

CreateWindowExW 함수가 임포트되는 위치이다.

 

단축키 X로 CreateWindowExW 함수가 사용되는 곳을 확인할 수 있다.

WinMain 함수에서 사용되고 있다.

 

 

3. WinMain 함수 분석

위 Xref 화면에서 "OK"를 누른 후 단축키 F5를 사용하여 WinMain을 디컴파일했다.

23번 줄에 있는 RegisterClassExW 함수가 윈도우를 클래스를 등록하는 함수이고, 인자로 v11 변수가 들어가고 있는 것을 확인할 수 있다. 

 

여기서 가장 중요한 부분은 윈도우의 메시지 콜백을 설정하는 부분인 14번째 줄이다.

보통 메시지 콜백 함수에서 윈도우의 동작이 정의되어 있기 때문에 sub_1400032F0 함수를 분석해 어떤 동작을 수행하는지 알아야 한다고 한다!

 

WinAPI에 익숙하지 않아 좀 더 관련 내용을 찾아보았다.

🙋🏻‍♀️ 메시지 콜백 함수를 찾는 방법 🙋🏻‍♀️

우선 WinAPI의 'WinMain' 함수에서 주로 윈도우 클래스의 'WNDCLASS' 또는 'WNDCLASSEXW' 구조체를 사용하여 윈도우 프로시저(콜백 함수)를 설정한다는 점을 알아야 한다.

위 코드에서는 변수 v11가 'WNDCLASSEXW' 타입을 가진다.
MSDN에 'WNDCLASSEXW'를 검색해 보면,
lpfnWndProc

형식: WNDPROC

창 프로시저에 대한 포인터입니다. CallWindowProc 함수를 사용하여 창 프로시저를 호출해야 합니다. 자세한 내용은 WindowProc을 참조하세요.​
위와 같이 lpfnWndProc 멤버가 정의되고 있는 것을 확인할 수 있다.

WNDPROC은 윈도우 프로시저(콜백 함수)에 대한 포인터를 정의하는 타입이기 때문에, 14번째 라인이 메시지 콜백 함수를 등록하는 라인이라는 것을 알 수 있다.

 

 

4. WinMain 함수 분석

디컴파일된 sub_1400032F0 함수이다.

switch case 구문 내에 총 세 개의 case가 존재한다.

 

간단히 코드를 분석해 보았다.

case 2u:
[11] PostQuitMessage(0): 애플리케이션 종료 메시지를 게시
[12] 처리 결과로 0을 반환한다.

case 0xFu:
Paint와 관련된 역할을 한다.
[15] BeginPaint(): 페인팅 시작
[16] 그래픽 객체 생성
[34] 그래픽 객체 삭제
[37] EndPaint(): 페인팅 종료

case 0x202u: 
[41] 윈도우의 클라이언트 영역 무효화해 다시 그리게 함

 

→ BeginPaint 함수와 EndPaint 함수 사이에서 플래그를 출력해 줄 것이기 때문에 중간에 있는 sub_140002C40 함수를 분석하면 플래그를 그리는 루틴을 알 수 있을 것이다.

 

디컴파일된 sub_140002C40 함수의 일부이다.

51번째 줄부터 75번째 줄까지 모두 sub_140002B80 함수를 호출하고, 그 아래부터는 다른 함수들이 호출된다.

아직 함수를 분석해보진 않았지만, 연속적으로 호출되는 sub_140002B80 함수는 무언가 반복적인 형태를 그리는 것으로 추측해볼 수 있고, 다른 함수들은 다른 형태의 그림을 하나씩 그리는 것으로 추측할 수 있다.

 

디컴파일된 sub_140002B80 함수이다.

[13] 펜 생성

[16] 선을 하나 그림

 

함수 비교를 위해 sub_140002B80 함수 이후에 호출된 sub_1400017A0 함수를 분석해 보겠다.

디컴파일된 sub_1400017A0 함수의 일부이다.

sub_140002B80와 다르게 펜을 생성한 뒤, 여러개의 선을 그리고 있는 것을 확인할 수 있다. 이 부분이 글자를 하나씩 그리는 부분이라고 추측할 수 있다.

 

 

#04. 동적 분석

💎 IDA의 단축키 정리 💎

1. BreakPoint(F2): 중단점 설정
2. Restart(Ctrl + F2): 디버깅 중단
3. Run(F9): 프로그램 계속 실행, 혹은 디버깅 시작
4. Step Into(F7): 어셈블리 코드 한 줄 실행. 함수의 호출이라면 함수 내부로 진입
5. Step Over(F8): 어셈블리 코드를 한 줄 실행. 함수 내부로 진입하지 않음!

1. 메시지 콜백 함수 디버깅

sub_140002B80 함수를 호출하면 어떤 일이 발생하는지 직접 확인하기 위해 브레이크 포인트를 걸고 디버깅을 진행해 보겠다.

 

sub_1400032F0에서 sub_140002B80를 처음 호출하는 부분에 단축키 F2로 브레이크 포인트를 걸고, F9를 눌러 실행해 보았다.

 

이런 창이 뜨길래 'Local Windows debugger'를 체크해 보았다.

 

아무튼 F8을 눌러 해당 함수를 실행해 보니, 위와 같은 선이 생겼다.

 

한 번 더 F8을 눌러보았더니 위와 같은 선이 그려졌다.

따라서 이를 통해 sub_140002B80 함수는 플래그를 가리는 선을 그리는 함수라는 것을 알 수 있다.

 

 

 

#05. 바이너리 패치

1. 함수 패치

앞선 과정을 통해 sub_140002B80 함수가 플래그를 가리는 선이라는 것을 알게 되었기 때문에 이 함수를 패치해서 플래그를 알아낼 수 있도록 해보겠다.

 

함수 패치에 대한 기능이 모여있는 Edit > Patch Program 메뉴의 기능을 이용하여 간단하게 함수를 패치해 보도록 하겠다. 이 중 어셈블리 인스트럭션을 패치하기 위해 사용할 기능은 Assemble 기능이다.

 

단축키 g를 이용하여 선을 그리는 함수인 sub_140002B80 함수로 이동한다. (이동할 주소에 140002B80을 입력해 주면 된다) 그리고 어셈블리 화면에서 첫 번째 인스트럭션에 커서를 올린 뒤 Edit > Patch Program > Assemble... 메뉴를 클릭하면 인스트럭션을 입력할 수 있는 창이 뜬다.

 

아무튼 이 함수가 선을 그리지 않고 그대로 반환하도록 패치해야 하므로 인스트럭션 입력 칸에 함수를 바로 리턴하도록 ret 인스트럭션을 입력한다.

 

적용된 모습이다.

 

패치한 내용을 실제 바이너리에 적용하기 위해 Edit > Patch Program > Apply patches to input file... 메뉴를 클릭한다. 아무것도 변경하지 않고 바로 OK를 눌러주면 된다.

 

 

#06. 플래그 인증

1. 플래그 인증

이제 프로그램을 다시 더블클릭하여 실행해 보면, 바이너리 패치가 적용되어 플래그 값이 정상적으로 보이는 것을 확인할 수 있다!

 

워게임 페이지에 위 플래그를 그대로 입력하면

 

성공이다!

 

💎 IDA 단축키 정리 2 💎

함수/주소 이동 (g): 입력한 함수, 주소로 이동
상호참조 (x): 함수, 변수를 사용하는 곳을 찾기
브레이크 포인트 (F2): 디버깅 시 중단점을 설정
Step Over (F8): 디버깅 시 인스트럭션 하나를 실행
실행 (F9): 바이너리를 실행
Edit - Patch Program: 바이너리 패치와 관련된 메뉴가 존재

 


IDA를 이용한 바이너리 패치는 처음이라 풀이하는 과정에서는 조금 어려웠지만,

바이너리 패치하는 방법에 확실히 이해하게 되었다!

 

 

 

참고

https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/ns-winuser-wndclassexw

 

WNDCLASSEXW(winuser.h) - Win32 apps

창 클래스 정보를 포함합니다. (유니코드)

learn.microsoft.com