목차

반응형

지뢰찾기를 자동으로 풀어버리는 프로그램을 만든다.

지뢰찾기 - 리버싱

을 먼저 읽어보면 도움이 될듯.

핵심원리

1. 지뢰찾기의 지뢰 정보를 가지고 있는 메모리 덤프를 찾음.

2. 지뢰정보를 받아옴.

3. 지뢰찾기 프로그램에 지뢰가 아닌 부분을 모두다 마우스 클릭하는 입력을함.


프로그램 폼


메모리 덤프를 읽어오는 부분 최대크기의 지뢰판을 형성하면 최대 864의 크기만큼 담기므로 864로 하였다.


while(true)
{
 //행 populate
 if (buffer[x + y * 32] + buffer[x + 1 + y * 32] != 0x20)//의미있는 열임.
 {
     while (true)
     {
         //열 populate
         //buffer[x + y * 32] 주소임
         if (buffer[x + y * 32] != 0x10)
         {
             if (buffer[x + y * 32] != 0x8F)
                click(x, y);
             x++;
         }
         else
         {
             y++;
             x = 1; 
             break;
         }
     }
 }
 else
     break;
}

지뢰정보를 어떻게 읽어올지 고민을 해봤는데

1,1에서 x좌표를 계속 증가시키다가 0x10(지뢰아님) 0x8F(지뢰) 둘다 아닌경우 다음 행으로 넘어감.



지뢰찾기에 마우스 이벤트를 보내는 부분.

지뢰한블록당 32px이므로 칸단 16px씩 이동하면 된다.(단위가 px인지는 모르겠지만 하여튼 들어맞음)

또한 시작지점은 18,60정도로하면 1,1의 지뢰부분이다.

그리고 가장중요한건데 메시지를 보낼때 이동할 좌표값을 넣는건데 쉬프트 연산자가 필요하다

x와 y로 이루어진 값들을 하나의 값으로 표현한뒤에 그것을 보내줘서 인식시키는데

int value = (y_start + (y-1)*16 << 16) + x_start + (x-1)*16;

            SendMessage(process.MainWindowHandle, 0x20, (uint)value, 0x000000001);

            SendMessage(process.MainWindowHandle, 0x20, (uint)value, 0x020100001);

            PostMessage(process.MainWindowHandle, 0x201, 0x000000001, (uint)value);

            PostMessage(process.MainWindowHandle, 0x202, 0x000000000, (uint)value);

보면 value가 x와 y로 이루어진 값이다.

직접 microsoft spy++을 봐보면 좌표부분의 데이터를 전송할때 0x???????? 이런식으로 보낸다.

그중에 앞의 4개의 ????가 y좌표를 나타내고 뒤의 ????가 x좌표를 나타낸다. 물론 16진수로 나타내어져있다.

따라서 x와 y의 값으로 나타내기위해서는 먼저 y좌표에 2^16을 곱하여 왼쪽으로 4칸이동시키고 x좌표값은 그냥 더해주면된다. 16진수로 바꿔줘야하고

그렇게 보내면 프로그램이 원하는 좌표로 이동하여 보내진다.



minesweeper.zip

해당 프로젝트 파일



반응형

'보안 > 리버싱' 카테고리의 다른 글

reversing - minesweeper  (0) 2017.01.25
반응형

winmine.exe


지뢰찾기 매크로를 만들려고 한다.

올리디버거로 먼저 지뢰찾기를 분석하였다.


http://www.morwire.com/index.php/reverse-engineering/5-introduction-to-reversing-minesweeper

이곳에서 자세한 정보를 얻을 수 있었음.

위의 글은 지뢰찾기를 시작할때 타이머가 작동하므로 독자적인 timer를 만들어서 사용한 것이 아니라면 user32.dll중에 settimer를 사용할 것이라고 가정하여 프로그램의 도입부분을 찾아내었다.





01003818에서 CMP를 통하여 DS:[010057A4]=00000000의 값과 0을 비교한다.

