본문으로 바로가기

[keygen] FSC_Level1 writeup, 풀이

category Reversing/Keygen 2018. 7. 8. 22:23

첫 keygen 문제 풀이를 시작하기에 앞서...


keygen 문제 풀이에 대해 많은 시선(?), 견해(?)가 있다.

keygen 문제 풀이가 과연... 리버싱 공부에 도움이 되는지, 되지 않는지에 대해....


필자는 keygen 문제 풀이 방식에 따라 도움이 될 수도..? 되지 않을수도 있다고 생각한다.

따라서 도움이 되는 방식으로 여러 각도에서 간간히 keygen 문제 풀이를 진행하려고 한다.


필자가 문제풀이를 하는 방식에 많은 견해가 있을 수 있을텐데... 의견 공유는 환영입니다.


앞으로의 풀이 및 FSC_Level series는 "리버스 엔지니어링 바이블"의 keygen을 참고하였습니다. 

 

FSC_Level1



우선 FSC_level1.exe가 어떤 프로그램인지 알기 위해 프로그램을 실행시켰다.

프로그램을 시키는 아래와 같은 화면이 나오고 key를 입력해야함을 알 수 있다.

간단히 실험하기 위해 key에 아무런 string을 입력했는데 key가 올바르지 않다는 정보를 알 수 있다.

따라서 알맞은 키캅을 알아내어 입력하는게  FSC_level1.exe의 문제이다.





가장 첫번째로 분석하기전에 패킹 여부와 어떤 언어로 작성되었는지 확인해야 한다.

PEID를 사용하면 위 정보를 모두 뽑아올 수 있다.





빨간 네모 친 부분을 보면 Nothing found * 라고 되어 있다. 

이와 같은 경우는 우리가 분석할 프로그램에 대한 정보를 제대로 뽑아오지 못한 경우이다. 

이러한 경우는 PE Header를 보고 정보를 알아내어야 한다. pe header를 위해 PE View를 사용한다.


우선 패킹 정보를 위해 IAT(Import Address table)을 살펴보자. 

만일 IAT 에 많은 함수들이 깨져 있으면 패킹된 프로그램일 확률이 높다.

아래 사진을 보면 IAT가 그대로 있으므로, 패킹이 되지 않았다고 간주할 수 있다.





패킹되지 않았으므로 미리 어떤 API가 사용되었는지 확인하는것도 디버깅하기 전에 많은 도움을 줄 수 있다.

어떠한 API가 사용되었는지도 PE Header를 통해 확인할 수 있다.


대충 쓱 보다보면 눈치가 빠르다면 _stricmp() 함수를 눈여겨 볼 것이다.

문자열을 비교하는 함수 이므로 아마 _stricmp() 함수가 이번 프로그램에서 가장 중요한 함수가 될 것이다. 


마지막으로 우리가 디버깅할 번지를 찾는 과정이 필요하다.

물론 트레이싱하면서 찾을 순 있지만 PE Header를 통해 빠르고 정확하게 찾을 수 있다.


Imagebase와 BaseOfCode를 통해 알 수 있다.

위의 정보는 PE Header의 Optional Header 를 통해 알 수 있다.





우리가 분석할 주소의 시작 번지Image Base + Base of Code 의 번지이다.

0x69000000 + 0x00001000 = 0x69001000 번지이다.



이제 우리가 지금까지 얻은 정보를 바탕으로 분석을 진행해보자.

디버거는 ollydbg를 사용하였다.





위에서 보이는것과 같이 0x69001000 번지부터 분석을 시작한다.

아래 printf와 string을 보니 key 값을 입력받기 전에 string을 출력하는것을 볼 수 있다.





이후에 사용자로부터 입력을 받은 후에 stricmp()를 통해 문자열을 비교하는것을 볼 수 있다.





stricmp 이후에 분기를 통해 성공 or 실패를 나타내는 string을 출력하는것을 알 수 있다.

즉 우리가 예측한대로 stricmp를 잘 분석해야한다. 


stricmp를 분석 전에 sprintf 함수가 나온다. 우선 이 함수가 무슨 기능을 하는지 알아보자.

간단히 설명하자면 화면에 출력없이 지정된 데이터를 지정된 버퍼에 저장하는 함수이다.


자, 그러면 stricmp를 통해 어떻게 key를 얻어낼 수 있는지 살펴보자.


우선 우리가 scanf를 통해 입력한 문자열은 s1(0x690031A0)에 저장된다.

또한 기존에 하드코딩된 문자열이 sprintf를 통해 s2(0x69003310)에 key 값이 저장된다.





위와 같이 s2에는 "Asm07REC", s1에는 "M4RC0" 가 들어가 있음을 확인할 수 있고, s1, s2를 stricmp를 위해 파라미터로 전달하고 있다.

즉 여기서 우리가 원하는 key값은 "Asm07REC"이다.


여기서 stricmp 함수는 파라미터가 같으면 return 1을 하고 파라미터가 다르면 return 0를 한다.

어셈블리단에서는 return이 따로 없고, eax를 통해 return 값을 전달한다. 위 경우에서는 파라미터가 같지 않아서 return 1을 할 것이다.

eax는 1이 되기 때문에 test eax eax에서 ZF는 0으로 세팅된다. 

만일 파라미터가 같으면 ZF는 1로 세팅되고 JNZ에서 점프하지 않는다. 따라서 같은 파라미터가 전달될 때 성공 메세지가 나온다.

 




위와 같이 stricmp에 초점을 맞추어 알맞은 key를 입력하면 위와같이 성공함을 알 수 있다.



** 참고 



stricmp는 strcmp의 famil function이다.

strcmp는 string을 비교하는 함수이지만, stricmp는 대, 소문자를 구분하지 않고 string을 비교하는 함수이다.





위와 같이 성공적으로 keygen을 끝낼 수 있다.


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

[keygen] abexcm1 writeup, 풀이  (0) 2018.09.11
[keygen] Lena tutorial 03-1 writeup, 풀이  (0) 2018.07.17
[keygen] Lena tutorial 01, 02 writeup, 풀이  (0) 2018.07.10