리버스엔지니어링 문제 Advance 13

2015. 8. 9. 18:16Security ★ Development/Reversing

반응형

http://codeengn.com/challenges/advance/13


Problem : Find the Username when the Password is 042D7650341B4060. 

(This problem has multiple answers, so post your answer on the messageboard in a private thread and we will verify it for you.) 
Note : "U got the key, you r0x ;)" must pop up for the serial. 


패스워드가 다음과 같을 때 올바른 유저네임을 찾는 것으로 틀린 값이 들어가면

위와 같은 메시지가 뜹니다.


문자열 검색을 해봐도 의심가는건 보이지 않고 의심가는 함수로 TerminateProcess, IsDebuggerPresent, GetSystemDirectoryW에 bp를 걸어봤지만 하나도 걸리지 않습니다.  물론 팩도 되어있지 않고 메시지 창이 뜰 때 기존 창이 안보였다가 다시 나타나는 것에서 단서를 얻을 수 있지 않을까 싶은데 별다른 도움은 되지 않았습니다. 


C#으로 되어있음을 확인하고 C# 디컴파일러로 확인합니다.  솔루션으로 export하고 비쥬얼 스튜디오로 열어서 디버깅 해줍니다.


CheckCredential 함수가 true를 리턴해야 합니다.  먼저 Username은 4글자로 맞춰야 한다는 것을 첫번째 if문에서 알 수 있습니다.


아래로 내려가다보면 이런 부분에서 예외가 발생합니다.  예외가 걸리면 아래 코드를 실행하지 않기 때문에 최종 리턴값을 확인할 수 없습니다...


main함수부터 차근차근 보겠습니다.

main에서는 ScrambleCode와 Check를 호출해주고 있습니다.    


ScrambleCode에서는 Program._secret를 만드는데 이건 CheckCredential에서 쓰입니다.  Check에서는 CheckCredential을 불러서 맞는지 틀렸는지를 확인해줍니다.  

그리고 밑에 CreateDynamicType 함수를 봅니다.  여기서 GetILCode와 DeoffuscatedCode라는 정의해준 함수를 호출하는데 이 둘을 분석합니다.  GetILCode는 s4tanic0이라는 함수의 몸체를 불러서 Byte array로 리턴해줍니다.  이렇게 얻은 값을 DeofuscateCode에서 처리합니다.  여기서는 또 ComputeDeoffuscateKey함수와 GetCRCMethods 함수를 호출합니다.  앞의 함수는 자세히는 몰라도 어떤 Key를 생성한다고 추측할 수 있습니다.  

 GetCRCMethods는 IL코드를 Byte 배열로 얻은 것을 xor연산을 통해 numArray2, numArray1로 넘겨 리턴합니다.  


- IL코드 -

 IL은 Intermediate Language을 의미합니다.  C#이 빌드되면 MSIL이라는 중간 코드를 생성하고 프로그램이 실행될 때 JIT compiler에 의해 이 IL코드가 컴파일되어 Native코드로 변경됩니다.  이 방법은 C#이 실행 머신 환경(32/64bit, x86/AMD 등)에 관계없이 같은 코드를 실행할 수 있도록 해줍니다.


Dotnet dumper를 이용하고 디스어셈블러를 써서 Validator의 Validate 부분의 코드를 봅니다.  이 부분이 CheckCredential의 Method.Invoke부분이 됩니다.

그럼 CheckCredential을 자세히 보겠습니다.  

1. username각 위치를 4바이트 배열에 누적하는데 위치 mode 4 연산을 해서 누적합니다.

2. password는 byte배열에 들어갑니다.

3. Program._secret도 byte배열에 들어가는데 길이가 2배가 됩니다.  

4. Validate 코드 (password와 _secret의 연산)

5. username byte배열은 1 2 3 4 4 3 2 1 의 값으로 길이가 2배가 됩니다.


4번의 결과와 5번의 결과가 같으면 됩니다.


그럼 주어진 Password에서 username을 거꾸로 구할 수 있습니다.