sweetchip's blog


안녕하세요 sweetchip입니다.


오늘도 역시 지뢰찾기를 쉽게 부수기 위해서 '공부용' 으로 분석 했습니다.


어제는 윈xp버전의 지뢰찾기.. 오늘은 윈도우7 버전의 지뢰찾기..


다음은 윈8인데, 윈8을 한번도 안써봐서 모르겠군요. ㅋㅋㅋ


울트라북 사서 윈8 이벤트 프로모션 코드를 받아놓긴 햇는데 신용카드가 없어서 못사네요. 쩝


어쨋든 윈7의 지뢰찾기를 보면..



xp와의 퀄리티와는 차원이 다른 디자인을 보여줍니다 ㅋㅋ


그리고 exe의 이름도 winmine 에서 minesweeper 로 바뀌엇더군요. ㅋㅋ


제 컴퓨터 시스템은 64비트라서 올디에서 돌아가지 않아 친구의 도움을 받아 32비트의 지뢰찾기를 구해서 분석을 진행했습니다.


아래는 잡다한것을 전부다 제외하고 핵심만 찍어뒀습니다.



저 함수가 이 버튼이 지뢰인가 정상인가를 판별하는 함수입니다.


0090c57 - x좌표를 구하고 ebx 에 저장. [win7버전에선 0부터 시작]

0090c6a - y좌표를 구하고 edi 에 저장. [win7버전에선 0부터 시작]


x와 y좌표를 구하면서 무언가 연산을 하지만, 지뢰를 찾는데에 구지 넣을 필요는 없을것 같습니다.


지뢰를 찾을때 핵심은 바로...


조금 확대시켜 보면



저기 파란색으로 그어진곳만 신경쓰면됩니다.


0090cba - esi 0x44 연산후 eax 저장

0090cbd - eax c 연산후 eax 저장

0090cc0 - eax (x좌표 * 4) 연산후 eax 저장

0090cc3 - eax y좌표 연산후 CL과 비교 [cl은 0으로 정해져 있음.]


이곳에서 1이면 폭탄, 0이면 그냥 넘어간다. 아무일도 없엇던 것처럼!


좋습니다.. 근데 문제는 0090cba의 esi를 어디서 구하냐 이겁니다.


그거는 이 함수에 오기전에 볼수있습니다.


따로 과정은 설명을 안하겠습니다. 직접 분석하시는게 최고!



지금 브레이크포인트의 아래아래 call문이 지뢰판별 함수입니다.


현재 브레이크 포인트의 00996FD6 주소의 구문은 위에서 필요한 esi 에 쓰일 값입니다.


자. 이제 필요한 정보는 모두 모았습니다.


위 분석은 정말 간단하게 이므로 나머지는 소스를 보시면 이해가 되실... 겁니다... [소스가좀 어지럽네요 ㅠ-ㅠ]





자 완성했습니다.


* 지난번 XP버전과 달리 win7버전은 메모리 주소가 일정하지 않아서 x좌표와 마인개수를 찾기가 쉬운일이 아니라서

[y 좌표는 치트엔진을 이용하면 쉽게 찾으실수 있습니다.] - 그냥 x좌표와 y좌표를 입력받는 형식으로 했습니다.


* 지뢰찾기 프로그램의 이름은 minesweeper.exe 이어야 햡니다.



구동영상



파일 ----------------------------------------------------------------------


지뢰찾기 게임 파일


minesweeper.zip


프로그램 및 소스


Win7_minesweeper.rar


---------------------------------------------------------------------------



소스

using System;

using System.Collections;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Diagnostics;

using System.Drawing;

using System.Linq;

using System.Runtime.InteropServices;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;


