CE自动汇编之CPP实现[CPP][FPS游戏]

#声明本文章只用于学习与研究,请勿用于犯法!

  · WriteProcessMemory与ReadProcessMemory

引言 · 相信每个热爱逆向的你最开始都是从植物大战僵尸开始的,先找数值再找偏移测试用ReadProcessMemory读取在用WriteProcessMemory进行修改,可学到后面可就不是简简单单的修改数值了,有些功能需要通过汇编注入的形式来实现。

如果你能搜到此篇文章就代表你已经掌握通过ce的自动汇编来修改,先上代码

#include <windows.h>
#include <tlhelp32.h>
#include <vector>
#include <string>
#include <stdexcept>
#include <sstream>
#include <cwchar>


class MusicBox_RemoteMemoryPatcher {
private:
    // 核心成员变量
    DWORD               m_dwProcessId;       // PID
    std::wstring        m_wsModuleName;      // 目标模块名
    DWORD_PTR           m_dwModuleOffset;    // 模块内偏移地址
    std::vector<BYTE>   m_vPatchData;        // 注入数据缓冲区
    std::vector<BYTE>   m_vOriginalData;     // 原始数据缓冲区
    HANDLE              m_hProcess;          // 进程句柄
    DWORD_PTR           m_dwModuleBase;      // 模块基址
    DWORD               m_dwOldProtect;      // 原始内存保护属性缓存
    DWORD_PTR GetRemoteModuleBase() {
        HANDLE hSnapshot = CreateToolhelp32Snapshot(
            TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
            m_dwProcessId
        );
        if (hSnapshot == INVALID_HANDLE_VALUE) {
            throw std::runtime_error(
                "CreateToolhelp32Snapshot 失败: " + std::to_string(GetLastError())
            );
        }
        MODULEENTRY32W stModuleInfo = { 0 };
        stModuleInfo.dwSize = sizeof(MODULEENTRY32W);
        DWORD_PTR dwModuleBase = 0;

        if (Module32FirstW(hSnapshot, &stModuleInfo)) {
            do {
                if (_wcsicmp(stModuleInfo.szModule, m_wsModuleName.c_str()) == 0) {
                    dwModuleBase = reinterpret_cast<DWORD_PTR>(stModuleInfo.modBaseAddr);
                    break;
                }
            } while (Module32NextW(hSnapshot, &stModuleInfo));
        }

        CloseHandle(hSnapshot);
        if (dwModuleBase == 0) {
            std::string sModuleName(m_wsModuleName.begin(), m_wsModuleName.end());
            throw std::runtime_error("未找到模块->" + sModuleName);
        }

        return dwModuleBase;
    }
    void OpenTargetProcess() {
        m_hProcess = OpenProcess(
            PROCESS_ALL_ACCESS, 
            FALSE,      
            m_dwProcessId
        );
        if (m_hProcess == NULL) {
            throw std::runtime_error(
                "OpenProcess 失败: " + std::to_string(GetLastError())
            );
        }
    }
    void ModifyMemoryProtect(DWORD_PTR dwAddress, SIZE_T dwSize, DWORD flNewProtect) {
        if (!VirtualProtectEx(
            m_hProcess,
            reinterpret_cast<LPVOID>(dwAddress),
            dwSize,
            flNewProtect,
            &m_dwOldProtect
        )) {
            throw std::runtime_error(
                "VirtualProtectEx 失败: " + std::to_string(GetLastError())
            );
        }
    }
    void RestoreMemoryProtect(DWORD_PTR dwAddress, SIZE_T dwSize) noexcept {
        VirtualProtectEx(
            m_hProcess,
            reinterpret_cast<LPVOID>(dwAddress),
            dwSize,
            m_dwOldProtect,
            &m_dwOldProtect
        );
    }
    void WriteRemoteMemory(DWORD_PTR dwAddress, const std::vector<BYTE>& vData) {
        SIZE_T dwWritten = 0;
        if (!WriteProcessMemory(
            m_hProcess,
            reinterpret_cast<LPVOID>(dwAddress),
            vData.data(),
            vData.size(),
            &dwWritten
        )) {
            throw std::runtime_error(
                "WriteProcessMemory 失败: " + std::to_string(GetLastError())
            );
        }

        // 验证写入长度
        if (dwWritten != vData.size()) {
            std::stringstream ss;
            throw std::runtime_error(ss.str());
        }
    }

public:
    MusicBox_RemoteMemoryPatcher(
        DWORD dwProcessId,
        const std::wstring& wsModuleName,
        DWORD_PTR dwModuleOffset,
        const BYTE* pPatchData,
        SIZE_T dwPatchSize,
        const BYTE* pOriginalData,
        SIZE_T dwOriginalSize
    ) : m_dwProcessId(dwProcessId),
        m_wsModuleName(wsModuleName),
        m_dwModuleOffset(dwModuleOffset),
        m_hProcess(NULL),
        m_dwModuleBase(0),
        m_dwOldProtect(0) {

        // 验证数据有效性
        if (pPatchData == nullptr || dwPatchSize == 0) {
            throw std::invalid_argument("补丁数据不能为空");
        }
        if (pOriginalData == nullptr || dwOriginalSize == 0) {
            throw std::invalid_argument("原始数据不能为空");
        }

        // 初始化数据缓冲区
        m_vPatchData.assign(pPatchData, pPatchData + dwPatchSize);
        m_vOriginalData.assign(pOriginalData, pOriginalData + dwOriginalSize);

        // 打开目标进程
        OpenTargetProcess();

        // 获取模块基址
        m_dwModuleBase = GetRemoteModuleBase();
    }


