内容纲要

内存扫描

使用Cheat Engine这款软件对扫雷的进程的内存进行扫描。查找与游戏获胜相关的内存区域。
扫描结果如下:

<?xml version="1.0" encoding="utf-8"?>
<CheatTable CheatEngineTableVersion="26">
  <CheatEntries>
    <CheatEntry>
      <ID>0</ID>
      <Description>"棋盘首地址"</Description>
      <LastState Value="15" RealAddress="01005361"/>
      <VariableType>Byte</VariableType>
      <Address>扫雷.exe+5361</Address>
    </CheatEntry>
    <CheatEntry>
      <ID>1</ID>
      <Description>"玩家未确定的地雷数"</Description>
      <LastState Value="10" RealAddress="01005194"/>
      <VariableType>Byte</VariableType>
      <Address>扫雷.exe+5194</Address>
    </CheatEntry>
  </CheatEntries>
  <UserdefinedSymbols/>
</CheatTable>

代码跟踪

使用x32dbg工具调试扫雷的进程,追踪扫雷代码。发现扫雷的判断条件是内存0x010057A4和0x010057A0值是否相等。
判定代码在代码段的0x0100359c区域。

破解

获取扫雷窗口句柄
获取扫雷进程号
获取扫雷进程句柄
修改代码段内存的保护属性
修改判定代码

详细代码
Injection.h

#pragma once

#include <string>
#include <Windows.h>
//#define ___DEBUG
class Injection
{
public:
    Injection(const char*);
    bool Init();
    bool DoInjection();
    void UnInit();
private:
    std::wstring className;
    HWND hw;
    DWORD pid; 
    HANDLE hp; 
    SIZE_T wr;
};

Injection.cpp

#include "stdafx.h"
#include "Injection.h"
#include <comutil.h> 
#pragma comment(lib, "comsuppw.lib")

Injection::Injection(const char * className)
    :hw(0), pid(0), hp(0), wr(0)
{
    _bstr_t tmp = className;
    this->className = (wchar_t*)tmp;
}

bool Injection::Init()
{
    hw = FindWindow(this->className.c_str(), NULL);
    if (hw) printf("找到目标进程窗口,窗口句柄:%X\n", hw);
    else return false;

    GetWindowThreadProcessId(hw, &pid);
    if(pid) printf("成功获取目标进程号:%d\n", pid);
    else return false;

    hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (hp) printf("成功获取目标进程句柄:%X\n", hp);
    else return false;

    return true;
}
// 0x010057A4
// 0x010057A0

// 0x0100359c
bool Injection::DoInjection()
{
#ifndef ___DEBUG
    if (VirtualProtectEx(hp, (int*)0x0100359c, 5, PAGE_EXECUTE_READWRITE, &wr))
        printf("成功修改代码段内存保护属性\n");
    else return false;
    // mov eax, dword ptr ds : [0x010057A0]
    char a[] = { 0xA1, 0xA0, 0x57, 0x00, 0x01 };
    if (WriteProcessMemory(hp, (int*)0x0100359c, a, 5, &wr))
        printf("成功修改内存\n");
    else return false;
#endif
    return true;
}

void Injection::UnInit()
{
    CloseHandle(hp);
}

main.cpp

#include"Injection.h"

void main(int argc, char *argv[])
{
#ifndef ___DEBUG
    if (!argc)
        return;
    Injection inj(argv[1]);
#else
    Injection inj("扫雷");
#endif // !1
    if (inj.Init()) printf("Init Success!\n");
    else return;
    inj.DoInjection();
    inj.UnInit();
}

1 对 “Windows XP版 扫雷的破解(一键获胜)”的想法;

  1. Pingback: viagra

发表评论