写程序写不动的时候就想找个有意思的话题讨论一下,来说说“挖”地雷的方法(直接改成绩文件不算)。如果谁有更多更好的方法,欢迎一块说说。我的手很笨,不怕大家笑话,挖地雷从来没有低过 140(从Windows3.1开始),所以有时候就想做个程序“辅助一下”。其实关于挖雷的技术讨论文章很可能已经有无数了,不过我没特别去找,见过的也不多。所以今天提出来说说,如果有高手已经讨论过了,麻烦给留几个文章的链接。方法 1: 让程序替我们挖先人工挖开一片“空地”,然后启动我们的程序,读扫雷程序的 Window 的界面 DC,然后进行简单的图像提取,提取出已经挖开的空地内的所有数字,设计一个算法计算哪些方块下面有地雷,以此向扫雷的 Window 发鼠标消息(左、右单击),看着扫雷的界面一块一块的展开,直到必须人工“蒙”的时候,人工干预一下。如果算法写不好可能比较慢(但比我自己挖快多了)。
前几天在清华的BBS上看到了一个人用 Java 写的这样一个程序,具体位置记不清了。方法 2: 打开地雷图我们自己挖启动扫雷程序后,启动我们的程序,然后做两个事情:一,把扫雷程序的 Windows 设置成透明的(Alpha值稍大于0,只能在win2k、xp上),把我们的程序做成界面与扫雷的一模一样,但不透明,然后放到扫雷程序的 Window 的后面。二,从扫雷程序的进程地址中读取内部数据,得到每个地雷的位置,然后显示在我们的程序的界面上,哈哈,是不是感觉地雷图已经打开了,我们只要狂点扫雷程序的没有地雷的地方就可以了。
CSDN 上有一篇文章讲如何从扫雷进程中取得地图数据:http://www.csdn.net/develop/Article/19/19921.shtm方法 3: 程序自己打开地图自己挖我们的程序从扫雷进程中取得地图数据,然后向扫雷程序的 Window 发一堆鼠标消息(左、右单击),直接将所有地雷挖出来。估计会很快,但是不是没什么乐趣了?方法 4: 恶作剧我们的程序从扫雷进程中取得地图数据,然后生成地雷已经全挖开的结果界面(位图),然后直接将位图写到扫雷程序的 Window 的 DC 中,结果会怎么样?是不是如果鼠标点的话,地雷已经全挖开了,而计时器仍然在跳?方法 5: 停止计时器这是我实际做过的一个方法。我们的程序运行时,向系统中塞进去一个消息钩子,把扫雷程序的 Window 的 WM_TIMER 改掉,想开始计时再改回来。这样,我可以心安理得的挨个判断地雷,不用担心计时器,可是到头来却发现扫雷变成了10以内的数学判断。方法 6: 让扫雷程序自己挖开我们的程序运行的时候,替换掉扫雷进程的某断代码或塞进去一个钩子,结果是点击那个小黄脸的时候,地图就全挖开了。关于这个方法我只是猜想,没有实际的经验,只能估计可行。

