반응형

 

06.exe
0.28MB
patched_debug_06.exe
0.58MB

 

 


분석 1

 

 

확인 버튼이나 창 오른쪽 위에 있는 닫기 버튼을 누르면 닫히지 않고 카운트가 올라간다.

 


분석 2

 

 

x32dbg에 프로그램을 열면 위와 같이 EP 코드 부분에 pushad 명령어가 있다.

 

pushad ~ popad  구조는 UPX 패킹에서 봤던 부분인데

 

이번 문제도 UPX로 패킹이 되어 있나보다.

 

패킹을 푸는 데는 두 가지 방법이 있다.

1. UPX 툴을 이용해 언패킹 한다.

2. 직접 BP를 걸고 F9 키 또는 Ctrl + F8 키로 언패킹 한다.

 

1. UPX 툴을 이용해 언패킹

 

위와 같이 UPX(https://upx.github.io/)를 다운로드하여 툴을 이용해 언패킹한다.

 

 

2. 직접 BP를 걸고 F9 키 또는 Ctrl + F8 키로 언패킹 한다.

UPX 패킹은 특성 상 pushad 명령어와 popad 명령어 사이에 복호화 코드가 있다.

 

그러므로 스크롤을 쭉 내리다보면 4AF386 주소에 popad 명령어가 있는데 4AF386 주소에 BP를 걸고 F9 키를 눌러 실행하면 4AF386 주소에서 멈추면서 복호화가 완료된다.

 

그리고 4AF394 주소에서 417770 주소로 점프하는데 417770 주소가 진짜 EP 부분이다.

 

 

 

언패킹한 파일을 F9 키를 눌러 실행하면 위와 같이 분석 1에서 봤던 내용과는 다른 메시지 창이 뜬다.

 

이는 디버깅 중인지를 검사하는 IsDebuggerPresent() 함수가 코드 내에 있어서 다른 루트로 실행되어 위의 창이 뜨는 것이다.

 

 

Ctrl + F2를 눌러 재실행 한 후 F9 키를 눌러 EP 코드로 간 다음 x32dbg 내에서 모듈 간 호출 찾기 기능에서 Debug를 검색하면 위와 같이 문자열이 뜬다.

 

IsDebuggerPresent() 함수를 참조하는 40E961, 4189F0, 426997 주소에 BP를 걸고 F9 키를 눌러 실행한다.

 

 

그러면 40E961 주소에서 멈추는데 IsDebuggerPresent() 함수를 참조하는 주소 3개 중 두 번째에 해당하는 주소이다.

 

IsDebuggerPresent() 함수는 디버깅 중이라면 1을 반환하고 디버깅하고 있지 않다면 0을 반환한다.

 

그렇다면 현재 디버깅 중이므로 1이 반환 될 것이고, eax가 0인지 검사하는 test 명령에서 0이 아니므로 ZF 플래그는 0로 설정되며 jne 명령은 이전 명령어 test의 결과가 1이면 ZF 플래그가 0으로 설정되니 ZF 플래그가 0이면 수행되는 조건 분기문이므로 4338DE 주소로 점프할 것이다.

 

 

4338DE 주소에는 위와 같이 "This is a compiled ~~ " 문자열을 출력하는 부분이다.

 

 

40E967 주소의 명령어를 위와 같이 xor로 만들어 eax의 값을 0으로 만든다.

 

그러면 jne 명령어 이전 명령어의 결과가 0이므로 ZF가 1로 설정되고 그러면 jne 명령어는 실행되지 않는다.

 

패치된 내용을 저장하고 패치된 파일로 디버깅을 진행한다.

 

 

패치된 파일에서 F9 키를 눌러 실행하면 위와 같이 1을 띄운다.

 

 

프로그램을 실행하면 계속해서 메시지 창에 증가된 숫자가 나온다.

 

WinAPI 에서 메시지 창을 띄우는 함수는 MessageBox() 함수이므로 Ctrl + F2 키를 눌러 재실행 한 후 모듈 간 함수 호출에서 MessageBox를 검색하여 모든 MessageBox에 BP를 건다.

 

 

그리고 F9 키를 눌러 실행하면 위와 같이 45E071 주소에서 멈춘다.

 

 

그리고 이어서 F9 키를 누르면 위와 같이 메시지 창이 뜨는데 확인 버튼을 누르면 또 45E071 주소에서 멈춘다.

 

그렇다면 45E071 주소에서 호출하는 MessageBox() 함수를 유심히 봐야한다.

 

// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox
int MessageBox(
  [in, optional] HWND    hWnd,
  [in, optional] LPCTSTR lpText,
  [in, optional] LPCTSTR lpCaption,
  [in]           UINT    uType
);

 

MessageBox() 함수의 매개변수는 위와 같다.

 

그 중 lpText가 메시지 창에 들어갈 문자열 부분인데

 

 

위의 사진에서는 ebp의 값이 메시지 창에 들어갈 문자열이다.

 

덤프 창에서 ebp가 가리키는 주소를 따라가면 위와 같이 1의 ascii 코드값인 31이 들어가있다.

 

 


풀이 1

 

그냥 무지성으로 확인 버튼을 눌러댔다.

 

사실 오기가 생겨서 1000번까지 해보자 했는데 790에서 꺼졌다.

 

그렇다면 790을 해시화 하면 그 값이 답이라는 것이다.

 

https://www.convertstring.com/ko/Hash/MD5

 

 

790을 해시화 하면 2DACE78F80BC92E6D7493423D729448E이다.

 

해당 값이 답이라는 것이다.


풀이 2

 

 

45E071 주소에서 MessageBox 함수를 호출하는데 BP를 걸고 F9 키를 눌렀을 때 해당 BP에서 멈출 때마다 Hits 항목의 숫자도 올라간다.

 

즉, 45E071주소에 10번 멈추면 Hits의 수도 10이라는 것이다.

 

그렇다면 Hits의 수가 남은 날 수와 같다는 것이다.

 

 

MessageBox 함수 내부 코드를 보면 함수를 종료하기 전에 위와 같이 MessageBoxTimeout 함수가 있다.

 

MessageBoxTimeout 함수는 Windows API 문서에 기술되지 않은 함수로 user.dll 파일에 포함되어 있으며, 일정 시간이 지나면 스스로 사라지는 메세지 박스이다.

 

int MessageBoxTimeoutA(IN HWND hWnd, IN LPCSTR lpText, 
    IN LPCSTR lpCaption, IN UINT uType, 
    IN WORD wLanguageId, IN DWORD dwMilliseconds);
    
int MessageBoxTimeoutW(IN HWND hWnd, IN LPCWSTR lpText, 
    IN LPCWSTR lpCaption, IN UINT uType, 
    IN WORD wLanguageId, IN DWORD dwMilliseconds);
    
// 2 초간 창을 띄운다.
ex) MessageBoxTimeout(NULL, _T("띄우고 싶은 메세지"), _T("작업표시줄메세지"), uiFlags, 0, 2000)

 

