创建博客 登录  
 关注
   显示下一条  |  关闭

Twilight的客博

随心所欲的涂鸦

 
 
 

日志

 
 

使用CALL调用实现扫雷 ---- 编码  

2010-09-20 22:39:11|  分类: 程序设计 |  标签: |字号 订阅

你可能需要首先查看:使用CALL调用实现扫雷以便理解这里的代码。

说明:程序使用MFC,具体代码是在一个DLL中,你需要将DLL注入目标进程,我使用的是键盘线程HOOK,使得在扫雷窗口上按下HOME键可以呼出DLL中的对话框。

图示下:
CALL调用扫雷实现 - twilight - Twilight的客博
 

另外程序代码里对“自动扫雷”按钮有2套代码,分别是OnBnClickedBtnAuto 和 OnBnClickedBtnAuto2。区别在于OnBnClickedBtnAuto使用了早期些的一些代码,而OnBnClickedBtnAuto2是独立写的。他们也分别调用了HitBlock和HitBlock2,他们区别是前者是单一的点击方块功能,后者集布雷、自动点击所有方块(当然排除是雷的方块)于一体,所以HitBlock需要在循环里调用,传入所需的行和列参数,HitBlock2只需要调用一次,它的参数个数同HitBlock一样,但是含义不同,HitBlock2参数的含义是首次点击方块的位置,这个位置用于布雷。

还有一点,这2个函数的执行都是很快很快的,这里看不出有什么不对,如果在中间加上Sleep问题就明显了,扫雷窗口在函数执行完毕之前是不更新的,也就是在扫雷过程中你看不到方块被一个一个的点开。导致问题的原因可能是DLL线程和扫雷主线程为同一个线程,在DLL执行过程中阻碍了扫雷主线程更新UI。可以使用SetTimer来修改代码,其实这也是我最先实现了的一种方式,后来删除了。另外也可以试着创建个新线程来执行扫雷。

=============================GameForm.h===============================
#pragma once


// GameForm dialog

class GameForm : public CDialog
{
DECLARE_DYNAMIC(GameForm)

public:
GameForm(CWnd* pParent = NULL);   // standard constructor
virtual ~GameForm();

// Dialog Data
enum { IDD = IDD_GAMEFORM };

protected:
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedBtnGetinf();
void HitBlock(int row, int column,  bool bFirst);
void HitBlock2(int arow, int acol);
CString m_MineInf;
char* mineInf;
DWORD m_VATOP;
DWORD m_VAFUN;
DWORD m_VAFUN2;
DWORD m_VAFUN3;
int mineCount,row,column;
afx_msg void OnBnClickedBtnAuto();
afx_msg void OnBnClickedBtnAuto2();
};

===============================GameForm.cpp=============================
// GameForm.cpp : implementation file
//

#include "stdafx.h"
#include "MineInjectDll.h"
#include "GameForm.h"
#include "afxdialogex.h"


// GameForm dialog

IMPLEMENT_DYNAMIC(GameForm, CDialog)

GameForm::GameForm(CWnd* pParent /*=NULL*/)
: CDialog(GameForm::IDD, pParent)
, m_MineInf(_T(""))
, mineInf(0)
, mineCount(0)
, row(0)
, column(0)
, m_VATOP(0)
, m_VAFUN(0)
, m_VAFUN2(0)
, m_VAFUN3(0)
{

}

GameForm::~GameForm()
{
if(mineInf!=NULL)
delete[] mineInf;
}

void GameForm::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_MINEINF, m_MineInf);
}


BEGIN_MESSAGE_MAP(GameForm, CDialog)
ON_BN_CLICKED(IDC_BTN_GETINF, &GameForm::OnBnClickedBtnGetinf)
ON_BN_CLICKED(IDC_BTN_AUTO, &GameForm::OnBnClickedBtnAuto2)
END_MESSAGE_MAP()


// GameForm message handlers


void GameForm::OnBnClickedBtnGetinf()
{
HMODULE hMine = GetModuleHandle(_T("Minesweeper.exe"));
if(hMine==NULL)
{
AfxMessageBox(_T("无法找到模块mineswpeer"));
return;
}
//模块句柄即为基址
DWORD mineBaseAddr = (DWORD)hMine;
const int RVA_top = 0x868B4;

DWORD VA_top = mineBaseAddr + (DWORD)RVA_top;

int lmineCount=0,lrow=0,lcolumn=0;
DWORD* mineTable = 0;
_asm
{
mov ecx,VA_top ;一级基址
mov ecx,[ecx]
mov ecx,[ecx+0x10]
mov ebx,[ecx+0x4]
mov lmineCount,ebx ;地雷总数
mov ebx,[ecx+0x8]
mov lrow,ebx ;行
mov ebx,[ecx+0x0c]
mov lcolumn,ebx ;列
mov ebx,[ecx+0x44]
mov ebx,[ebx+0x0C] ;ebx是一个地址表首地址
mov mineTable,ebx
}

mineCount = lmineCount;
row = lrow;
column = lcolumn;

if(mineInf!=NULL)
delete[] mineInf,mineInf=NULL;
mineInf = new char[row*column];
memset(mineInf,0,column*row);
DWORD mineColumn=0;
char* mineColumnTable=0;
for(int i=0;i<column;i++)
{
for(int j=0;j<row;j++)
{
//第I列
mineColumn = mineTable[i];
mineColumnTable = (char*)(*((DWORD*)(mineColumn + 0x0C)));
mineInf[j*column+i] = mineColumnTable[j];
}
}

CString str;
for(int r=0;r<row;r++)
{
for(int col=0;col<column;col++)
{
if(mineInf[r*column+col]==1)
str+=_T("M");
else
str+=_T("O");
str+=_T(" ");
}
str+=_T("\r\n");
}

m_MineInf = str;

UpdateData(false);

}

