Easy Keygen
Reversing the serial routine and reimplementing it as a keygen that produces a valid serial for any name.
취미로 푸는 워게임 풀이기 때문에, 전문성이나 깊이 있는 이해도가 떨어질 수 있음. 개인 기록용으로 올리는 거기 때문에, 전문성을 원하는 거면 다른 보안 블로그의 풀이를 찾아보기 바람.
파일은 두 가지가 있다. 하나는 실행 파일이고 하나는 워게임의 instruction 을 담은 노트이다.
Reversing.kr 에서 Easy Keygen 문제 파일을 다운로드한 뒤, x32dbg 에서 실행 파일을 연다. 좌측 Symbols(또는 Modules/Functions) 창을 확인하면 main(또는 엔트리포인트 → main 으로 이어지는 함수)과 여러 DLL 함수들이 보인다. 이 문제의 목표는 시리얼 키에 맞는 네임을 확인하는 루틴 분석이므로, main(혹은 main 으로 추정되는 함수)을 더블클릭하여 디스어셈블리 뷰로 이동한다.
Strings(A2)를 열고 프로그램 실행 시 화면에 출력될 것 같은 문자열을 찾아 들어가면, 첫 번째로 input name 을 받고 어떠한 계산을 끝낸 후 밑에 input serial 을 받는 걸 볼 수 있다. 그 밑에서, 계산에서 만들어진 값을 시리얼 넘버와 비교한다.
그 사이 코드들을 분석해보면 입력한 이름을 한 글자(1 Byte)씩 이용해서 시리얼 번호를 생성하고, 입력한 이름의 길이만큼 반복문을 반복하는 것을 알 수 있다. 즉 프로그램이 실행되는 방법은:
이름 입력
→ 이름을 가지고 연산해 시리얼 키 생성
→ 시리얼 번호 입력
→ if (시리얼 넘버 == 생성된 값) → Correct
if (시리얼 넘버 != 생성된 값) → Wrong
좀 더 자세히 계산을 분석하기 위해 메모장에 어셈블리어를 붙였다.
위의 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진수 문자열로 누적하여 붙이는 역할을 한다.
이제 분석한 정보를 가지고 파이썬 코드를 짜서 네임을 얻을 수 있다. 아래처럼 어떠한 네임이 주어졌을 때 맞는 시리얼 넘버를 내놓도록 구현했다.
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 




