- 導入庫 pro
win32:LIBS += -lpsapi
win32:LIBS += -lkernel32
- 獲取列表
#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);
}
在代碼中獲取動態內存
-
先在CE中獲取基址,如:
上面找到的基址就是"Game.exe"+00ABBBB0
,就算重啟游戲后,這個地址也不會變,然后按照對應的偏移量,更着讀下去,就能獲取到最后的值 -
編寫代碼
// 獲取人物當前的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
- 打印結果,這里全部是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
參考:
- 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
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
- GetProcAddress
- DLL也能調用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;
}