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;
}
posted @ 2020-05-08 10:32  Ajanuw  阅读(231)  评论(0编辑  收藏