天天看點

C++基礎之:掃雷破解

版權聲明:

  • 本文原創釋出于部落格園"優夢創客"的部落格空間(網址:

    http://www.cnblogs.com/raymondking123/

    )以及微信公衆号"優夢創客"
  • 您可以***轉載,但必須加入完整的版權聲明!

記憶體掃描

使用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();
}