qt 取進程列表,讀寫內存, 寫字節集


  1. 導入庫 pro
win32:LIBS += -lpsapi
win32:LIBS += -lkernel32
  1. 獲取列表
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <windows.h>
#include <QtDebug>
#include <locale>
#include <tchar.h>
#include <string>
#include <QMessageBox>
#include <stdio.h>
#include <psapi.h>

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, &hMod, sizeof(hMod),&cbNeeded) )
        {
            GetModuleBaseNameA(hProcess, hMod, (LPSTR)&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);
}

在代碼中獲取動態內存

  1. 先在CE中獲取基址,如:

    上面找到的基址就是"Game.exe"+00ABBBB0,就算重啟游戲后,這個地址也不會變,然后按照對應的偏移量,更着讀下去,就能獲取到最后的值

  2. 編寫代碼

// 獲取人物當前的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

寫字節集, 將點擊一次-1的程序,改為每點擊一次+2

舊的:

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

參考:

DLL 簡單注入C++ video1 video2

#include <iostream>
#include <windows.h>
#include <Psapi.h>

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, &hMod, sizeof(hMod), &cbNeeded))
		{
			GetModuleBaseNameA(hProcess, hMod, (LPSTR)&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;
}


顯示連接DLL

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

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

另一種找pid的方法

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM