Difficult Mine / 어려운 지뢰찾기

winmine_sjkim.exe

지뢰찾기 잘 하시나요?
제가 약간 손봐둔 지뢰찾기는 조금 어려울겁니다.

성공하기만 한다면 플래그를 출력할테니 다운받아 
게임을 성공해보세요.


여러가지 접근방법이 있다.




비교적 쉽게 풀 수 있는 방법도 분명 존재 할 것이다. 


문제를 해결하는 동안 많은 시행착오를 겪었고 해결하였다.


입문자에게 추천할 만한 난이도는 아닌것 같다.


하지만 리버싱을 어느정도 접한 사람들에게는 좋은 문제인것 같다.


해당 문제를 해결하기 위해 다음과 같이 생각하였다.




1. 플래그를 출력하는 이벤트 호출 함수를 찾아 그 주소로 JMP 한다.



해당 방법의 경우 flag 와 관련된 직접적인 string 이 없어 찾기 힘들다. 따라서 제외하였다.



2. 지뢰는 10*10 총 100개이며 지뢰를 피할 수 있는 칸은 오직 두개 뿐이다. 

   그렇다면 그 두 곳에 대한 좌표가 있을 것이다. 그 좌표를 찾아 누르고 플래그를 획득하자. 


그렇다면 좌표는 어떻게 구할 수 있을까?




먼저 게임을 시작할 때의 루틴을 찾아야 한다. 

게임 시작과 동시에 폭탄이 세팅될 것이기 때문이다.



루틴을 찾기 위해서는 String, 함수명, 메모리 엑세스 로그 등의 정보가 필요한데.


해당 바이너리는 다행히도 심볼이 살아 있어 비교적 쉽게 찾을 수 있었다. 


함수명으로 쉽게 게임을 시작할 때 호출하는 함수임을 짐작할 수 있다.


이제 코드를 자세히 들여다 보자.




위의 코드를 보면 cBomStart가 무한루프 한다.


v1 = Rnd(xBoxMac) + 1

v2 = Rnd(yBoxMac) + 1


이 코드를 보고 대충 좌표값일거라고 생각을 하게 되었다. Rnd 함수를 들여다 보자.




예상 대로 rand() 함수를 이용하여 난수를 생성하는 함수이다.


즉 v1에는 랜덤한 x좌표가, v2 에는 랜덤한 y 좌표가 저장된다.


--cBomStart 되면서 특정 메모리 주소에 값을 넣는것이 보인다.


여기까지 봤다면 cBomStart 의 초기값은 두개를 제외한 98이어야 한다.


정확하게 알아보기 위해 치트엔진을 이용하여 cBomStart의 초기값을 확인한다.



예상대로 초기값이 98로 설정되어 있었다.


이제 저 루틴에 대해서 신뢰성이 생겼으니 x와 y의 좌표를 구해야 한다.


x좌표와 y좌표를 구할 수 있는 방법은 다음과 같다.


1. seed값을 알아낸 뒤 rand 함수를 직접 코딩한다.

2. Code Injection을 통해 좌표 값을 알아낸다.

3. 값이 들어간 테이블을 분석하여 좌표값을 알아낸다.


필자는 코드인젝션을 통해 x좌표와 y좌표를 가져왔다.


 

Code Injection 을 수행하기 위해 먼저 인젝션 포인트를 잡는다.





Rnd(x)의 결과 값이 eax에 들어가므로 밑의 인스트럭션 아무거나 잡아서 eax를 출력하면 된다.


필자의 경우 call rnd 바로 밑의 인스트럭션 주소를 잡았다.


x : 0x10036DE


Rnd(y) 또한 마찬가지로 결과 값이 eax에 저장되므로 밑의 인스트럭션을 잡는다.


y : 0x10036E0


두 주소 모두 eax 레지스터에 결과를 저장한다는 것을 파악하였다.


이제 치트엔진을 이용하여 코드인젝션을 해보자.



Lua Engine을 이용하여 다음과 같이 코드를 작성한다.



x = 0x10036D2

y = 0x10036E0


x_val = 0

y_val = 0

function debugger_onBreakpoint()

         if x==EIP then

            x_val = EAX

         end


         if y==EIP then

            y_val = EAX

            print(x_val .. ", "..y_val)

         end

         return 1

end


debug_setBreakpoint(x)

debug_setBreakpoint(y)



코드에 대해서 간단히 설명하자면


먼저 x와 y에 BreakPoint를 걸어주고 eax 를 받아줄 함수를 구현한다.


EAX의 순서가 x,y / x,y 이지만 만일의 상황을 대비하여 


EIP 가 x일 경우 x_val에 EAX 를 세팅

EIP가 y 일 경우 y_val에 EAX 를 세팅


debugger_onBreakpoint() 함수의 리턴값은 브레이크 포인트를 통과 여부를 의미한다. 


0일 때 : Breakpoint 지점에서 멈춤

1일 때 : Breakpoint 지점을 통과


이제 코드를 작성하고 execute 버튼을 누르면 코드가 적용된다.


그리고 지뢰찾기 대가리? 버튼을 눌러 테이블을 초기화 한다.



초기화와 동시에 Output 란에 예쁘게 좌표 값을 뱉어내는 것을 확인할 수 있다.


이제 저 좌표를 정리하자.


정리할 때 https://www.online-utility.org/text/sort.jsp 이 사이트를 이용하였다.


그리고 정렬된 값을 참조하여 없는 좌표를 눈으로 찾는다


여기서 주의해야 할 점은 앞에서 +1 값을 좌표에 넣어줬으므로 좌표에도 +1을 해줘야 한다.


좌표를 올바르게 찍으면 플래그를 출력하게 된다.


#Thanks to Tonix

'Wargame > sjkim.net' 카테고리의 다른 글

Packet Analyze - Busan Travel  (0) 2017.04.21
Programming - RSA Decrypt  (0) 2017.04.21
Programming - Lotto Number  (0) 2017.04.20
Packet Analyze - Find EXE File  (0) 2017.04.20
Packet Analyze - hacker msg??  (0) 2017.04.20

+ Recent posts