함수의 정의는 위와 같다.

 

 

함수의 인자 부분 중 초 부분의 값을 1로 한다.

 

그러면 메세지 창이 떴다가 바로 꺼짐으로써 확인 버튼을 눌러주지 않아도 꺼지게 된다.

 

 

x32dbg 상단에 있는 메뉴 중 모듈 간 호출 찾기 기능에서 ExitProcess 함수를 찾는다.

 

 

그리고 위와 같이 BP를 걸고 F9 키를 누르고 있는다.

 

 

그러다가 ExitProcess() BP에서 멈추면 Hits 수가 몇인지 확인한다.

 

790을 MD5로 해시화 하면 답이다.

 


풀이 3

 

 

 

MessageBox 함수에 BP를 걸고 F9 키를 눌러 45E071 주소로 온 뒤 F8 키를 눌러 MessageBox 함수를 실행한다.

 

그러면 45E077 주소에서 멈추게 되는데 F8 키를 눌러 진행하다보면 45E0A6 주소에서 ret 명령이 수행되어

 

 

40BCC2 주소로 간 뒤 

 

40BCC4 주소에서 

 

 

40B21F 주소로 간다.

 

eax 레지스터의 값이 0인지 비교하는데 이 eax에는 40B21A 주소에서 호출한 40BC70 주소의 함수의 반환값이 들어있다.

 

40BC70 주소의 함수는 MessageBox() 함수를 호출하는 부분이 있는 함수이다.

 

 

스크롤을 조금 위로 올리다보면 위와 같이 je 조건 분기문이 많이 있다.

 

그리고 모든 조건 분기 문이 수행되지 않고 통과되면 40B170 주소에서 점프하여 40B187 주소에서 408C40 주소의 함수를 호출한다.

 

 

위와 같이 40B187 주소에 BP를 걸고 F9 키를 눌러 실행한다.

 

 

그러면 위와 같이 40B187 주소에서 멈추게 된다.

 

F7 키를 눌러 함수 내부로 들어간 뒤 

 

 

F8 키를 눌러 진행하면 위와 같이 408C5D 주소에서 408DFB 주소로 점프한다.

 

 

408DFB 주소로 점프한 뒤 F8 키를 눌러 진행하다보면 408E6A 주소에서 eax의 값에 1을 담고 조건 분기를 하는데 조건 분기가 되지 않으면 

 

 

 

위의 부분에 오게 되고 각 레지스터에 값이 설정된 후 조건 분기를 하는데 모두 수행되지 않고 통과되면

 

 

408F02 주소로 오게 된다.

 

ebp에는 316이 담겨있는데. eax의 값은 1이고, eax에 esi 레지스터가 가리키는 주소에 있는 값(메세지 창에 띄워질 다음 수)이 담긴다

 

그리고 408F13 주소에서 ebp와 eax를 비교한다.

 

즉, 현재 남은 날 수로 메세지 창에 출력됐던 수 + 1한 수와 ebp의 값을 비교하는 것이다.

 

 

316은 10진수로 790이다.

 

790을 MD5로 해시화 한 것이 답이다.

 

반응형

'전쟁 > codeengn' 카테고리의 다른 글

[codeengn] MobileApp Analysis L02  (0) 2022.10.31
[codeengn] MobileApp Analysis L01  (0) 2022.10.29
[codeengn] Advance RCE 05  (0) 2022.10.20
[codeengn] Advance RCE 04  (0) 2022.10.20
[codeengn] Advance RCE 03  (0) 2022.10.20

+ Recent posts