sweetchip's blog


심심해서 시작한 지뢰찾기 리버싱.. ㅋㅋ


리버싱중 몇가지 재미있는것을 발견해서 C#프로그램으로 작성해봤다.



프로그램은 바로 위와 같다.


물론 몇가지 버그가 있을때 찍어서 화면을 보기에도 한가지 버그가 눈에 보인다. ㅋㅋ


지금은 버그 픽스를 하고 최종을 내놓았다.


메모리 수정관련 프로그램은 처음이라 프로세스와 메모리에 접근하는 방법은 구글링을 해서 많이 도움을 받게 되었다.


나머지는 직접 분석해서 어떤식으로 지뢰를 체크하는지 알아내고 치트엔진을 사용해서 x, y, 지뢰개수 를 가지고 있는 포인터를 알아낼수 있었다.


생각보다 지뢰를 찾는방법은 간단했다.


소스를 보면 알겠지만, 핵심은 X, Y좌표를 이용해서 쉬프트연산과 곱셈, 더하기, and 연산과 or 연산도 있다..


어쨋든 이러한 연산을거치면 포인터 주소가 나오는데 그 포인터주소의 실제값이 0x80 이 되면 그 위치에 지뢰가 있는것이다.


# (물론 연산을 안해도 0x8f 가 있다면 지뢰가 있다고 볼수있다. - 이것은 분석을 해봐야 이해가 가능하다.)


# (기회가 된다면 분석을 하는 포스팅을 쓰도록 하겠습니다.)




위는 작동영상이다.


조건] 지뢰찾기 파일 이름이 winmine 이어야한다 [기본이름]


소스코드


using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Diagnostics;

using System.Drawing;

using System.IO;

using System.Linq;

using System.Runtime.InteropServices;

using System.Runtime.Serialization.Formatters.Binary;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;


/*

* Open Source Project.

* 지뢰찾기 지뢰 위치 알아내기

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

* 날자 : 2013.01.21

*

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

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

*

*/


// youroffset은 메모리 주소입니다. 메모리 관련 함수는 처음이라서 그대로 가져오는도중 이름수정을 못햇네요 ㅋㅋㅋ

namespace winmine_hack

{

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);


Process[] p;

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 int temp = 0;



public Form1()

{

InitializeComponent();

}


public void auto(int x, int y)

{

int a_temp = 1;

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

int YOUR_OFFSET = 0x1005340;

int r = 0;

for (int i = 1; i < x 1; i )

{

for (int j = 1; j < y 1; j )

{

int cal = (i * (int)Math.Pow(2, 5)) j YOUR_OFFSET;

r = int.Parse(ReadMemory(cal, 1, processHandle)[0].ToString());

int t = r & 0xe0;


if (t == 0x80)

{

a_temp = i j;

}

}

}

if (a_temp != temp)

{

get();

temp = a_temp;

}

}



private void Form1_Load(object sender, EventArgs e)

{

timer1.Interval = 100;

timer1.Start();


}


public void get()

{

try

{

p = Process.GetProcessesByName("winmine");

listBox1.Items.Clear();

int x = xlength();

int y = ylength();

label1.Text = "우와! 신기하다 @_@\nStatus : " x " X " y " 지뢰 개수 " mine();

for (int i = 1; i < x 1; i )

{

for (int j = 1; j < y 1; j )

{

cal(i, j);

}

}

}

catch { MessageBox.Show("Error","Error"); }

}


public int mine()

{

//0x010056a8

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

int m = int.Parse(ReadMemory(0x01005330, 1, processHandle)[0].ToString());


return m;

}


public int xlength()

{

//0x010056a8

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

int x = int.Parse(ReadMemory(0x010056a8, 1, processHandle)[0].ToString());


return x;

}


public int ylength()

{

//0x010056ac

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

int y = int.Parse(ReadMemory(0x010056ac, 1, processHandle)[0].ToString());


return y;

}


public void cal(int x, int y)

{

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

int YOUR_OFFSET = 0x1005340;

int cal = (x * (int)Math.Pow(2, 5)) y YOUR_OFFSET;

int r = int.Parse(ReadMemory(cal, 1, processHandle)[0].ToString());


int t = r & 0xe0;

if (t == 0x80)

{

temp = x y;

listBox1.Items.Add(x "," y "에 지뢰");

}

}


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

{

byte[] buffer = new byte[processSize];

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

return buffer;

}


private void timer1_Tick(object sender, EventArgs e)

{

try{

p = Process.GetProcessesByName("winmine");

auto(xlength(), ylength());

button1.Enabled = true;

}

catch

{

button1.Enabled = false;

listBox1.Items.Clear();

label1.Text = "우와! 신기하다 @_@";

}

}


private void button1_Click(object sender, EventArgs e)

{

get();

}

}

}



프로젝트 파일


winmine_hack.zip


xp_지뢰찾기 [win7_64bit 작동확인]


winmine.rar





신고

Comment 2

  • 자바하다가c#보고빠진1인
    2014.01.09 21:31 신고 수정 답글

    대박
    대박
    대박

    와 C#그정도 다룰려면
    얼마나 해야되나요 !!??

    • 2014.01.11 03:45 신고 수정

      C#에서도 많은 기능을 지원하더군요
      자바를 많이 다뤄보셧다면 금방하실 수 있을 것입니다.