문제확인


이번 문제는 독특하게도 Unlock Code가 존재한다. 문제를 실행 시켜서 About을 통해 확인을 해보았을 때 올바른 Unlock Code를 찾은 후에 진행을 해야 하는 것 같다.

The Serial-generation code in this crackme is obfuscated and there are no signatures this time.

After the Unlock Code has been found, type it in and it will de-obfuscate the serial generation code.

Then it should be straight forward.


Rules:

- No patching

- Find the correct unlock code

- Write a keygen

- Write a tutorial explaining how you solved this one and please include your code


i really look forward to seeing your solutions!



Unpacking - 1


Ollydbg를 통해서 문제를 열자마자 난해하게 되어 있다. 패킹이 되어 있는 것 같다. 이를 해제하기 위해선 그냥 단순하게 쭉 따라서 가도 괜찮지만  나는 그렇게 시간이 오래걸리는 방법을 선호하지는 않는다. 그렇기에 PE 구조도 최근에 공부한김에 이를 통해서 해보기로 했다.


우선 현재 EIP는 바로 저 부분으로 제대로 설정이 되어있다. 아래의 사진에서 보듯이 .text 영역은 흔히 Code 영역으로 실행에 쓰이는 Opcode들이 존재하고 있다. 이러한 .text 섹션의 시작 주소는 1000이다. 즉 ImageBase 까지 더한다고 생각하면 401000으로 이동을 해보자.


그 후 이 부분에 BP를 걸고 F9를 통해 진행을 할 경우 두번째 사진과 같이 패킹이 해제 되는 것을 확인 할 수가 있다. 이러한 방법 외에도 다양한 방법이 있는 것 같으니 직접 찾아보는 것을 추천드립니다.



Unpacking -2 


프로세스를 진행하다 보면 아래와 같이 2개의 호출문을 볼 수가 있다. 첫 번째 호출문은 Unlock Code를 가지고 어떠한 연산을 진행하는 부분이고, 두 번째 호출문은 0x7B 번 어떠한 연산을 진행하는 과정이다. 하나하나 살펴보자.


호출문 - 1

이 함수 내에는 Loop가 존재하는 이러한 반복문은 항상 수상히 여겨야 한다. 바로 내가 입력한 UnlockCode를 가져와서 연산을 진행한다. 연산에 대한 과정은 아래에 직접 타이핑한 것을 보면 어떻게 Loop가 진행하는지 충분히 이해를 할 수가 있다.

여기서 중요한 것은 바로 붉은 상자에 표시한 부분인데 저 부분이 최종적으로 나온 값이 저장되는 곳이다. 이 값은 후에 쓰이게 된다.

<Loop - 1 참고>


호출문 - 2

여기에는 위에서 나온 값을 통해 연산이 진행이 된다. 우선 lstrlen을 통해 Unlock Code의 길이가 1보다 큰지를 확인하고 만약 아니라면 바로 실패문을 출력을 한다. 이 부분을 넘어가면 바로 0040111C 에서부터 0040123C까지 이미 지정된 값을 위에서 나온 값과 XOR 연산을 진행하는 작업이다.

여기서 이 XOR에 쓰일 위의 값이 중요한 이유는 바로 감춰진 명령어들을 우리가 복구해야하기 때문이다.


특정한 값과 XOR연산이 진행된 후에 해당 주소의 값은 모두 변해 있다. 아래의 Dump 부분에 드래그 한 곳부터 나중에 호출이 되므로 이후에 참고하자.




Name을 통한 값 생성


위의 XOR 과정을 통해서 생성된 4011E8부분을 호출한다. 여기서 중요한 것은 결국 위의 XOR 값이 잘못된 값일 경우에는 이상한 명령어들로 복구시키므로 인하여 제대로 동작이 하지 않을 수가 있다. 즉 UnlockCode에 어떠한 값을 넣는지에 따라 전혀 다른 진행이 이루어 진다는 것이다.

처음에 나는 JMP문을 통해 어떠한 부분으로 가는 명령어들을 생성해야하는지 알고 삽질을 하였으나, 지인의 조언을 통하여 결국 새로운 함수를 호출하는 부분이므로 결국 그 함수에 진입을 하였을땐 스택프레임을 구성하는 작업이 이루어질것이라는 말이였다. 

즉 PUSH EBP; MOV EBP,ESP 가 이루어져야 하기에 위에서 4011E8의 코드를 55 8B EC에 초점을 맞추고 XOR 연산을 진행하였다. 그 결과 모두 0x25와 XOR을 진행했을 경우에 아래와 같이 정상적인 코드가 복구되는 것을 확인 할 수가 있다.


아래는 정상적으로 복구된 코드의 부분이다. 우선 GenerateSerial 이라고는 했지만 저 부분에서 최종 키 값이 형성이 되는 것이 아니라 그 최종 키 값 형성에 쓰이는 값을 형성하는 부분이므로 중요하다.


안을 들여다 보면 아래와 같이 Name을 통해 특정한 값을 생성한다. 구성은 아래의 Loop-2를 참고하면 조금 이해하기 편할 것 같다. 입력한 Name을 한 글자씩 읽은 다음에 Count 값과 같이 연산을 진행하는 구성이다. 



Serial 생성


위의 함수를 빠져나오면 바로 다시 새로운 Loop를 만나게 된다. 여기선 위에서 최종적으로 나온 값을 통해 Count와 연산을 진행하는 작업이 진행이 된다. 이 역시 자세한 구성은 아래의 Loop - 3을 참고하는 것이 편할 것이다.


그리고 성공문을 체크하는 곳으로 가면 아래와 같이 내가 입력한 Serial과 Name에 따라 생긴 Key 값이 한글자씩 비교가 되는 부분을 확인 할 수가 있다.



느낀점


이번 문제를 풀면서 역시 자살충동이 솟아났다. 도저히 혼자서 jmp문을 고집했다면 죽어도 못풀문제였다. 이번에 확실히 느낀건 여러 문제나 파일을 접하면서 직접 많이 해보는 것이 가장 좋은 방법같다. 앞으론 패킹이 되어있는 파일이 언패킹되는 과정을 좀더 유심히 보게 될것 같다.




'Reversing > CodeEngn' 카테고리의 다른 글

CodeEngn Advance 02  (0) 2015.07.30
CodeEngn Advance 14  (0) 2015.07.24
CodeEngn Advance 12  (1) 2015.07.22
CodeEngn Advance 11  (0) 2015.07.17
CodeEngn Advance 10  (0) 2015.07.13