LoginSignup
3
3

More than 3 years have passed since last update.

メモリハックの作り方(Minecraft Windows 10)

Last updated at Posted at 2021-03-02

はじめに

簡単なメモリハックの仕方について書いていきます。動機などありません。試す方は自己責任でやってください。
今回は一番簡単であるズーム機能を実装する方法を書いていこうと思います(Visual Studio)

メモリハックとは

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;
}

できましたね。これはCキーを押すとズームをするコードです。
ビルドするときはx64を選びましょう。
Minecraft 2021_03_02 9_51_19.png
Minecraft 2021_03_02 9_51_23.png
ちゃんとCキーを押すとズームされるようになってますね!

最後に

この技術を使えばほぼ何でもできてしまいます。悪質なハックも簡単に作れてしまいます。
なので絶対に悪用はしないでください。
ポインタースキャンの仕方は次回やります
次回

参考

Guided hacking
GetAsyncKetState

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3