본문 바로가기

RVS

Reversing.kr 9번 문제(Ransomware)

문제 분석


Reversing.kr 9번 문제는 (그림 1)과 같이 세 개의 파일이 제공된다.

먼저, readme.txt 파일을 살펴보자.

그림 1

 

(그림 2)의 readme.txt 파일을 통해 파일을 복호화하라는 내용을 확인할 수 있다.

아직, readme.txt 파일만으로는 감이 오지 않는다. 실행파일 run.exe 파일을 실행해보자.

 

그림 2

 

run.exe 파일을 실행하면 (그림 3)과 같이 Key 값을 입력받은 후, Key를 통해 파일을 복구했다고 한다.

즉, 이 프로그램은 위 (그림 1)에서 'file'이라는 이름을 가진 파일을 run.exe 프로그램 알고리즘을 통해 복호화할 수 있다.

이 때, 옳은 Key 값이 아닌 경우 파일이 정상적으로 복호화되지 않는다.

 

그림 3

우리가 해결해야하는 문제는 다음과 같다. 

1. run.exe 프로그램 분석을 통한 복호화 절차

2. 키 값 획득

 

run.exe 프로그램 디버깅을 통해 분석하기 이전에 run.exe 파일은 UPX 방식으로 패킹되어 있다.

이 글에서는 패킹 파일을 언패킹하는 과정을 다루지 않는다.

다만, 아래 포스터에서 UPX Manual Unpacking 방식을 통해 run.exe 프로그램을 언패킹하는 과정에 대해 자세히 설명한다.

 

 

https://forensic-wetware.tistory.com/7

 

 

 

run.exe 프로그램 알고리즘 분석


언패킹된 run.exe 프로그램을 디버깅해보자.

run.exe 프로그램은 대략 file 파일을 읽어와 입력한 키 값으로 file 파일을 복호화하는 방식이다.

그렇다면, 먼저 file을 읽는 부분을 찾아야겠다.

 

(그림 4)는 file 파일의 데이터를 바이트 단위로 읽어 메모리에 저장하는 반복문이다.

0044A870 주소의 getc 함수는 파일 스트림에서 한 문자를 읽는 동작을 수행하는 함수다.

따라서, 0044A870 주소를 실행하면 EAX 레지스터에 file 파일 스트림의 문자가 세팅되는 것을 확인할 수 있다.

그림 4

 

(그림 5)는 file의 헥스 데이터이며, (그림 6)은 0044A870 주소의 getc 함수를 수행하고 난 후 세팅된 레지스터이다.

(그림 5)에서 볼 수 있듯이 file 파일의 첫 번째 헥스 값은 'DE'이다. 그리고 (그림 6)에서 0044A870 주소의 getc 함수가 수행되고 난 후 EAX 레지스터가 'DE'로 세팅된 것을 볼 수 있다.

그림 5
그림 6

그리고 아래 주소들을 좀 더 살펴보자.

(그림 4)의 0044A87C 주소에서 al 레지스터에 저장된 값을 [ecx+5415B8] 주소에 저장한다.

 

AL 레지스터는 EAX 레지스터의 부분이다. EAX (Extend Accumulator)는 32비트 크기의 레지스터인데, 아래의 (그림 7)처럼 EAX 레지스터는 AX 레지스터로 나눠지고, AX 레지스터는 AH와 AL 레지스터로 나눠진다. 즉, AX는 16비트 크기, AH와 AL은 8비트 크기의 레지스터이다.

 

본론으로 돌아와서 0044A87C 주소에서 AL 레지스터에 저장된 값은 즉 EAX에 세팅된 데이터 중 하위 8비트이다.

AL은 'DE' 문자이며, AL에 세팅된 'DE' 문자는 [ECX+5415B8] 주소에 저장된다.

 

그림 7

 

아래 (그림 8)은 [ECX+5415B8] 주소에 저장된 데이터이다. 'DE'부터 차례로 위 file의 헥스 값이 저장된 것을 볼 수 있다.

