문제

"StolenByte를 구하시오 Ex) 75156A0068352040"


해결

 

실행결과는 위와 같다. Key file을 제시하라는 Dialog와 찾을 수 없다는 Dialog 2가지가 연속으로 나타난다. 우리 프로그램을 HXD로 확인을 해보면 UPX Header를 확인할 수 있다.

 

우선 Stolen bytes가 무엇인지 알아야 되겠다. Stolen(훔친) - byte(바이뚜) 인데, 직역을 하면 훔친 바이트이다. 그러니까 대충 가져간 byte라는 것인데.... 

 

UPX 같은 패커는 PE 파일의 공간 압축 등을 그 목적으로 프로그램이 실행될 때 여러 번의 루프를 돌면서 원래 있던 섹션과 IAT를 복구한다. UPX는 그 특성상 PUSHAD - [압축해제 코드] - [POPAD] - [JMP OEP]의 순서로 언패킹이 이루어지는데, 이때 POPAD와 JMP OEP사이에 PUSH 명령어 등을 통해서 워래 OEP부터 실행되어야 할 코드를 스택으로 빼돌리는 것을 Stolen byte라고 부른다.

 

UPX를 언패킹 한 실행결과를 보면 조금 이해가 빠를 듯하다.

 

??? 이상한 파라미터로 MessageBoxA가 실행된 듯하다. 하단 사진은 언패킹 된 파일의 EP부터 디버거 화면이다.

MessageBoxA의 함수 파라미터는 원래 다음과 같다.

int MessageBoxA(
  [in, optional] HWND   hWnd,
  [in, optional] LPCSTR lpText,
  [in, optional] LPCSTR lpCaption,
  [in]           UINT   uType
);

물론 OPTIONAL이긴 하지만, Text와 Cpation이 깨져서 들어갔고, 정상적으로 언패킹이 이루어지지 않았다고 볼 수 있다. 그럼 이제 stolen byte를 찾으러 패킹된 실행파일을 확인해보자 여러 번의 루프를 돌고 나서 마지막으로 OEP점프 이전 다음과 같은 PUSH 3개를 발견할 수 있다.

찾았다=. 훔친 코드의 길이는 0x0040736E ~ 0x00407379까지 총 12byte가 사라졌다. 정답의 양식이 "75156 A0068352040" 인 것을 미루어보아 OP Code를 쓰면 되는 거 같다. 

문제

"OEP를 구하시오 Ex) 00400000"


해결

프로그램은 계산기이다. OEP를 찾으라는 단순하고도 어려워보이는 문제이다. 일단 패킹되어있을것이 뻔하니 hxd를 돌려보자

UPX UNPACK하자

이제조금 마음이 편하다. PEVIEW를 통해서 IMAGE_OPTIONAL_HEADER를 들어가보자

응? 뭔가 미심쩍은 기분이 든다; 디버거를 돌려보자

다행이 맞는거 같다, 이 문제는 나중에 UPX 언패킹포스팅을 올리고 다시 쓰러오겠다. 아 정답은 ImageBase와 Address Of Entry Point를 더한 01012475이다.

문제

"컴퓨터 C 드라이브의 이름이 CodeEngn 일경우 시리얼이 생성될때 CodeEngn은 'ß어떤것'으로 변경되는가"


해결

프로그램은 단순하다. 한가지 UserForm을 받아서 판정하는 실행프로그램이다. 바로 디버거로 만나보자

MessageBoxA 파라미터의 Error!위쪽에 문제와 연관되는 함수가 보인다. 0x00401099에 GetVolumeInformationA라는 함수가 보이는데, API를 조금 보고오자 Fileapi.h에 정의되어 있는 함수다.

 

https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa

 

GetVolumeInformationA function (fileapi.h) - Win32 apps

Retrieves information about the file system and volume associated with the specified root directory.

docs.microsoft.com

BOOL GetVolumeInformationA(
  LPCSTR  lpRootPathName,		// root디렉토리를 가르키는 String이 있는 pointer
  LPSTR   lpVolumeNameBuffer,		// 지정된 볼륨의 이름을 저장하는 버퍼를 가르키는 pointer
  DWORD   nVolumeNameSize,		// volume name Buffer의 길이
  LPDWORD lpVolumeSerialNumber,	
  LPDWORD lpMaximumComponentLength,
  LPDWORD lpFileSystemFlags,
  LPSTR   lpFileSystemNameBuffer,
  DWORD   nFileSystemNameSize
);

