qt 取进程列表,读写内存, 写字节集
阅读原文时间:2023年07月12日阅读:1
  1. 导入库 pro

    win32:LIBS += -lpsapi
    win32:LIBS += -lkernel32

  2. 获取列表

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    void MainWindow::on_pushButton_2_clicked()
    {
    DWORD PID = 0;
    // 获取进程标识符列表。
    DWORD aProcesses[1024], cbNeeded;

    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
    {
        qDebug() << "获取失败";
        return;
    }
    
    // 计算返回了多少个进程标识符。
    unsigned int cProcesses = cbNeeded / sizeof(DWORD);
    
    // 打印每个进程的名称和进程标识符。
    unsigned int i;
    for ( i = 0; i < cProcesses; i++ )
    {
        DWORD processID = aProcesses[i];
        if(processID == 0 ) continue;
    char buff[255];
    // 打开现有的本地过程对象
    HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |PROCESS_VM_READ,FALSE, processID );
    if(hProcess == NULL)continue;
    
    // 获取进程名称。
    HMODULE hMod;
    DWORD cbNeeded;
    
    if (EnumProcessModules(hProcess, &amp;hMod, sizeof(hMod),&amp;cbNeeded) )
    {
        GetModuleBaseNameA(hProcess, hMod, (LPSTR)&amp;buff, DWORD(sizeof(buff)/sizeof(char)));
    }
    
    QString s= QString::fromLocal8Bit(buff);
    if(s == "game2.exe"){
        PID = processID;
        break;
    }
    
    // 释放该过程的句柄。
    CloseHandle( hProcess );
    } if(PID == 0) return; // 获取进程所有访问权限 https://docs.microsoft.com/zh-cn/windows/win32/procthread/process-security-and-access-rights HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, PID); if(hProcess == NULL) return; // 读内存 https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-readprocessmemory int hpAddress = 0x004B3724; int hp; // 进程句柄, 内存地址, 值引用,值的字节大小, null ReadProcessMemory(hProcess, (LPCVOID)hpAddress, &hp, sizeof(hp), 0); qDebug() << hp; // 写内存 https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory // 注:这里的int是4字节类型,如果是单浮点那么你就要用float,虽然两个都是4字节,但是就是会出问题 int newHP = 100; if(WriteProcessMemory(hProcess, (LPVOID)hpAddress, (LPCVOID)&newHP, sizeof(newHP), 0 )){ qDebug() << "写入ok."; } CloseHandle(hProcess);

    }

  3. 先在CE中获取基址,如:

    上面找到的基址就是"Game.exe"+00ABBBB0,就算重启游戏后,这个地址也不会变,然后按照对应的偏移量,更着读下去,就能获取到最后的值

  4. 编写代码

    // 获取人物当前的x坐标
    float Game::getX()
    {
    // 基址 "Game.exe"+00ABBBB0 => 8A0000+00ABBBB0
    int x;

    // 第0层
    ReadProcessMemory(gameProcess, (LPCVOID)(9043968+11254704), &x, 4, 0);
    qDebug() << "第0层: " << x;
    
    // 第1次层 偏移48位,这里转为10进制来运算
    ReadProcessMemory(gameProcess, (LPCVOID)(x+72), &x, 4, 0);
    qDebug() << "第1层: " <<x;
    
    // 第2层,将第1层的结果偏移8位
    ReadProcessMemory(gameProcess, LPCVOID(x+8), &x, 4, 0);
    qDebug() << "第2层: " <<x;
    
    // 第3层,将第2层的结果偏移14位
    ReadProcessMemory(gameProcess, LPCVOID(x+20), &x, 4, 0);
    qDebug() << "第3层: " <<x;
    
    // 第4层,将第3层的结果偏移2c位
    x += 44;
    qDebug() << "第4层: " <<x;
    
    // 获取结果,如果要修改内存也可以在这里修改
    float r;
    ReadProcessMemory(gameProcess, LPCVOID(x), &r, 4, 0);
    qDebug() << "x: " << r;
    
    return r;

    }

上面的"Game.exe"+00ABBBB0 = 0135bbb0,然后0135bbb0 - 00ABBBB0 = 8A0000

  1. 打印结果,这里全部是10进制,箭头后面的16进制手动加上去的

    第0层: 30277160 -> 1CD FE28
    第1层: 30034224 -> 1CA 4930
    第2层: 719894592 -> 2AE8 B840
    第3层: 882993840 -> 34A1 6AB0
    第4层: 882993884 -> 34A1 6ADC‬
    x: 455.14

旧的:

00401881 - 83 E8 01 - sub eax,01

新的:

00401881 - 83 c0 02 - add eax,02

注:00401881是基址

代码:

    DWORD PID = 0;
    DWORD aProcesses[1024], cbNeeded;

    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
    {
        qDebug() << "获取失败";
        return;
    }

    unsigned int cProcesses = cbNeeded / sizeof(DWORD);
    unsigned int i;
    for ( i = 0; i < cProcesses; i++ )
    {
        DWORD processID = aProcesses[i];
        if(processID == 0 ) continue;

        char buff[255];
        HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |PROCESS_VM_READ,FALSE, processID );
        if(hProcess == NULL)continue;
        HMODULE hMod;
        DWORD cbNeeded;

        if (EnumProcessModules(hProcess, &hMod, sizeof(hMod),&cbNeeded) )
        {
            GetModuleBaseNameA(hProcess, hMod, (LPSTR)&buff, DWORD(sizeof(buff)/sizeof(char)));
        }

        QString s= QString::fromLocal8Bit(buff);
        if(s == "xxx.exe"){
            PID = processID;
            break;
        }
        CloseHandle( hProcess );
    }

    if(PID == 0) return;

    // 进程句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, PID);
    if(hProcess == NULL) return;

    // 要写入的字节集
    BYTE data[3] = {0x83, 0xc0, 0x02};
    int r = WriteProcessMemory(hProcess, LPVOID(0x401881), LPCVOID(data), SIZE_T(3), NULL);
    qDebug() << r;

    // 写入成功后,再次点击就能发现每次-1变成了+2