/*

* Open Source Project.

* 지뢰찾기 지뢰 위치 [Win7 32bit minesweeper]

* 분석, 프로그램작성 : sweetchip

* 날자 : 2013.01.22

*

* Blog : http://pgnsc.tistory.com

* Site : http://studyc.co.kr

*

* xp의 지뢰찾기와는 달리 가로 세로 지뢰수를 따로 구하려면 리버싱 작업이 더 필요해서

* 일단은 가로, 세로는 입력을 받는 형식으로 목적을 두고 분석하고 프로그램을 만들었습니다.

* 세로는 쉽게 찾을수 있으나, 가로와 지뢰개수를 찾기가 힘드네요. 그렇다고 리버싱을 더하기엔 시간이 없네요 ㅠㅠ

* 좋은 아이디어 있으신분 덧글로 남겨주심 감사하겠습니다.

*/


namespace Win7_minesweeper

{

public partial class Form1 : Form

{


[DllImport("kernel32.dll")]

public static extern int OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);


[DllImport("kernel32.dll")]

public static extern bool ReadProcessMemory(int hProcess, int lpBaseAddress, byte[] buffer, int size, int lpNumberOfBytesRead);


public uint DELETE = 0x00010000;

public uint READ_CONTROL = 0x00020000;

public uint WRITE_DAC = 0x00040000;

public uint WRITE_OWNER = 0x00080000;

public uint SYNCHRONIZE = 0x00100000;

public uint END = 0xFFF;


public Process[] processes;


public static byte[] ReadMemory(int adress, int processSize, int processHandle)

{

byte[] buffer = new byte[processSize];

ReadProcessMemory(processHandle, adress, buffer, processSize, 0);

return buffer;

}


public int getbaseaddr()

{

int basea = processes[0].MainModule.BaseAddress.ToInt32();

return basea;

}

public Form1()

{

InitializeComponent();

}


private void Form1_Load(object sender, EventArgs e)

{

processes = Process.GetProcessesByName("MineSweeper");

numericUpDown2.Value = gety(getbaseaddr());


}


public void go()

{

processes = Process.GetProcessesByName("MineSweeper");

listBox1.Items.Clear();

try

{


for (int i = 0; i < (int)numericUpDown2.Value; i )

{

for (int j = 0; j < (int)numericUpDown1.Value; j )

{

ismine(i, j);

}

}

}

catch

{

MessageBox.Show("ERROR","ERROR");

}

}



public void ismine(int y, int x)

{

int basea = processes[0].MainModule.BaseAddress.ToInt32();

int ecx1 = getecx(getbaseaddr() 0x868b4) 0x10;

int ecx2 = getmem(ecx1);


int cel = ecx2 0x44;

cel = getmem(cel) 0x0c;

cel = getmem(cel) (x * 4);

cel = getmem(cel) 0x0c;

cel = getmem(cel) y;

cel = getmem1byte(cel);

if (cel == 1)

{

int tempx = x 1;

int tempy = y 1;

listBox1.Items.Add(tempy ", " tempx " 좌표에 지뢰");

}

label1.Text = "우와 @_@ 신기하다\n총 지뢰 개수 : " listBox1.Items.Count;

}


public int getecx(int baseaddr)

{

int processHandle = OpenProcess((DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE | END), false, processes[0].Id);

byte[] tmp = ReadMemory(baseaddr, 4, processHandle);

int m = BitConverter.ToInt32(tmp,0);

return m;

}



public int gety(int baseaddr)

{

int processHandle = OpenProcess((DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE | END), false, processes[0].Id);

byte[] tmp = ReadMemory(baseaddr 0x7e1dc, 4, processHandle);

int m = BitConverter.ToInt32(tmp, 0);

return m;

}


public int getmem(int addr)

{

int basea = processes[0].MainModule.BaseAddress.ToInt32();

int processHandle = OpenProcess((DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE | END), false, processes[0].Id);

byte[] tmp = ReadMemory(addr, 4, processHandle);

int m = BitConverter.ToInt32(tmp, 0);

return m;

}


public int getmem1byte(int addr)

{

int basea = processes[0].MainModule.BaseAddress.ToInt32();

int processHandle = OpenProcess((DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE | END), false, processes[0].Id);

byte[] tmp = ReadMemory(addr, 1, processHandle);

int m = (int)tmp[0];

return m;

}


private void button1_Click(object sender, EventArgs e)

{

go();

}


}

}



