Estou tentando fazer esse código funcionar:
#include <iostream> // For general input and output
#include <Windows.h> // Windows API for interacting with windows processes
#include <TlHelp32.h> // For getting snapshots
int main()
{
/*
Get the process ID to attach later
*/
DWORD gameProcID = -1; // Variable to hold the process ID, has to be a DWORD because the windows API wants it that way. Starts as -1 (which is invald) so it is known if the process wasn't found
HANDLE procSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS , 0); // Creates a "snapshot" of the current processes (Essentially a list of the processes)
// Creates a placeholder process entry, that will hold each process for checking
PROCESSENTRY32 currentProc;
currentProc.dwSize = sizeof(PROCESSENTRY32); // Has to have it's "sizeof" member set, or else the loop fails.
// Loops through each process in the snapshot until it finds Winquake.exe
if (Process32First(procSnap, ¤tProc)) { // Starts by getting the first process
do {
if (!_wcsicmp(currentProc.szExeFile, L"Winquake.exe")) { // Checks if the process is Winquake, using a Wide Character String Compare function
// If found, update the variable and break out the loop
gameProcID = currentProc.th32ProcessID;
break;
}
} while (Process32Next(procSnap, ¤tProc)); // While there are still more processes, keep checking
}
CloseHandle(procSnap); // Close the snapshot. Good memory management :)
// If it can't find the process, print and then close
if (gameProcID == -1) {
std::cout << "Couldn't find process" << std::endl;
exit(1);
}
/*
Get the module inside the found process (Quite similar to finding the process)
*/
uintptr_t gameBaseAddr = -1; // Variable to hold the base memory address of the module we want to find, Starts as -1 (which is invalid) so it is known if the module wasn't found
HANDLE modSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, gameProcID); // Creates a snapshot of all the modules inside the process
// Creates a placeholder module entry, that will hold each module for checking
MODULEENTRY32 currentMod;
currentMod.dwSize = sizeof(currentMod); // Has to have it's "sizeof" member set, or else the loop fails.
// Loops through each module in the snapshot until it finds Winquake.exe
if (Module32First(modSnap, ¤tMod)) { // Starts by getting the first module
do {
if (!_wcsicmp(currentMod.szModule, L"Winquake.exe")) { // Checks if the module is Winquake, using a Wide Character String Compare fucntion
// If found, update the variable and break out the loop
gameBaseAddr = (uintptr_t)currentMod.modBaseAddr;
}
} while (Module32Next(modSnap, ¤tMod)); // While there are still more modules, keep checking
}
CloseHandle(modSnap); // Close the snapshot. Good memory management
// If it can't find the module, print and then close
if (gameBaseAddr == -1) {
std::cout << "Couldn't find module inside game. Perhaps you have the wrong 'Winquake.exe' executable" << std::endl;
exit(1);
}
// The final handle for the game process
HANDLE gameProc = OpenProcess(PROCESS_ALL_ACCESS, NULL, gameProcID); // Opens a handle to attach to the Winquake process and module. With full access rights
}
Ele não lança uma exceção, mas se você definir um ponto de interrupção na linha 56 do código, poderá ver no depurador que o modBaseAddr
campo do currentMod
objeto contém a string
modBaseAddr 0x00007ffac7c00000 <Error reading string characters.>
.
Se você tentar enviar o valor deste campo para o console usando std::cout
, uma exceção será lançada:
Uma exceção foi lançada em 0x00007FF9FAA77CC1 (ucrtbased.dll) em ProjectName.exe: 0xC0000005: Violação de acesso ao ler 0x00007FF7EF6C0000.
Tentei obter dados de diferentes jogos.
Meu Visual Studio está sendo executado como administrador e executa o projeto como administrador. Também tentei executar o .exe
arquivo da pasta "debug" como administrador.
Nenhuma delas afetou o problema.
Também não consegui encontrar nada sobre meu problema na Internet.
Eu esperava que o modBaseAddr
campo do currentMod
objeto contivesse o endereço base do módulo.
se alguma coisa, todos os outros campos deste objeto contêm dados corretos.
O
MODULEENTRY32::modBaseAddr
campo é declarado como umBYTE*
ponteiro, ou sejaunsigned char*
, . O<<
operador destd::basic_ostream
(questd::cout
é uma instância de) é sobrecarregado para tratar todos os tipos dechar*
ponteiros como strings terminadas em nulo no estilo C, o quemodBaseAddr
não é o caso. É por isso que o depurador diz que está tentando acessar caracteres de string e por que a função print trava. Ambos estão tentando acessar memória que não deveriam.Para inspecionar o ponteiro corretamente no depurador, você pode instruir o inspetor a interpretá-lo como um ponteiro bruto, não um ponteiro de caractere.
Para imprimir o endereço para o qual um
char*
ponteiro está apontando, você precisa converter o tipo do ponteiro paravoid*
ou(u)intptr_t
invocar um<<
operador mais apropriado, por exemplo: