如何制作内存hack(Minecraft Windows 10)

首先

我将写下关于简单的内存修改技巧。没有什么特别的动机。请自行承担责任进行尝试。
这次我打算写下最简单的实施方式,即实现缩放功能(在Visual Studio中)。

“Memory hacking” refers to

记忆破解是指

Windows上のプロセスの仮想メモリに無理やり書き込み&読み込みをすることで、プロセスの挙動を変えることです。
簡単ですね。それでは具体的にコードを書いていきましょう。

获取基址地址和进程句柄

在Windows系统上,执行一个进程会被分配一个进程ID。可以使用这个进程ID来获取基址和进程句柄。

#include <iostream>
#include <Windows.h>
#include <vector>
#include <TlHelp32.h>

uintptr_t GetProcId(const wchar_t* procname) //プロセスID取得
{
    DWORD ProcId = 0;
    HANDLE hSnap = (CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
    if (hSnap != INVALID_HANDLE_VALUE)
    {
        PROCESSENTRY32 procentry;
        procentry.dwSize = sizeof(procentry);

        if (Process32First(hSnap, &procentry))
        {

            do
            {
                if (!_wcsicmp(procentry.szExeFile, procname))
                {
                    ProcId = procentry.th32ProcessID;
                    break;
                }
            } while (Process32Next(hSnap, &procentry));
        }
    }
    CloseHandle(hSnap);
    return ProcId;
}
uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName)//ベースアドレス取得
{
    uintptr_t modBaseAddr = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
    if (hSnap != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 modEntry;
        modEntry.dwSize = sizeof(modEntry);
        if (Module32First(hSnap, &modEntry))
        {
            do
            {
                if (!_wcsicmp(modEntry.szModule, modName))
                {
                    modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnap, &modEntry));
        }
    }
    CloseHandle(hSnap);
    return modBaseAddr;
}
int main()
{
    DWORD procId = GetProcId(L"Minecraft.Windows.exe");//実行中のMinecraft.Windows.exeのプロセスID
    uintptr_t BaseAddress = GetModuleBaseAddress(procId, L"Minecraft.Windows.exe");//ベースアドレスの取得
    if (BaseAddress != NULL) {
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId);//プロセスハンドル取得
    }
    return 0;
}

接下来我们会继续使用进程ID、基址和进程句柄,所以要先保留它们。

全球键盘钩子的使用方法

一番簡単な方法でやります。

    while (true)
    {
        if (GetAsyncKeyState(67)) {//仮想キーコードを入れる今回はC

        }
    }

ポインターからアドレス取得

ポインターとは毎回プロセスが起動するとアドレスが変わるので、アドレスを計算するために必要なものです。
ポインターを取得する方法は次の記事で詳しく書きます。ここ
ここではそのポインターからアドレスを導き出す関数を書きます。

uintptr_t FindDMAAddy(HANDLE hProc, uintptr_t ptr, std::vector<unsigned int> offsets)
{
    uintptr_t addr = ptr;
    for (unsigned int i = 0; i < offsets.size(); ++i)
    {
        ReadProcessMemory(hProc, (BYTE*)addr, &addr, sizeof(addr), 0);
        addr += offsets[i];
    }
    return addr;
}

関数はこれだけです。使い方は

uintptr_t fovdirectadd = 0x0369BD40;
vector<unsigned int> fovoffset = { 0x28,0x130,0x1E8 };
int main()
{
    DWORD procId = GetProcId(L"Minecraft.Windows.exe");//実行中のMinecraft.Windows.exeのプロセスID
    uintptr_t BaseAddress = GetModuleBaseAddress(procId, L"Minecraft.Windows.exe");//ベースアドレスの取得
    if (BaseAddress != NULL) {
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId);//プロセスハンドル取得
        uintptr_t fovaddr = FindDMAAddy(hProcess, BaseAddress + fovdirectadd, fovoffset);//これが欲しいアドレスです
    }
    return 0;
}

写入

準備はできましたそれでは書き込みをしてみましょう

WriteProcessMemory(hProcess, (BYTE*)Address, &value, sizeof(value), nullptr);

这是用于写入的API。
Address代表地址,value则是想要输入的值的指针,sizeof(value)表示输入值的长度。

整体代码

#include <iostream>
#include <Windows.h>
#include <vector>
#include <TlHelp32.h>

using namespace std;

uintptr_t GetProcId(const wchar_t* procname) //プロセスID取得
{
    DWORD ProcId = 0;
    HANDLE hSnap = (CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
    if (hSnap != INVALID_HANDLE_VALUE)
    {
        PROCESSENTRY32 procentry;
        procentry.dwSize = sizeof(procentry);

        if (Process32First(hSnap, &procentry))
        {

            do
            {
                if (!_wcsicmp(procentry.szExeFile, procname))
                {
                    ProcId = procentry.th32ProcessID;
                    break;
                }
            } while (Process32Next(hSnap, &procentry));
        }
    }
    CloseHandle(hSnap);
    return ProcId;
}
uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName)//ベースアドレス取得
{
    uintptr_t modBaseAddr = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
    if (hSnap != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 modEntry;
        modEntry.dwSize = sizeof(modEntry);
        if (Module32First(hSnap, &modEntry))
        {
            do
            {
                if (!_wcsicmp(modEntry.szModule, modName))
                {
                    modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnap, &modEntry));
        }
    }
    CloseHandle(hSnap);
    return modBaseAddr;
}
uintptr_t fovdirectadd = 0x0369BD40;
vector<unsigned int> fovoffset = { 0x28,0x130,0x1E8 };
uintptr_t FindDMAAddy(HANDLE hProc, uintptr_t ptr, std::vector<unsigned int> offsets)
{
    uintptr_t addr = ptr;
    for (unsigned int i = 0; i < offsets.size(); ++i)
    {
        ReadProcessMemory(hProc, (BYTE*)addr, &addr, sizeof(addr), 0);
        addr += offsets[i];
    }
    return addr;
}
int main()
{
    DWORD procId = GetProcId(L"Minecraft.Windows.exe");//実行中のMinecraft.Windows.exeのプロセスID
    uintptr_t BaseAddress = GetModuleBaseAddress(procId, L"Minecraft.Windows.exe");//ベースアドレスの取得
    if (BaseAddress != NULL) {
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId);//プロセスハンドル取得
        uintptr_t fovaddr = FindDMAAddy(hProcess, BaseAddress + fovdirectadd, fovoffset);//これが欲しいアドレスです
        float value = 0.0f;
        while (true)
        {
            if (GetAsyncKeyState(67)) {
                value = 30.0f;
                WriteProcessMemory(hProcess, (BYTE*)fovaddr, &value, sizeof(value), nullptr);
            }
            else {
                value = 110.0f;
                WriteProcessMemory(hProcess, (BYTE*)fovaddr, &value, sizeof(value), nullptr);
            }
        }
    }
    return 0;
}
Minecraft 2021_03_02 9_51_23.png

最后

我们使用这种技术几乎可以做任何事情。甚至可以轻松制作恶意黑客软件。所以请绝对不要滥用。指针扫描的方法将在下次讲解。

请参考

引导式的黑客攻击
获取异步按键状态