    ~MusicBox_RemoteMemoryPatcher() noexcept {
        if (m_hProcess != NULL) {
            CloseHandle(m_hProcess);
            m_hProcess = NULL;
        }
    }

    void EnablePatch() {
        DWORD_PTR dwTargetAddr = m_dwModuleBase + m_dwModuleOffset;

        try {
            ModifyMemoryProtect(dwTargetAddr, m_vPatchData.size(), PAGE_EXECUTE_READWRITE);
            WriteRemoteMemory(dwTargetAddr, m_vPatchData);
            RestoreMemoryProtect(dwTargetAddr, m_vPatchData.size());
        }
        catch (const std::exception& e) {
            RestoreMemoryProtect(dwTargetAddr, m_vPatchData.size());
            throw; 
        }
    }

    void DisablePatch() {
        DWORD_PTR dwTargetAddr = m_dwModuleBase + m_dwModuleOffset;

        try {
            ModifyMemoryProtect(dwTargetAddr, m_vOriginalData.size(), PAGE_EXECUTE_READWRITE);
            WriteRemoteMemory(dwTargetAddr, m_vOriginalData);
            RestoreMemoryProtect(dwTargetAddr, m_vOriginalData.size());
        }
        catch (const std::exception& e) {
            RestoreMemoryProtect(dwTargetAddr, m_vOriginalData.size());
            throw;
        }
    }
    DWORD_PTR GetModuleBase() const noexcept {
        return m_dwModuleBase;
    }
    DWORD_PTR GetTargetAddress() const noexcept {
        return m_dwModuleBase + m_dwModuleOffset;
    }
    DWORD GetProcessId() const noexcept {
        return m_dwProcessId;
    }
};

实用实例

 BYTE patch[] = { 0xE9, 0xE7, 0x00, 0x00, 0x00, 0x90 };
 BYTE original[] = { 0x0F, 0x8E, 0xE6, 0x00, 0x00, 0x00, 0x8B, 0x43, 0x08, 0x3B, 0x46 };



 MusicBox_RemoteMemoryPatcher patcher(
     g_miniWorldPid,                  // 进程ID
     L"libSandboxEngine.dll",          // 目标模块名
     0x5842BB,                         // 模块内偏移
     patch, sizeof(patch),             // 注入数据+长度
     original, sizeof(original)        // 原始数据+长度
 );

 //启用注入
 patcher.EnablePatch();
 //恢复
 patcher.DisablePatch();

好让我们来解析一下调用

patch[]列表储存这是这个->

original列表储存这是这个->

被 MusicBox_RemoteMemoryPatcher定义的patcher具有两个功能函数,一个是.EnablePatch()为开启(也就是将patch注入到进程中)  一个是.DisablePatch()他是用于恢复(也就是达到关闭的效果将原本的original重新注入回去)

结语:不管是汇编注入还是简单的修改内存本质上都是对游戏创作者心血的亵渎与诋毁所以我本人不倡导、但是还是热爱逆向,如果这篇题材对你有用不妨留下你的痕迹。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值