参考:

  • https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocesses

  • https://docs.microsoft.com/windows/desktop/psapi/enumerating-all-processes

  • https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulebasenamea

  • https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess

  • https://github.com/januwA/game-reversed-study/blob/master/cpp-hack.md

    #include
    #include
    #include

    DWORD findPID(std::string name)
    {
    DWORD PID = 0;
    // 获取进程标识符列表。
    DWORD aProcesses[1024], cbNeeded;

    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
    {
        std::cout << "EnumProcesses Error." << std::endl;
        return PID;
    }
    unsigned int cProcesses = cbNeeded / sizeof(DWORD);
    unsigned int i;
    for (i = 0; i < cProcesses; i++)
    {
        DWORD processID = aProcesses[i];
        if (processID == 0) continue;
        char buff[255];
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
        if (hProcess == NULL) continue;
    HMODULE hMod;
    DWORD cbNeeded;
    if (EnumProcessModules(hProcess, &amp;hMod, sizeof(hMod), &amp;cbNeeded))
    {
        GetModuleBaseNameA(hProcess, hMod, (LPSTR)&amp;buff, DWORD(sizeof(buff) / sizeof(char)));
    }
    if (buff == name) {
        PID = processID;
        break;
    }
    CloseHandle(hProcess);
    } return PID;

    };

    int main()
    {
    DWORD PID = findPID("Game.exe");
    if (!PID)
    {
    printf("程序没找到");
    return 0;
    }

    // 我编写的DLL
    LPCSTR myDLLPath = "C:\\Users\\ajanuw\\Desktop\\injectDll\\Release\\injectDll.dll";
    int nSize = strlen(myDLLPath) + 1;
    
    // 打开一个现有的本地过程对象
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
    
    // 在指定进程的虚拟地址空间内保留,提交或更改内存区域的状态。
    // 该函数将其分配的内存初始化为零。
    LPVOID pDLLPath = VirtualAllocEx(hProcess, 0, nSize,
        MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    
    // 在指定的进程中将数据写入内存区域。
    // 必须写入整个区域,否则操作将失败。
    BOOL writeOk = WriteProcessMemory(hProcess, pDLLPath, LPCVOID(myDLLPath), nSize, 0);
    
    // 创建一个在另一个进程的虚拟地址空间中运行的线程。
    HANDLE pLoadThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA,
        pDLLPath, 0, 0);
    
    // 等待直到指定的对象处于发信号状态或超时间隔过去
    WaitForSingleObject(pLoadThread, INFINITE);
    
    if (pLoadThread == NULL) {
        std::cout << "pLoadThread error." << std::endl;
        return 0;
    }
    else CloseHandle(pLoadThread);
    
    if (hProcess) CloseHandle(hProcess);
    
    // std::cout << "DLL path alloc at: " << pDLLPath << std::endl;
    // std::cin.get();
    
    // 在指定进程的虚拟地址空间内释放,解除授权或释放并解除授权的内存区域。
    // VirtualFreeEx(hProcess,pDLLPath, strlen(myDLLPath) + 1,MEM_RELEASE);
    
    return 0;

    }

injectDll.cpp:

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <Windows.h>
#include <iostream>

void Mythread(HMODULE hModule)
{

    std::cout << "<------------------------->" << std::endl;
    std::cout << "inject dll" << std::endl;
    std::cout << "<------------------------->" << std::endl;
    Sleep(3000);
    MessageBoxA(0, "a", "b", 0);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CloseHandle(CreateThread(0,0, (LPTHREAD_START_ROUTINE)Mythread, hModule, 0, 0));
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }

    return TRUE;
}
  • GetProcAddress

  • DLL也能调用DLL

    #include
    #include

    typedef void (CALLBACK* LPFNDLLFUNC1)();

    int main()
    {
    LPFNDLLFUNC1 fun;
    // 获取DLL中的a函数,LPFNDLLFUNC1类型对上
    fun = (LPFNDLLFUNC1)GetProcAddress(
    // or LoadLibrary(TEXT("C:\Users\ajanuw\Desktop\Game\Debug\ADll.dll")),
    GetModuleHandle(TEXT("C:\Users\ajanuw\Desktop\Game\Debug\ADll.dll")),
    "a"
    );
    if (NULL != fun)
    {
    fun();
    }
    else {
    std::cout << "GetProcAddress error." << std::endl;
    }

    return 0;

    }

    #include
    #include
    #include

    using namespace std;

    DWORD getPID(const wchar_t* name)
    {
    DWORD pid = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE)
    {
    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(pe);
    if (Process32First(hSnap, &pe))
    {
    do {
    if (!_wcsicmp(pe.szExeFile, name)) {
    pid = pe.th32ProcessID;
    break;
    }
    } while (Process32Next(hSnap, &pe));
    }
    }
    CloseHandle(hSnap);
    return pid;
    }

    int main()
    {
    cout << getPID(L"game2.exe") << endl;
    }