(그림 4)의 반복문은 file의 모든 헥스 값을 읽을때 까지 반복한다.

그러므로 반복문을 한번에 실행시켜주기 위해 반복문 다음의 0044A897 주소에서 [F2] 단축키를 통해 Breakpoint을 걸어두고 [F9] 단축키로 실행하자.

 

그림 8

 

그 뒤로 계속 디버깅을 수행하다보면, 아래 (그림 9)의 코드와 (그림 10)의 세팅된 레지스터와 같이 file의 헥스 값과 입력한 input 값을 계산하는 세 가지 흐름을 볼 수 있다.

 

1. (그림 9)의 0044A8B9 주소를 살펴보자. [edx+5415B8] 주소 값 한 바이트를 ECX 레지스터로 세팅한다.

[edx+5415B8] 주소 메모리에는 앞서 file의 헥스 값을 저장해주었으므로, (그림 10)에서와 같이 ECX에는 file의 첫 번째 바이트 'FFFFFFDE'가 세팅된 것을 확인할 수 있다.

 

2. (그림 9)의 0044A8C8 주소에서는 [edx+44D370] 주소 값 한바이트를 EDX 레지스터에 세팅한다.

[edx+44D370] 에는 KEY로 입력한 input 값인 'maam2'가 저장되어 있으므로 EDX 레지스터에는 'maam2'의 첫 번째 바이트인 'm' 이 저장된다.

 

3. (그림 9)의 0044A8CF 주소에서는 ECX와 EDX 레지스터 간의 XOR 연산을 수행한다. ECX 레지스터는 1에서 file 스트림 바이트인 'FFFFFFDE' 그리고 EDX 레지스터에는 KEY로 입력한 input 값의 첫 번째 바이트인 'm'이 세팅되어 있다.

즉, 'FFFFFFDE'와 'M' 문자의 헥스 값을 XOR 연산을 통해 계산한 후 ECX 레지스터에 저장한다.

 

 

그림 9
그림 10

 

 

XOR 연산을 통한 결과는 아래 (그림 13) 에서 볼 수 있듯이 ECX 레지스터에 세팅되었다 (FFFFFFB3).

(그림 11)의 0044A8D4에서 CL 레지스터 즉, ECX의 8비트 크기 값인 B3을 file 스트림 바이트가 저장되어 있는 주소인 [eax+5415B8]에 저장한다.

즉, 이전의 file 데이터를 XOR 계산이 수행된 값으로 대체한다. 

 

그림 11

다음 (그림 12)은 원래 'DE' 값이 었던 데이터가 'B3'으로 바뀐 결과이다.

 

그림 12

다시 위 (그림 11)을 보면 0044A8E2에서 바뀐 값인 'B3'가 저장된 [ecx+5415B8] 주소 값을 아래 (그림 13)에서와 같이 EDX 레지스터에 세팅한다.

그리고 (그림 11)의 0044A8E9에서 한 번 더 XOR 계산을 수행하는데 이번에는 'FF' 과 XOR 연산을 수행하여 EDX에 다시 저장한다. 아래 (그림 14)는 'FF'와 XOR 연산을 완료한 후 EDX 레지스터에 세팅이 완료된 것이다(FFFFFF4C). 

 

그림 13
그림 14

그리고 마찬가지로 다음 (그림 15)에서와 같이 0044A8F2 에서 EDX에 세팅된 값의 8비트 크기만큼(4C) 다시 한번 'B3'가 저장된 [ecx+5415B8] 주소 값을 덮어쓴다. 

 

그림 15

이 프로그램은 계속 이와 같은 방식으로 파일 스트림 바이트와 KEY 값 그리고 FF 값을 반복적으로 XOR 하여 기존의 파일 데이터를 덮어쓴다. 즉, 아래와 같은 알고리즘으로 파일을 복호화한다.

1. file[n] XOR KEY[m]