적당히 주석도 달아보았다. 우리의 프로그램은 다음과 같이 동작한다.

 

그러니 강제로 0040225C에 CodeEngn을 넣어보자

마지막 비교분기(0x4010F7)에서 우리의 입력은 L2C-5781EqfgEngn4562-ABEX과 비교된다. 즉 CodeEngn은 EqfgEngn으로 변환된다.

문제

"Unpack을 한 후 Serial을 찾으시오. 정답인증은 OEP + Serial"


해결

PE파일을 hxd로 까보자

UPX문자열이 Section에 보이는것으로 UPX Packing되어있다는 걸 알 수 있다. UNPACK방법은 지난포스팅에도 올려두었으니 참고하자

2021.09.05 - [WarGame/CodeEngn] - [CodeEngn] 코드엔진 - Basic RCE 5 -

[CodeEngn] 코드엔진 - Basic RCE 5 -

문제 "이 프로그램의 등록키는 무엇인가" 해결 5번째문제에 왔다. 아직까지 문제가 7z압축에 exe들어있는 형태가 변하지는 않았다. 으흠; 위에 Unregistered는 Editable하지 않다. 아래 등록키를 crack하

tutoreducto.tistory.com

UNPACK을 한 PE를 우선 실행시켜보자

파일자체는 단순해 보인다. OEP를 찾기위해서 PEVIEW로 IMAGE_OPTIONAL_HEADER의 ImageBase와 Address Of Entry:

Point를 보자

그렇다. 상식적으로는 Image_base + Address of Entry Point로 0x00401360이 될텐데, 디버거를 켜보자

나이스 이제 Key를 찾아보자. MessageBoxA의 문자열 Wrong serial!!!을 참조하자

0x00422A30의 "AD46DFS547"을 발견할 수 있다. KEY형식에 따라 정답은 00401360AD46DFS547 이다.


UPX언패킹 방법을 기억은 하는데 가물가물하다. 정보보안이론카테고리에 언패킹방법을 따로 올려두어야 할 듯하다.

문제

"이 프로그램의 등록키는 무엇인가"


해결

5번째문제에 왔다. 아직까지 문제가 7z압축에 exe들어있는 형태가 변하지는 않았다.

으흠; 위에 Unregistered는 Editable하지 않다. 아래 등록키를 crack하는것이 이번 문제의 목표이다,.

잘못된 임의의 문자열을 입력하였을 때 MessageBoxA가 보인다. 문자열을 찾아가고 싶은데 아쉽게도 UPX패킹되어있다.

어쩐지 문자열찾기로 가져오는게 조금 느리더라 일단 언패킹을 하자 UPX를 다운받아 다음의 명령어로 UNPACK을 수행한다,.

  • C:$>upx -d 05.exe

UNPACK된 PE에서 디버깅을 해보자

문자열 잘 찾았다. 문자열로 GFX-754-IER-954가 보이긴 하는데, 입력해봐도 동작하지는 않는다. 이 문제는 위에 Unregistered...도 입력할 수 있는 UserForm이다.

 

0x00441014의 "Registered User"과 0x0044102C의 "GFX-754-IER-954"가 Auth Code가 된다. 

이제 패커가 사용되기 시작했다. 아직까지는 KEY까지 평문으로 사용되고 있는데, 계속 나아가자

문제

"이 프로그램은 디버거 프로그램을 탐지하는 기능을 갖고 있다. 디버거를 탐지하는 함수의 이름은 무엇인가"


해결

파일은 이전과 동일하다. 04.7z안에 04.exe가 들어있다.

실행파일은 이전 이뿌장한 GUI와는 다르게 무한루프를 통해서 "정상"이라는 문자열이 반복된다. 얘를 디버거에 붙여보자

다행스럽게도 디버거에 붙여도 별일은 일어나지 않는다. 문제또한 "정상"이라는 문자열을 찾으면 쉽게 해결된다. 위에 호출되는 함수명 IsDebuggerPresent가 함수명이다.

+ Recent posts