캡스톤 디자인 #8 코드엔진 Basic RCE L07~L10

llip·2022년 5월 18일
0

캡스톤 디자인

목록 보기
8/9

이전 게시글에서 이어진다.

남아있는 Basic RCE 문제 풀이를 진행해보려 한다.

https://ch.codeengn.com/
풀이를 진행할 문제 사이트.

https://github.com/codeengn/codeengn-challenges-writeups
해당 링크의 해설을 참고하여 풀이를 진행했다.


Basic RCE L07

7번 문제. 시리얼이 생성되는 경우를 잘 살펴보아야할 것 같다.

실행 화면

exe파일을 실행시켰을 때 나타나는 창이다.

문구를 그대로 입력해서 Check 버튼을 눌렀을 경우.
Error 창이 발생하며 프로그램이 꺼진다.

X32 dbg

실행하다보면 DialogBoxParamA 함수를 호출하면 실행시 뜨는 윈도우 창이 뜬다.
당연하게도 ExitProcess 함수를 호출하면 프로그램이 종료된다.

실행화면에서 스크롤을 내리다 보면 오늘도 주석이 열일을 한다.
주목할 부분은 Error! 부분과 well Done! 부분이다. 위는 오류, 아래는 정답인 경우 출력되는 스트링인듯 하다.

좀 더 윗부분을 보면 4562-ABEX, L2C-5781이라는 문구가 보인다. 아직 자세히는 모르겠지만 기억해두도록 하겠다.

GetDigItemTextA이라는 함수를 살펴보겠다.
해당 함수는 매개변수로 nID의 아이디를 갖는 컨트롤의 문자열을 받아, 두 번째 매개변수 rString에 대입해주는 함수이다.
nID는 텍스트를 얻고자 하는 컨트롤 번호를 명시한다. rString은 지정된 컨트롤의 문자열을 저장할 CString 형 변수의 이름을 적는다. 참조로 사용된다.
이 함수는 CString 변수에 저장된 문자열 길이를 반환한다.

http://www.tipssoft.com/bulletin/board.php?bo_table=FAQ&wr_id=49

GetDigItemTextA 함수 안에는 4개의 변수가 있다. 컨트롤이 들어있는 대화 상자의 핸들, 제목 도는 텍스트를 검색 할 컨트롤의 식별자, 입력받은 텍스트를 저장하는 부분, 입력받은 텍스트를 저장하는 부분이 가리키는 버퍼에 복사 할 문자열의 최대 길이 이다.
0040106C부터 함수를 호출하기까지 위 변수들의 순서의 역순으로 진행된다. 즉, 40106E의 주소는 입력받은 텍스트를 저장하는 부분을 나타낸다.
우리가 입력한 값은 402324로 향한 뒤 저장된다.

그리고 GetVolumeInformationA는 지정된 루트 디렉터리가 속한 파일 시스템 정의와 볼륨 정보를 가져오는 함수이다. 하드드라이브의 정보를 얻어오는 것이다.

BOOL GetVolumeInformationA(
In_opt LPCSTR lpRootPathName,
out_opt LPSTR lpVolumeNameBuffer,
In DWORD nVolumeNameSize,
out-opt LPDWORD lpVolumeSerialNumber,
out-opt LPDWORD lpMaximumComponentLength,
out-opt LPDWORD lpFileSystemFlags,
out-opt LPSTR lpFileSystemNameBuffer,
In DWORD nFileSystemNameSize
);

https://min-12.tistory.com/59

차례대로 볼륨의 루트 경로를 포함하는 문자열에 대한 포인터, 지정된 볼륨의 이름을 수신하는 버퍼에 대한 포인터, 볼륨이름 버퍼의 길이, 볼륨 일련 번호를 수신하는 변수에 대한 포인터, 지정된 파일 시스템이 지원하는 파일 이름 구성요소의 쵀대 길이를 받는 변수에 대한 포인터, 지정된 파일 시스템과 연관된 플래그를 수신하는 변수에 대한 포인터, 파일 시스템 이름 버퍼의 길이 이다.

이 문제는 드라이브에 관련된 문제이므로 드라이브의 이름에 집중해야한다고 한다. 두 번째 매개변수의 주소는 401092. 해당 명령어 부분을 보면... 40225C에 드라이브 이름이 저장되는 것 같다.

그리고, lstrcatA 함수는 한 문자열을 다른 문자열에 추가한다고 한다. 첫 번째 매개변수는 널 종료 문자열, 두 번째 매개변수는 저장된 문자여렝 추가될 널 종료 문자열이다.

코드를 살펴보면 4562-ABEX가 0040225C에 저장된다.

00401000과 00401099, 004010F7에 종단점을 걸고 돌리다보니, 다시 실행모드로 돌아왔을 때는 보이지 않던 문자열들이 보이게 되었다.

여기서 문제는... 중간에 F2를 눌렀다가 다시 실행했더니 ABEX 앞의 숫자가 바뀌었다.

쭉 진행하다보지 실시간으로 코멘트가 변동됐다.

완성된 문자열을 입력하니 맞았다고 한다.
종단점을 잘 걸어 실행하다보면 답이 나오는 문제였던 걸까?