解决方案 »

  1.   

    windows里面的那个不是有一个后门吗?
      

  2.   

    我记得windows中,点击鼠标左键的同时,好象是按住ESC键,然后松开,就可以将计时器定住
    你试试
      

  3.   

    在win95年代,我们老师挖雷最好记录是79秒
      

  4.   

    哈哈,扫雷好象有BUG上次我挖只用了1S
      

  5.   

    写了一个自动扫雷的
    class CProcessMem : public CWnd
    {public:
    CProcessMem();
    bool InitModule (HWND hWnd);
    bool InitModule (DWORD processID);
    bool InitModule (CString wndTitle); bool ReadVal (DWORD iAddress, BYTE &value);
    bool WriteVal (DWORD iAddress, BYTE value); bool ReadVal (DWORD iAddress, short int &value);
    bool WriteVal (DWORD iAddress, short int value);

    bool ReadVal (DWORD iAddress, int &value);
    bool WriteVal (DWORD iAddress, int value); bool ReadVal (DWORD iAddress, CString &text);
    bool WriteVal (DWORD iAddress, CString text); virtual ~CProcessMem();

    CString m_sError; struct _ProcessInfo {
    CString windowTitle;
    DWORD pID;
    DWORD dwPageSize;
    HANDLE hProcess;
    LPVOID lpMinAppAddress;
    LPVOID lpMaxAppAddress;
    } ProcessInfo;private: // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CProcessMem)
    //}}AFX_VIRTUALprotected:
    //{{AFX_MSG(CProcessMem)
    // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };自动扫雷代码(中文Win2000):CProcessMem m_mem;
    m_mem.InitModule("扫雷");
    DWORD address=0;
    int m_width;
    int m_height;
    int m_mineNum;
    /*
    int iMinesAddress = 0x10052C4;
    int iHeightAddress = 0x10052C8;
    int iWidthAddress = 0x10052CC;
    int iCellBaseAddress = 0x1005720;
    */
    sscanf("0x010052C4","%x",&address);
    m_mem.ReadVal(address,m_mineNum); sscanf("0x010052C8","%x",&address);
    m_mem.ReadVal(address,m_width); sscanf("0x010052CC","%x",&address);
    m_mem.ReadVal(address,m_height); HWND hDestWnd=::FindWindow(NULL,"扫雷");
    int yOffset=62;
    int xOffset=19;

    if(hDestWnd){
    ::BringWindowToTop(hDestWnd);
    ::SetForegroundWindow(hDestWnd);
    ::SetFocus(hDestWnd); DWORD address=0;
    sscanf("0x010052C4","%x",&address);
    m_mem.ReadVal(address,m_mineNum); sscanf("0x010052C8","%x",&address);
    m_mem.ReadVal(address,m_width); sscanf("0x010052CC","%x",&address);
    m_mem.ReadVal(address,m_height); sscanf("0x01005720","%x",&address);
    BYTE bValue;
    srand( (unsigned)time( NULL ) );
    for(int row=0;row<m_width;row++){
    for(int col=0;col<m_height;col++){
    bValue=0x0F;
    m_mem.ReadVal(address+32*row+col+1,bValue);
    if(bValue!=0x8F){
    ::SendMessage(hDestWnd,WM_LBUTTONDOWN,0,MAKELPARAM(xOffset+16*col,yOffset+16*row));
    ::SendMessage(hDestWnd,WM_LBUTTONUP,0,MAKELPARAM(xOffset+16*col,yOffset+16*row));
    }
    }
    }
    }
      

  6.   

    CProcessMem::CProcessMem()
    {
    ProcessInfo.dwPageSize = 0;
    ProcessInfo.lpMaxAppAddress = 0;
    ProcessInfo.lpMinAppAddress = 0;
    ProcessInfo.pID = 0;
    ProcessInfo.hProcess = 0;
    }CProcessMem::~CProcessMem()
    {
    CloseHandle(ProcessInfo.hProcess);
    }
    BEGIN_MESSAGE_MAP(CProcessMem, CWnd)
    //{{AFX_MSG_MAP(CProcessMem)
    // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    /////////////////////////////////////////////////////////////////////////////
    // CProcessMem message handlers
    bool CProcessMem::InitModule(CString wndTitle)
    {
    HWND hwnd = GetForegroundWindow()->GetSafeHwnd();
    CWnd cWnd;
    CString wndtext; if (wndTitle.IsEmpty())
    {
    m_sError = _T("wndTitle is empty.");
    return FALSE;
    } for(int i=0;i<1000;i++)
    {
    hwnd = ::GetNextWindow(hwnd,GW_HWNDNEXT);

    if(!IsWindow(hwnd))
    break;

    cWnd.Attach(hwnd);
    cWnd.GetWindowText(wndtext);

    if(wndtext==wndTitle)
    break;
    cWnd.Detach();
    }

    if(wndtext!=wndTitle)
    {
    m_sError = _T("No window found with matching title.");
    return FALSE;
    } ProcessInfo.windowTitle = wndTitle;

    GetWindowThreadProcessId(cWnd.GetSafeHwnd(),&ProcessInfo.pID);
    cWnd.Detach(); InitModule(ProcessInfo.pID);
    m_sError.Empty();
    return TRUE;
    }
    bool CProcessMem::InitModule(HWND hWnd)
    {
    if(!IsWindow(hWnd) || hWnd == 0)
    {
    m_sError = _T("hWnd handle invalid.");
    return FALSE;
    } GetWindowThreadProcessId(hWnd,&ProcessInfo.pID);
    InitModule(ProcessInfo.pID); m_sError.Empty();
    return TRUE;
    }bool CProcessMem::InitModule(DWORD processID)
    {
    SetLastError(0); SYSTEM_INFO sysinfo; CloseHandle(ProcessInfo.hProcess); ProcessInfo.pID = processID;
    // Note: This function will only work if the user has ADMIN access
    ProcessInfo.hProcess = OpenProcess(PROCESS_VM_READ|PROCESS_VM_WRITE|
    PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION, FALSE, ProcessInfo.pID);

    if(GetLastError()!=0)
    {
    m_sError = _T("Failed to open the Proccess. Use GetLastError() for further information.");
    return FALSE;
    }

    GetSystemInfo(&sysinfo);
    ProcessInfo.lpMinAppAddress = sysinfo.lpMinimumApplicationAddress;
    ProcessInfo.lpMaxAppAddress = sysinfo.lpMaximumApplicationAddress;
    ProcessInfo.dwPageSize = sysinfo.dwPageSize;

    m_sError.Empty();
    return TRUE;
    }bool CProcessMem::ReadVal(DWORD iAddress, int &value)
    {
    // Reads 4 bytes
    DWORD dummy; if (!ReadProcessMemory(ProcessInfo.hProcess,(void*) iAddress,
    (void*) &value,sizeof(value),&dummy))
    {
    m_sError = _T("Failed to read memory.");
    return FALSE;
    }

    m_sError.Empty();
    return TRUE;
    }
    bool CProcessMem::WriteVal(DWORD iAddress, int value)
    {
    // Writes 4 bytes

    DWORD dummy;
    if (!WriteProcessMemory(ProcessInfo.hProcess,(void*) iAddress,
    (void*) &value,sizeof(value),&dummy))
    {
    m_sError = _T("Failed to write to memory.");
    return FALSE;
    }

    m_sError.Empty();
    return TRUE;
    }bool CProcessMem::ReadVal(DWORD iAddress, short int &value)
    {
    // Reads 2 bytes
    DWORD dummy; if (!ReadProcessMemory(ProcessInfo.hProcess,(void*) iAddress,
    (void*) &value,sizeof(value),&dummy))
    {
    m_sError = _T("Failed to read memory.");
    return FALSE;
    }

    m_sError.Empty();
    return TRUE;
    }bool CProcessMem::WriteVal(DWORD iAddress, short int value)
    {
    // Writes 4 bytes

    DWORD dummy;
    if (!WriteProcessMemory(ProcessInfo.hProcess,(void*) iAddress,
    (void*) &value,sizeof(value),&dummy))
    {
    m_sError = _T("Failed to write to memory.");
    return FALSE;
    }

    m_sError.Empty();
    return TRUE;
    }bool CProcessMem::ReadVal(DWORD iAddress, BYTE &value)
    {
    // Reads 1 byte
    DWORD dummy; if (!ReadProcessMemory(ProcessInfo.hProcess,(void*) iAddress,
    (void*) &value,sizeof(value),&dummy))
    {
    m_sError = _T("Failed to read memory.");
    return FALSE;
    }

    m_sError.Empty();
    return TRUE;
    }bool CProcessMem::WriteVal(DWORD iAddress, BYTE value)
    {
    // Writes 1 byte

    DWORD dummy;
    if (!WriteProcessMemory(ProcessInfo.hProcess,(void*) iAddress,
    (void*) &value,sizeof(value),&dummy))
    {
    m_sError = _T("Failed to write to memory.");
    return FALSE;
    }

    m_sError.Empty();
    return TRUE;
    }bool CProcessMem::ReadVal(DWORD iAddress, CString &text)
    {
    // Reads 1024 bytes and returns the memory block as a CString
    DWORD dummy;
    char buffer[1024]; if (!ReadProcessMemory(ProcessInfo.hProcess,(void*) iAddress,
    (void*) &buffer,1024,&dummy))
    {
    m_sError = _T("Failed to read memory.");
    return FALSE;
    }

    text = buffer;
    m_sError.Empty();
    return TRUE;
    }bool CProcessMem::WriteVal(DWORD iAddress, CString text)
    {
    DWORD dummy;
    char buffer[1024]; strcpy(buffer,text);

    buffer[text.GetLength()] = '\0'; if(text.GetLength()>= 1024)
    {
    m_sError = _T("Cannot write strings longer than 1024 characters");
    return FALSE;
    }

    if (!WriteProcessMemory(ProcessInfo.hProcess,(void*) iAddress,
    (void*) &buffer,text.GetLength()+1,&dummy))
    {
    m_sError = _T("Failed to read memory.");
    return FALSE;
    } m_sError.Empty();
    return TRUE;
    }