본문 바로가기

리버싱

Reversing.kr Easy Keygen 문제 풀이

<분석>

파일은 두 가지가 제공된다.

파일 두가지

ReadMe의 내용은 다음과 같다.

ReversingKr KeygenMe


Find the Name when the Serial is 5B134977135E7D13

파일을 실행했을 때 두 가지를 물어본다. (이름과 시리얼 번호)

파일 실행 화면

x64dbg로 디버깅해 보자.

EntryPoint 화면

EntryPoint 부근의 코드는 위와 같다.

프로그램에서 상용되는 문자열

문자열 참조를 통해 보면 입력할 때 사용하는 문자열들인 "Input Name: "과 "Input Serial" 문자가 보인다.

첫번째 입력을 받는 부분
두번째 입력을 받는 부분

그 밑에는 비교한 결과에 따라 맞는지 틀렸는지를 출력하는 코드가 있다.

결과 출력

입력한 이름을 가지고 시리얼 번호를 생성하여 입력한 시리얼 번호와 일치하는 지를 확인하는 구조이다.

프로그램 순서도

문제에서 구해야 하는 것은 ReadMe에 적혀있는 시리얼 번호 5B134977135E7D13에 대해서,

이 시리얼 번호를 만든 이름 입력값은 무엇일지 유추하라는 것이다.

그럼 코드상에서 이름을 가지고 시리얼 번호를 어떻게 만드는지를 분석하면 된다.


<시리얼 번호 생성하는 방법 분석>

시리얼 번호 생성하는 코드

첫번째 입력 이후에 시리얼 번호를 생성하는 부분은 위와 같다.

입력한 이름을 한 글자(1 Byte)씩 이용해서 시리얼 번호를 생성하고, 입력한 이름의 길이만큼 반복문을 반복한다.

반복문의  시작과 끝 역시 주석으로 표시해 뒀다.

 

상세히 분석해 보자.

0040105E | 8D7C24 18                | lea edi,dword ptr ss:[esp+18]           | edi:EntryPoint
00401062 | 83C9 FF                  | or ecx,FFFFFFFF                         | ecx:EntryPoint
00401065 | 33C0                     | xor eax,eax                             |
00401067 | 83C4 08                  | add esp,8                               |
0040106A | 33ED                     | xor ebp,ebp                             |
0040106C | 33F6                     | xor esi,esi                             | esi:EntryPoint
0040106E | F2:AE                    | repne scasb                             |
00401070 | F7D1                     | not ecx                                 | ecx:EntryPoint
00401072 | 49                       | dec ecx                                 | ecx:EntryPoint
00401073 | 85C9                     | test ecx,ecx                            | ecx:EntryPoint
00401075 | 7E 3F                    | jle easy keygen.4010B6                  |
00401077 | 83FE 03                  | cmp esi,3                               | 반복문 시작

첫 번째 입력 후 반복문 시작할 때까지의 부분이다.

edi에 입력한 이름의 주소를 넣고, 이름의 길이를 재서 반복문을 준비한다.

00401077 | 83FE 03                  | cmp esi,3                               | 반복문 시작
0040107A | 7C 02                    | jl easy keygen.40107E                   |
0040107C | 33F6                     | xor esi,esi                             |
0040107E | 0FBE4C34 0C              | movsx ecx,byte ptr ss:[esp+esi+C]       |
00401083 | 0FBE542C 10              | movsx edx,byte ptr ss:[esp+ebp+10]      | 입력 문자
00401088 | 33CA                     | xor ecx,edx                             |
0040108A | 8D4424 74                | lea eax,dword ptr ss:[esp+74]           |
0040108E | 51                       | push ecx                                |
0040108F | 50                       | push eax                                |
00401090 | 8D4C24 7C                | lea ecx,dword ptr ss:[esp+7C]           |
00401094 | 68 54804000              | push easy keygen.408054                 | 408054:"%s%02X"
00401099 | 51                       | push ecx                                |
0040109A | E8 B1000000              | call easy keygen.401150                 |
0040109F | 83C4 10                  | add esp,10                              |
004010A2 | 45                       | inc ebp                                 |
004010A3 | 8D7C24 10                | lea edi,dword ptr ss:[esp+10]           |
004010A7 | 83C9 FF                  | or ecx,FFFFFFFF                         |
004010AA | 33C0                     | xor eax,eax                             |
004010AC | 46                       | inc esi                                 |
004010AD | F2:AE                    | repne scasb                             |
004010AF | F7D1                     | not ecx                                 |
004010B1 | 49                       | dec ecx                                 |
004010B2 | 3BE9                     | cmp ebp,ecx                             |
004010B4 | 7C C1                    | jl easy keygen.401077                   | 반복문 끝

esp+esi+C 주소 -> 0x0019FE04

esp+esi+C

esp+ebp+10 주소

esp+ebp+10

입력한 문자열(이름)의 한 바이트씩 XOR 연산을 하는데, 0x10 0x20 0x30을 돌아가면서 사용한다.

즉, 첫 번째 문자 XOR 0x10, 두 번째 문자 XOR 0x20, 세 번째 문자 XOR 0x30, 네 번째 문자 XOR 0x10 ...

이런 식이다.

 

계속 디버깅을 해보자.

call easy keygen.401150 이 함수를 집중적으로 보면,

0040108E | 51                       | push ecx                                |
0040108F | 50                       | push eax                                |
00401090 | 8D4C24 7C                | lea ecx,dword ptr ss:[esp+7C]           |
00401094 | 68 54804000              | push easy keygen.408054                 | 408054:"%s%02X"
00401099 | 51                       | push ecx                                |
0040109A | E8 B1000000              | call easy keygen.401150                 |

4개의 인수가 들어간다.

첫 번째는 XOR 한 값

두 번째는 0x19FE6C

세 번째는 "%s%02X"

네 번째도 0x19FE6C

 

이 함수가 실행된 후, 0x19FE6C 주소에 시리얼 넘버가 쓰인다.

 

그 뒷부분은 루프문을 위한 부분들이다.

 

결국 시리얼 번호를 만드는 방법은

입력한 문자열과 특정 16진수와의 XOR

연산이다. ( 0x10, 0x20, 0x30 )


<해결>

모든 분석을 끝냈다.

이제 분석한 내용을 가지고 문제를 풀면 된다.

다음 파이썬 코드를 작성해 문제를 해결했다.

serial = '5B134977135E7D13'

xorValue = ['10', '20', '30']

iRange = len(serial) // 2
xorIndex = 0
resultString = ''

for i in range(iRange):
    s = serial[i*2:i*2+2]
    s = int(s, 16)
    xV = int(xorValue[xorIndex], 16)
    # print(s, xV)
    result = s ^ xV
    resultString += chr(result)
    
    xorIndex = (xorIndex + 1) % 3


print(resultString)

코드를 더 간단히 짜지 못한 게 좀 아쉽다. 하지만 결과는 잘 나온다.

✨문제해결완료