void GameForm::HitBlock(int arow, int acol, bool bFirst)
{
int va_top = m_VATOP;
int va_fun = m_VAFUN;
int va_fun2 = m_VAFUN2;
int va_fun3 = m_VAFUN3;

_asm
{
push eax //保留参数
push ecx
push ebx
mov eax,va_top
mov eax,[eax]
mov [eax+0xC5],1
mov ecx,va_top
mov ecx,[ecx]
push arow
push acol
xor bl,bl
mov eax,va_fun
call eax //调用点击方块CALL
test eax,eax
jg here_
jmp end_
here_:
push eax
mov eax,va_fun2
call eax //后续处理CALL
end_:
pop ebx
pop ecx
pop eax
}
}

void GameForm::OnBnClickedBtnAuto()
{
HMODULE hMine = GetModuleHandle(_T("Minesweeper.exe"));
if(hMine==NULL)
{
AfxMessageBox(_T("无法找到模块mineswpeer"));
return;
}
//模块句柄即为基址
DWORD mineBaseAddr = (DWORD)hMine;
const int RVA_top = 0x868B4; //数据基址 RVA
const int RVA_fun = 0x21418; //扫雷CALL RVA
const int RVA_fun2 = 0x26BCD; //后续函数 RVA
const int RVA_fun3 = 0x200BB; //布雷函数 RVA


m_VATOP = mineBaseAddr + (DWORD)RVA_top;
m_VAFUN = mineBaseAddr + (DWORD)RVA_fun;
m_VAFUN2 = mineBaseAddr + (DWORD)RVA_fun2;
m_VAFUN3 = mineBaseAddr + (DWORD)RVA_fun3;

//第一次点击,同时生成布雷信息
HitBlock(0,0,true);

//在第一次点击之后才会有布雷信息,此时获取雷信息
OnBnClickedBtnGetinf();

//开始扫雷
for(int r=0;r<row;r++)
{
for(int col=0;col<column;col++)
{
if(mineInf[r*column+col]!=1)
{
HitBlock(r,col,false);
}
}
}
}

void GameForm::OnBnClickedBtnAuto2()
{
HMODULE hMine = GetModuleHandle(_T("Minesweeper.exe"));
if(hMine==NULL)
{
AfxMessageBox(_T("无法找到模块mineswpeer"));
return;
}
//模块句柄即为基址
DWORD mineBaseAddr = (DWORD)hMine;
const int RVA_top = 0x868B4; //数据基址 RVA
const int RVA_fun = 0x21418; //扫雷CALL RVA
const int RVA_fun2 = 0x26BCD; //后续函数 RVA
const int RVA_fun3 = 0x200BB; //布雷函数 RVA


m_VATOP = mineBaseAddr + (DWORD)RVA_top;
m_VAFUN = mineBaseAddr + (DWORD)RVA_fun;
m_VAFUN2 = mineBaseAddr + (DWORD)RVA_fun2;
m_VAFUN3 = mineBaseAddr + (DWORD)RVA_fun3;

HitBlock2(0,0);
}

void GameForm::HitBlock2(int arow, int acol)
{
int va_top = m_VATOP;
int va_fun = m_VAFUN;
int va_fun2 = m_VAFUN2;
int va_fun3 = m_VAFUN3;
_asm
{
mov esi,va_top
mov esi,[esi]
mov eax,[esi+0x10]
mov edi,arow //行
mov ebx,acol //列
// mov [eax+0x18],0 //edi+18=0,zf=1,第一次
mov [esi+0xC5],1
mov ecx,esi
push edi
push ebx
xor bl,bl
mov eax,va_fun
call eax //第一次点击方块

mov edi,0
mov ebx,0
/* mov eax,[esi+0x10]*/
/* mov [eax+0x18],1*/
row_:
push edi
column_:
push ebx
mov     eax, dword ptr [esi+0x10]
mov     eax, dword ptr [eax+0x44]
mov     eax, dword ptr [eax+0x0C]
mov     eax, dword ptr [eax+ebx*4]
mov     eax, dword ptr [eax+0x0C]
xor ecx, ecx
cmp     byte ptr [edi+eax], cl      //  判断是不是雷
jnz     end_ //  雷跳转到最后
mov [esi+0xC5],1
mov ecx,esi
push edi
push ebx
xor bl,bl
mov eax,va_fun
call eax //调用点击方块CALL
test eax,eax
jg here_
jmp end_
here_:
push eax
mov eax,va_fun2
call eax //后续处理CALL
push 200
mov eax,Sleep
call eax
end_:
pop ebx
inc ebx
mov eax,[esi+0x10]
cmp ebx,[eax+0x0C]
jb column_
pop edi
mov ebx,0
inc edi
cmp edi,[eax+0x08]
jb row_
}
}

================================Form资源=============================
// Dialog

IDD_GAMEFORM DIALOGEX 0, 0, 299, 123
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
    EDITTEXT        IDC_EDIT_MINEINF,7,7,175,109,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | NOT WS_TABSTOP
    PUSHBUTTON      "获取MINE信息",IDC_BTN_GETINF,195,7,97,21
    DEFPUSHBUTTON   "自动扫雷",IDC_BTN_AUTO,195,39,97,21
END
  评论这张
转发至微博
转发至微博
0   分享到:        
阅读(633)| 评论(0)| 引用 (0) |举报

历史上的今天

相关文章

最近读者

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--相关文章--> <#--历史上的今天--> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2012