c드라이브의 이름이 CodeEngn이라면 시리얼 키는 "L2C-5781EgfgEngn4562-ABEX"가 되는듯 하다.


Basic RCE L08

8번 문제는 OEP를 구하는 문제이다.

OEP란?

Original Entry Point의 약자로 패킹된 파일의 실제 프로그램 시작 부분이다.

엔트리 부분을 알아내면 되는 것 같다.


8번을 실행했을 때의 화면. 계산도 잘 된다.

PEView를 통해 열어봤을 때의 화면.
UPX가 보이는 걸로 보아, 패킹이 되어있는듯 하다.

언패킹 완료.


이리저리 구조체를 뒤적여보다가 IMAGE_OPTIONAL_HEADER에서 엔트리 주소를 알아냈다.

정답은 0012475.


Basic RCE L09

문제에서 말하는 StolenByte는 패킹된 프로그램에서 코드의 일부를 OEP로 점프하기 전 숨기는 것이라고 한다.

패킹을 풀 때 OEP를 찾아 덤프를 뜨는데, 이게 적용된 프로그램은 정상적으로 실행되지 않게끔 해준다. 언패킹을 방해하는 것이다.

https://brainfreeee.tistory.com/35

덤프는 컴퓨터 기억장치를 일부나 전부를 출력(복사)하는 것이다.
StolenByte가 언패킹 코드와 OEP 사이에 끼어서 덤프를 뜨기 때문에 OEP 이전에 있던 값이 스택에 push되지 않는 것이라고 한다.

실행하면 나타나는 창.

확인을 눌러 넘어온 창. 여기서 확인을 누르면 종료된다.
keyfile을 찾지 못하는 게 문제가 되는 것 같다.

PEView로 확인해보면 아니나 다를까 UPX로 패킹이 되어있다.


언패킹 완료.

09.exe를 그냥 실행하면 글자가 깨져있다. 언패킹을 하며 StolenByte가 방해한듯 하다.

x32 dbg로 09.exe를 열어주면 실행창의 코드 상단부가 nop으로 가득 차 있다. 이 부분이 정상적이지 않은 값으로 채워져있기에 메시지 박스의 글자가 깨진다고 한다. 12바이트가 비어 있다.
0040100C가 우선은 OEP인듯.


코멘트를 보면 정답일때, 맞는 키 파일이 아닐 때, 키 파일을 찾을 수 없을 때 3가지 경우로 나뉘는 것 같다.
abex.12c는 무엇인지 모르겠는데...

찾아보니 언패킹 전 프로그램과 비교해봐야 하는듯 하다.


언패킹 전 프로그램. popad라는 게 눈에 띈다.
이건 pushad로 저장한 레지스터를 복원할 때 사용한다고 한다.

잘 모르겠어서 참고해보니까, StolenByte는 OEP주소로 점프하기 전에 push된다고 한다. popad 뒤에 oep 주소로 점프하는 곳이 있다는데... 점프 후엔 바로 메시지 박스를 호출하는듯. (게시글을 참고했다. https://velog.io/@hamham/%EC%BD%94%EB%93%9C%EC%97%94%EC%A7%84-Basic-RCE-L09-%ED%92%80%EC%9D%B4 )

6A 00 68 00 20 40 00 68 12 20 40 00 이 코드들이 언패킹하면서 사라진듯 하다. 총 12바이트라고 한다.
nop으로 채워져있던 곳도 12바이트.
따라서 StolenByte 크기가 12바이트라고 한다.

정답은 6A 00 68 00 20 40 00 68 12 20 40 00이다.


Basic RCE L10

10번은 OEP를 구한 후 '등록성공'으로 가는 분기점의 OPCODE를 구하는 것이다. OEP+OPCODE를 구할 것.

10.exe를 실행하면 뜨는 메시지 박스이다.
Name과 Serial에는 아무것도 입력되지 않는다.

About을 누르면 나타나는 창.


PEiD로 확인해보니 ASPACK이 되어있다고 한다. 하는 법을 모르겠어서 검색하며 진행했다.

entrypoint에 pushad 문자열이 들어있다. 범용 레지스터에 저장된 값들을 스택에 저장하는 명령어이다.

popad를 검색해서 와보니, C로 리턴하는 걸 알 수 있다.

찾아보니 ASPACK을 손수 푸는 방법 중 하나가 ret C를 찾아 OEP를 찾는 것이라고 한다.

ret C에 bp를 걸고 f9로 실행했더니, 이렇게 OEP가 새겨졌다. 이 bp에서 f8을 누르면 OEP로 이동한다.

이동한 모습. OEP는 00445834가 된다.
여기서 상단 메뉴의 플러그인 - Scylla로 들어간다.

IAT Autosearch를 이용해 입력값을 자동으로 받아왔다. 이후 Get Imports - Dump - Fix Dump를 실행해준다.

이렇게 하면 언패킹이 완료된 것이다.

언패킹한 덤프파일을 열어 실행창으로 향한 모습. EntryPoint가 잘 잡혀있다.

문자열 검색을 통해 register을 검색해주었다.

해당 주소로 이동한 모습.
jne 점프문에 포함되어 있는 문자열이다. 그러므로 분기점의 OPCODE는 7555이다.

정답은 004458347555.

profile
공부중

0개의 댓글