Мне нужен базовый адрес exe "tibia.exe". Это то, что я получил до сих пор, но это не работает. Он всегда возвращает 0
.
Что не так?
DWORD MainWindow::getBaseAddress(DWORD dwProcessIdentifier)
{
TCHAR lpszModuleName[] = {'t','i','b','i','a','.','e','x','e','\0'}; //tibia.exe
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
dwProcessIdentifier);
DWORD dwModuleBaseAddress = 0;
if(hSnapshot != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 ModuleEntry32;
ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
if(Module32First(hSnapshot, &ModuleEntry32))
{
do
{
if( wcscmp(ModuleEntry32.szModule, lpszModuleName) == 0)
{
dwModuleBaseAddress = (DWORD)ModuleEntry32.modBaseAddr;
break;
}
}
while(Module32Next(hSnapshot, &ModuleEntry32));
}
CloseHandle(hSnapshot);
}
return dwModuleBaseAddress;
}
//Call it here
tibiaWindow = FindWindow( L"TibiaClient", NULL);
DWORD PID;
GetWindowThreadProcessId( tibiaWindow, &PID );
DWORD baseAddress = getBaseAddress( PID );
if( baseAddress == 0 )
return false ;
Возможно, только потому, что я использовал их до того, как был доступен ToolHelp32 (по крайней мере, в операционных системах на базе NT), но я предпочитаю использовать функции PSAPI для такого рода задач. Используя их, код будет выглядеть так:
#include <windows.h>
#include <string>
#include <psapi.h>
#include <iostream>
int main(int argc, char **argv) {
HANDLE process = GetCurrentProcess();
if (argc != 1)
process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, atoi(argv[1]));
HMODULE handles[2048];
DWORD needed;
EnumProcessModules(process, handles, sizeof(handles), &needed);
for (int i = 0; i < needed / sizeof(handles[0]); i++) {
MODULEINFO info;
char name[1024];
GetModuleBaseName(process, handles[i], name, sizeof(name));
if (std::string(name).find(".exe") != std::string::npos) {
GetModuleInformation(process, handles[i], &info, sizeof(info));
std::cout << name << ": " << info.lpBaseOfDll << "\n";
break;
}
}
}
Поскольку это прямо сейчас, это позволит вам ввести идентификатор процесса в командной строке и показать адрес загрузки первого модуля, который он находит в этом процессе, с именем, которое включает в себя ".exe". Если вы не укажете идентификатор процесса, он будет выполнять поиск по собственному процессу (демонстрации того, как работают функции, но в остальном в значительной степени бесполезны).
Используя либо ToolHelp32, либо PSAPI, вы получаете аналогичное ограничение: вам нужно скомпилировать это в 64-разрядный исполняемый файл, чтобы он мог "видеть" другие 64-битные процессы (т.е. При компиляции как 32-битный код, они видят только другие 32-битные процессы).
Существуют также некоторые процессы (например, CSRSS.exe), которые не смогут успешно открыть/перечислить. Насколько я знаю, те же процессы будут успешными/неудачными с PSAPI и ToolHelp32.
У PSAPI есть один кусочек неуклюжести по сравнению с ToolHelp32: дело (хорошо) с процессами, у которых много модулей неуклюжие (в лучшем случае). Вы вызываете EnumProcessModules
, и если вы не дали места для достаточного количества модулей, параметр "Необходимый" будет установлен в пространство, необходимое для количества содержащихся в нем модулей. Там есть условие гонки: между временем, которое возвращается, и временем, когда вы снова вызываете EnumProcessModules
, процесс может загрузить больше DLL, так что второй вызов может завершиться неудачно.
На данный момент я только предположил, что ни один процесс не будет использовать более 2048 модулей. Чтобы быть действительно правильным, у вас должен быть цикл while (или, может быть, цикл do/while), который начинается с нулевого пробела, вызывает EnumProcessModules
чтобы узнать, сколько места необходимо, выделите это (возможно, немного больше, если он загрузит больше DLL) и повторять до тех пор, пока это не удастся.
.exe
, например myapp.exe.resources.dll
. Поддержка UNICODE тоже не помешает.
lpszModuleName
отсутствуетlpszModuleName
'\0'
в конце.