만약에 프로그램이 처음이 아니면 DS:[010057A4]=00000000의 값이 DS:[010057A4]=00000001이런식으로 바뀌므로

아래의 JNZ를 통하여 처음이면 타이머를 설정하기위하여 그대로 내려가고 처음이 아니라면 

0100386B  |> 841D 00500001  TEST BYTE PTR DS:[1005000],BL            ;  처음아니면 일로옴

이곳으로 내려가게된다.


지뢰찾기에서 맨처음은 항상 통과한다는것을 찾아내었다.

지뢰정보는 덤프 1005340에 담겨있다.


그림을 보면 현재 1,3이 지뢰인것을 알 수 있다. (위의 사이트 참조)

0100389B  |. 8A9402 4053000>MOV DL,BYTE PTR DS:[EDX+EAX+1005340] 에 브레이크 포인트를 걸어준뒤

1,3의 좌표를 누르면



누른부분의 좌표의 값이 8F에서 80으로 바뀌게된다. 원래 지뢰를 누르면 일단 그자리의 값이 80으로 바뀐다. (나중에 설명함)

이후 계속 돌리면 



분명 지뢰였던 부분이 지뢰가 아닌것으로 바뀌게된다. 맨처음일때 걸렸으면 알아서 수정해주는 기능이 있는것으로 보인다. 하지만 이부분은 더 깊이 조사할 생각은 없다.


그 이후 지뢰에대한 데이터가 저장되어있는것은 위의 페이지에 상세하게 나와있으므로 생략하고 나는 지뢰를 눌렀을때의 작동원리를 살펴보겠다.



먼저 다시 새로 시작한뒤에 맨처음에는 지뢰를 누르면 바뀌어버리기 때문에 정상적인 칸을 눌러주고 지뢰를 누르자.

위의 사진을 보면 2,2가 지뢰다. 따라서 1,2를 누른뒤 2,2를 누르겠다.


그러면 다시 2,2의 좌표가 80으로 바뀐다.

그렇다면 분명 코드중에 80과 비교하는 코드가 있을것이다. 그것을 찾아보았다.


어느정도 따라가다보면 

01003529  |. F602 80        TEST BYTE PTR DS:[EDX],80

의 코드를 볼 수 있다.[EDX]에 담긴 값과 80을 비교하라고 하는데 코드를 읽어보면 EDX에 사용자가 누른 값의 데이터의 주소를 넣어놓았으므로 실질적으로는

01003529  |. F602 80        TEST 80,80 인 상태다.

지뢰를 의미하는 것끼리 비교하라는 것이니까 무언가 느낌이 지뢰를 판별하려는 것임을 알수있다.

한번 테스트용으로 아래의 JE에서 원래는 점프가 일어나면 안되지만 0인 ZF를 1로 바꾸어 진행시켜보았다.

따라서 아래의 JE문에서 점프가 발생하였다.

그리고 진행시켜보면 지뢰찾기 프로그램에서 지뢰가 아니라고 뜨는 것을 알 수 있다.

지뢰정보를 보면 정보가 약간 모순적이게도 지뢰였던 자신과 오른쪽의 지뢰를 합쳐 주변에 지뢰가 2개있다고 말해준다. 또한 판에 있는 8F의 개수를 세어보면 지뢰가 총 9개밖에 안된다.

한번 클리어를 해보았다.


분명 지뢰는 9개이며 이상한 칸도 있지만 클리어는 하였다.

위의 TEST 80부분이 지뢰인지 판단하는 핵심기능임을 알 수 있다.


다음은 이 정보들을 토대로 지뢰찾기를 자동으로 클리어해주는 매크로를 만들고자 한다.


못깨는 지뢰찾기.exe

그전에 test부분을 수정하여 누르는 곳이 어디던 항상 틀림표시 되도록하는 못깨는 지뢰찾기를 만들어보았다.

친구를 골탕먹이기 좋을것같다.


지뢰찾기 매크로

반응형

'보안 > 리버싱' 카테고리의 다른 글

C# - minesweepr hack + macro  (0) 2017.02.06