Reversing.kr - Easy_KeygenMe 풀기
/*
진짜 초보라 설명에 오류가 있거나
틀린 점이 있을수 있습니다..ㅠㅠ
열심히 공부해서 고쳐갈게요
*/
파일을 다운로드 하고 압축을 풀면 ReadME.txt파일이 있다. 내용은 다음과 같다.
Serial이 5B134977135E7D13일 때의 Name을 알아내라
구해야 하는 값을 알게 되었다.
프로그램 실행 시, 콘솔 창이 뜨면서, Name을 입력받고, Serial을 입력한다. 그리고 알맞은 값을 입력했나 판별한다.
문제 해결을 위해선 Name과 Serial의 관계를 알아야 한다.
일단 Ollydbg로 디버깅하자.
Ollydbg로 파일을 실행하고, 마우스 오른쪽 클릭 후 search for -> all referenced string메뉴로 들어가서
Serial Number를 입력하라는 문자열을 스택에 넣는 코드로 가본다
그러면 Serial Number와 Name의 관계를 찾을 수 있지 않을까?
Name 과 Serial Number는 분명히 어떠한 관계 속에 있고, 그 관계를 검증하는 방법을 알아내야 한다
(중간과정 생략)
.
.
.

명령어에서 Serial Number를 저장하고 있는 [ESP+10]의 주소와 의문의 문자열 [ESP+74] 주소를 레지스터에 넣어 반복문으로 같은지 비교하고 있다. 같고 다름에 따라 함수 호출을 위해 스택에 넣는 문자열이 달라진다.
아마 이 함수가 맞는 값을 입력했는지 알려주는 함수임에 틀림없다(breakpoint 잡고 직접 해보길 바래ㅁ)
같으면 "Correct!" 문자열을 출력하고, 같지 않으면 "Wrong" 문자열을 출력한다.
아마도 ESP+74에 있는 문자열은 입력한 Name이 재료가 되는 Serial Keygen 방식으로 만들어진 문자열일 것이다.

.
그럼 일단 Serial Keygen에 필요한 재료인 Name을 입력받는 곳으로 가보자.
00401059에 있는 CALL 004011A2이 Name을 입력받는 함수고 호출하고, 호출인자로 넣은 주소인 ESP+10가
입력받은 문자열을 저장할 부분이 될 것 같다.
이후엔 저장된 문자열의 길이를 구한다. >> 자주보이는 리버싱 패턴
만약 문자열 길이가 0이면 반복이 끝난 지점으로 보내버린다. 아마 문자열 입력받는 코드로 다시 가는 등
프로그램이 알아서 처리할것이다.
반복문(Keygen routine)
0040107C부터 보이는 루프가 Serial Keygen 루틴일 것이다
처음에는 ESI의 값이 3보다 크면, 값을 0으로 만들어버린다. 분명 무슨 역할을 할 것이다.
위 조건문을 통과하면, ECX에는 스택상에 있는 특정 값을 넣는다. 그런데 이때 ESI가 주소값에 영향을 준다.
EDX에는 아까 입력한 Name값의 주소를 넣어준다.
근데 여기에도 EBP값이 이에 영향을 미치게 된다(EBP를 변수처럼 사용. BASE POINTER아님).
아마 각각의 문자에 접근하려고 할 것 같다.
그러면, ECX에 들어갈 값, ESI+ESP+0C엔 뭐가 들어있을까...?

바이트 단위로 0x10, 0x20, 0x30 값이 차례로 들어 있다. 그뒤엔 아까 입력한 Name이 저장되어 있다.
반복문의 조금 뒤쪽을 보면, 반복할때 마다 ESI를 1 증가시켜주는 코드가 있다(004010AC)
ESI가 3 보다 크면 값을 0으로 만들어 준다는 내용과 종합해 보면, ECX에 들어가는 값은 차례대로 0x10, 0x20, 0x30뿐이고, 0x30값 후엔 다시 0x10값을 갖게 된다.
EDX에 넣은, Name값의 주소인 EBP+ESP+10도 마찬가지로, 뒤에 반복할때 마다 EBP가 1씩 증가하는 코드가 있다(004010A2)
즉, EDX의 값은 문자열의 인덱스와 같은 역할을 할 것이다.
.
.
.
그 뒤에는 XOR이 나온다.
첫 반복때엔 Name 맨 첫번째 값 0000 0041(16)과 0000 0010(16)값을 xor연산하여 ECX에 넣어둔다.
후에 함수가 하나 호출되는데, 매개변수를 보고 한번 맞춰보자 ㅎㅎ
스택에는 나중에 입력받을 Serial number와 비교하는 문자열인 ESP+74의 주소를 넣는다.
그 후, "%s%02X" 문자열 주소를 스택에 또 넣고 ESP+7C 주소도 넣는다. 이렇게 스택에 값을 넣어두고, 함수를 호출한다.
그러면 함수 매개변수가 전달되는 꼴은 " 함수명( ESP+7C , "%s%02x"문자열주소, dest주소, xor된 hex값) " 이렇게 될 것이다.
특정 주소에 문자열을 쓰는 함수이라는 것을 짐작할 수 있고, 아마 C언어의 sprintf 함수일 것이다.
아래는 sprintf함수의 원형이다
int sprintf (char *s, const char *template, ...)
sprintf함수의 첫번쨰 매개변수는 문자열 데이터를 쓸 주소
두번쨰 매개변수는 쓸 문자열(형식문자 포함)
나머지 가변 매개변수는 형식문자에 대응하는 변수들이다.
위처럼 하게 되면, 아마 반복될때마다 원래의 문자열은 %s로 유지되고, xor된 hex값이 2자리로 쓰여질 것이다.
즉 끝에다가 이번에 XOR한 값을 추가해준다.
문자열 길이를 구해 ECX에 넣고, 위에서 Name문자열의 순차적으로 증가하는 인덱스 역할을 할 EBP가 그보다 작으면 반복을 돈다.
아래는 Name을 ABCD로, 반복문을 다 돈 후의 ESP+7C주소의 dump

이렇게 값이 들어간다.
Serial Key 생성 루틴
반복문에서, 0x10, 0x20, 0x30값을 차례로 갖으며, 0x30값을 가진 후에는 다시 0x10값을 갖는 변수가 있다.
그리고, Name문자열을 스캔해서 차례대로 값을 갖는 변수가 있다.
변수는 문자의 ASCII 디코딩 값을 갖는다.
그렇다면, XOR역연산으로 우리에게 주어진 Serial Number값을 이에 해당하는 Name 값으로 바꾸면 된다

파이썬을 잘 못해서 대충 역연산을 해보니 저런 hex값이 나왔다. 저걸 ASCII코드로 encoding하면 된다.
Name : K3yg3nm3

-----------------------------------------
파이썬이 정말 좋은데 함수나 모듈에 대해 너무 모르는거같다ASCII변환..
공부해서 더 잘해졌으면 좋겠다 ㅎㅎ
그런데, 비교하는 루틴에 넣는 주소는 ESP+74고, 만들어진 Serial Key 주소는 ESP+7C이다..??