긴 글 읽어주시느라 수고 하셨습니다.


감사합니다 :D



신고

Comment 11

  • 2013.01.24 17:20 수정 답글

    비밀댓글입니다

    • 2013.01.24 19:41 신고 수정

      안녕하세요
      프로모션 코드는 저도 필요해서 ^^;
      처음사용자용 사기엔 학생이라 부담이 많이 가거든요.... ㅠㅠ

    • 2013.01.24 19:50 수정

      비밀댓글입니다

  • 안녕하세요
    2013.03.09 11:21 신고 수정 답글

    열심히 구독했습니다 ..그런데궁금한점이생기더군요
    엔진을 이용해서 openprocess로 곰플레이어를실행하고 x를눌러도 꺼지지 않게 할수 있는 방법이 있나요??

    • 2013.03.09 13:36 신고 수정

      안녕하세요

      엔진쪽은.. 잘 모르겠습니다.

      엔진은 잘 안써봐서 확답을 드릴수는 없네요.

      x눌러도 꺼지지 않게 하려면 리버싱으로 하시는게 더 나을듯 합니다.

  • 안녕하세요2
    2014.01.30 04:37 신고 수정 답글

    지뢰 찾기 하다가 첫클릭에 지뢰가 나왔다고해서 소스 찾아볼려다가 이 블로그 들어오게 되었는데요. 리버싱 하는 영상을보니깐 우선 지뢰찾기게임에서 한번 클릭을 하시고나서 지뢰 위치를 로드 하시던데 이게 지뢰찾기 게임자체가 첫클릭에 클릭위치를 피해 지뢰가 설정된다는 의미인지 궁금해서요. 맞나요?

    • 2014.01.30 13:50 신고 수정

      늦은 시간에 질문을 주셧네요! (이런 시간대에도 제 블로그에 사람이 들어오다니 신기합니다 ㅋㅋ)

      제 기억상 윈도우 7에서는 처음 x y를 정한다음에 지뢰 위치를 설정합니다.

      제 추측상 이 이유는 말씀하신것과 같이 첫번째 지뢰를 피하려고 한것 같습니다.

      XP에서는 처음 로딩시에 지뢰 위치를 설정하고 만약 그 지뢰를 밟으면 다른 곳으로 지뢰 위치를 옮겨서 첫번째 시도에 지뢰가 터지지 않도록 하던것으로 기억합니다.

      요약하면 제 추측컨대 말씀하신 것이 맞다고 봅니다.

  • 안녕하세요2
    2014.01.30 05:43 신고 수정 답글

    늦은시간에도 안주무시고 친절히 답변을 달아주셔서 감사합니다! 도움이 되었어요!!

  • master
    2015.11.17 21:38 신고 수정 답글

    안녕하세요.

    리버싱 분야를 공부하다 궁금한점이 생겨서 댓글남겨봅니다.

    저는 리버싱을 통해 악성코드 분석이나 프로그램 제어에 관심이많은데 실제 필드에서 리버싱이 많이 사용되나요??

    이 능력을 업으로 삼고싶습니다.

    • 2015.12.03 00:24 신고 수정

      말씀하신 내용은 리버싱이 꼭 필요한 요소이기도 합니다. 그리고 악성코드 분석같은 그런 프로그램을 분석하는 일의 경우 실제 필드에서도 리버싱이 필수로 다뤄집니다. 11월에 너무 바쁜일이 많아서 못봤었네요 :(

  • 호돌이
    2017.03.28 14:37 신고 수정 답글

    혹시 윈도우7 64비트 지뢰찾기는 안되나요?