EASY KEYGEN

Reversing the serial routine and reimplementing it as a keygen that produces a valid serial for any name.

2026.08.18 Reversing original post

** 취미로 푸는 워게임 풀이기 때문에, 전문성이나 깊이있는 이해도가 떨어 질수있음. 개인기록용으로 올리는거기 때문 에, 전문성을 원하는거면 다른 보안 블로그의 풀이를 찾아보기 바람.

파일은 두가지가 있다. 하나는 실행 파일이고 하나는 워게임의 instruction 을 담은 노트이다.

Figure 1

Figure 2

Reversing.kr에서 Easy Keygen 문제 파일을 다운로드한 뒤, x32dbg에서 실행 파일을 연다. 좌측 Symbols(또는 Modules/Functions) 창을 확인하면 main(또는 엔트리포인트 → main으로 이어지는 함수)과 여러 DLL 함수들이 보인 다. 이 문제의 목표는 시리얼 키의 맞는 네임을 확인하는 루틴 분석이므로, main(혹은 main으로 추정되는 함수)을 더블클 릭하여 디스어셈블리 뷰로 이동한다.

Figure 3

Figure 4

Strings(A2)를 열고 프로그램 실행 시 화면에 출력될 것 같은 문자열을 찾아 들어가면, 첫번째로 input name 을 받고 어 떠한 계산을 끝넨후 밑에 input serial 을 받는걸 볼수있다. 그 밑에서, 계산에서 만들어진 값과 비교해서, 값을 시리얼 넘 버와 비교한다. ** 그 사이 코드들은 분석해보면 입력한 이름을 한 글자(1 Byte)씩 이용해서 시리얼 번호를 생성하고, 입 력한 이름의 길이만큼 반복문을 반복하는것을 알수있다.

즉 프로 그램이 실행되는 방법은: 이름 입력 —> 이름을 가지고 연산해 시리얼 키 생성 —> 시리얼 번호 입력 —> if(시리얼 넘버 == 네임) —> correct if(시리얼 넘버 != 네임) —> wrong

좀 더 자세히 계산을 분석하기 위해 메모장에 어셈블리어를 붙였다.

Figure 5

위에 3개 줄을 보면 력한 문자열(이름)의 한 바이트씩 XOR 연산을 하는데, 0x10, 0x20, 0x30을 돌아가면서 사용하는걸 알수있다. 계속 어셈블리어를 디버깅해보자. call easy_keygen.401150 이 함수를 집중적으로 보면,

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

easy_keygen.401150 함수는 sprintf 계열 함수로, 기존 시리얼 문자열(0x19FE6C)에 XOR 결과값을 %02X 형식의 16 진수 문자열로 누적하여 붙이는 역할을 한다.

이제 분석한 정보를 가지고 파이썬 코드를 짜서 네임을 얻을 수 있다. 아래처럼 어떠한 네임이 주어졌을 때 맞는 시리얼 넘버를 내놓도록 구현했다.

Figure 6

aaaa 를 줘서 루프를 돌렸을때 시리얼 키 값이 71415171 나오는 것을 알수있다. 이러한 것들을 반복해본다. 그럼 aaaaaaaa 는 7141517141517141, 그리고 abcd 는 71425374 나오는걸 알수있다. 이러한 정보들을 같고 gemini 를 돌려보면 이러한 코드를 얻을수있다:

def serial_to_name(serial_hex: str) -> str:
serial_hex = serial_hex.strip()
if len(serial_hex) % 2 != 0:

raise ValueError(“Invalid serial length (must be even number of hex chars).”)

key = [0x10, 0x20, 0x30]
out = []
for i in range(0, len(serial_hex), 2):
b = int(serial_hex[i:i+2], 16)
k = key[(i // 2) % 3]

out.append(chr(b ^ k)) return "".join(out)

시리얼: 5B134977135E7D13 를 위 로직으로 풀면:

Name = K3yg3nm3