상세 컨텐츠

본문 제목

윈도우7 지뢰찾기 분석! - 리버싱과 맵핵[?]

0x10 정보보안/0x14 Reverse Engineering

by sweetchip 2013. 1. 22. 17:03

본문

반응형


안녕하세요 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



반응형

관련글 더보기