2. 1번째 결과 값 XOR '0xFF'

 

이 문제는 file을 복호화하는 것이다.

그렇다면 file 스트림 바이트를 가지고서 위의 1과 2 과정을 거꾸로 수행하면 되겠다.

 

1. file[n] XOR '0xFF'

2. 1번째 결과 값 XOR KEY[m]

 

 

 

키 값 구하기


 

실행 프로그램 디버깅을 통해 알고리즘 분석을 수행하였다. 

이번에는 키 정보를 획득해야한다.

다행히 readme.txt 파일에서 아래 (그림 16)과 같이 암호화된 파일이 exe 라는 힌트를 주었다.

 

그림 16

 

exe 확장자 파일은 PE 파일 구조로 구성되었다.

우선, HxD 프로그램을 통해 내 PC에 있는 exe 파일을 아무거나 열어보았다.

아래 (그림 17)처럼 exe 파일은 MZ 라는 시그니처로 시작하며, 여러가지 exe 프로그램을 열어보았을 때 0-32 길이의 헥스 값이 동일하였다.

 

 

그림 17

 

따라서, 파이썬 코드를 통해 exe 파일의 0-32 길이의 헥스값으로 계산해보았다.

아래 코드는 암호화된 파일 데이터와 '0xff' 값을 XOR 연산을 통해 계산한 후, exe 파일 데이터를 XOR 한다.

exe='4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00'
en_exe='DE C0 1B 8C 8C 93 9E 86 98 97 9A 8C 73 6C 9A 8B 34 8F 93 9E 86 9C 97 9A CC 8C 93 9A 8B 8C 8F 93'
flag =''

exe = exe.split(' ')
en_exe=en_exe.split(' ')

for i in range(len(exe)):
	flag += chr((int(en_exe[i], 16) ^ 0xff) ^ int(exe[i], 16))
print(flag)

 

위의 코드를 실행해보면 (그림 18)과 같이 'letsplaychess' 단어가 반복되는 것을 확인할 수 있다.

즉, 키 값은 'letsplaychess' 인 걸 알 수 있겠다.

그림 18

 

run.exe 프로그램을 실행해서 다음 (그림 19)와 같이 letsplaychess 키를 입력해주자.

그리고 file의 헥스 값을 확인해보자. (그림 20)은 file을 HxD을 통해 확인한 것이다. MZ 시그니처로 시작하여 정상적인 exe 파일 구조로 복호화 된 것처럼 보인다.

 

그림 19

 

그림 20

 

letsplaypress가 flag 값인가 싶어서 입력해보았지만, flag 값이 아니라고 한다.

file은 확장자가 없는 파일이지만 복호화된 file 파일은 현재 exe 파일 구조로 이뤄져있다.

file을 file.exe로 파일 이름을 변경하여 실행파일로 변경된 파일을 실행해보았다.

그러면 아래 (그림 21)처럼 'MSVCR100D.dll' 파일이 존재하지 않는다는 오류 창이 뜬다. 

 

그림 21

 

이 문제는 간단하게 해결할 수 있다. 구글링을 통해 'MSVCR100D.dll' 파일을 다운로드하여 'C:\Windows\SysWOW64\' 폴더 내에 파일을 이동시켜주면 된다(x64 PC인 경우).

그리고 다시 file.exe 프로그램을 실행시켜보자. 아래 (그림 22)와 같이 프로그램이 실행되었다.

Key를 획득했다!! 'Colle System'을 입력해주면 Flag를 획득할 수 있다.

 

 

그림 22

 

 

 

 

'RVS' 카테고리의 다른 글

Reversing.kr 11번 문제(Easy ELF)  (0) 2020.03.19
Reversing.kr 7번 문제 (Position)  (0) 2020.03.19
UPX Manual Unpacking  (0) 2020.03.12
Reversing.kr 2번 문제(Easy Keygen)  (0) 2020.03.11
Reversing.kr 4번 문제(Music Player)  (1) 2020.03.04