使用JNA获取特定进程的dll的基地址
Getting base address of dll of specific process using JNA
已更新:请参阅问题机器人的更新
我想获取 war3.exe 进程内的 game.dll
的基地址。
我正在尝试通过 JNA 库版本 5.9.0 来实现,但没有成功。
我遇到的问题:我无法从 war3.exe 进程中获取 game.dll 模块。
我尝试使用:
int pid = getProcessId("Warcraft III");
openProcess(PROCESS_ALL_ACCESS, pid);
WinDef.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle("game.dll")
但是hMod
的结果是null
。
我也尝试获取 war3.exe 进程拥有的所有模块。如您所见,它仅包含 5 个模块,并且不包含 game.dll
。但是当我通过 Process Explorer 打开 war3.exe 时,我看到的肯定不止 5 个。
使用 Intellij Idea 执行:
取自 Process Explorer:
请分享您的意见和想法,为什么我只从 IDE 获得 5 个模块。
任何有关如何通过 JNA 获取 game.dll
模块及其基地址的建议将不胜感激。
更新:
根据 Remy 的回答,我又尝试了 EnumProcessModules()
。
这是我的代码片段:
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Psapi;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import java.util.Arrays;
import java.util.List;
import static com.sun.jna.platform.win32.WinNT.PROCESS_ALL_ACCESS;
import static handler.memory.MemoryHandler.openProcess;
public class MemoryHandler {
static final User32 user32 = User32.INSTANCE;
static final Psapi psapi = Psapi.INSTANCE;
public static void main(String[] args) {
int pid = getProcessId("Warcraft III");
HANDLE process = openProcess(PROCESS_ALL_ACCESS, pid);
HMODULE[] hMods = new HMODULE[1024];
psapi.EnumProcessModules(process, hMods, hMods.length, new IntByReference(1024));
List<HMODULE> hModList = Arrays.asList(hMods);
hModList.forEach(hMod ->
System.out.println(Pointer.nativeValue(hMod.getPointer())));
}
public static int getProcessId(String window) {
IntByReference pid = new IntByReference(0);
user32.GetWindowThreadProcessId(user32.FindWindow(null, window), pid);
return pid.getValue();
}
}
结果如下:
据我所知,我得到了一些指示。但是我应该如何理解他们中哪一个与game.dll
相关呢?我假设我应该以某种方式获得模块列表,在那里我可以看到它们的名称和基址。
此外,如果我将 System.out.println(Pointer.nativeValue(hMod.getPointer())));
更改为 hModList.forEach(System.out::println);
,我会看到以下指针和大量空值(大约 1000 个)。
这些地址是否包含game.dll
的地址?
GetModuleHandle()
只查看调用进程。由于game.dll
没有在自己的进程中加载,所以GetModuleHandle()
找不到。
要查找在另一个进程中加载的模块,您需要使用:
EnumProcessModules()
/EnumProcessModulesEx()
, using GetModuleFileNameEx()
to get their file names. See Enumerating All Modules for a Process.
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32)
, using Module32First()
/Module32Next()
to enumerate the snapshot. See Traversing the Module List.
Kernel32Utils.getModules()
使用 CreateToolhelp32Snapshot(TH32CS_SNAPMODULE)
,因此如果您的 Java 应用是 运行 作为 64 位应用,那么它将仅枚举 64 位模块。但是 war3.exe
在您的屏幕截图中是 运行 作为 32 位进程,因此如果您在 64 位进程中使用 CreateToolhelp32Snapshot()
那么您需要使用 TH32CS_SNAPMODULE32
代替。
更新:
正如我上面提到的,如果你采用 EnumProcessModules()
方法,你可以使用 GetModuleFileNameEx()
来确定每个模块的文件名。这样,您就可以找到 game.dll
.
的模块
更重要的是:
您缺少对每个系统调用的错误处理。始终测试 return 失败值。
本身不是错误,但您确实不应该使用 openProcess()
请求 PROCESS_ALL_ACCESS
权限。仅请求您实际需要的权限,仅此而已。在这种情况下,请改用 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ
。
你不是在查看 EnumProcessModules()
的第 4 个参数的输出来了解数组中实际存储了多少个模块。
你输入的EnumProcessModules()
第3、4个参数的值是错误的,需要用bytes表示,而不是元素.
根据 EnumProcessModules()
documentation:
cb
The size of the lphModule array, in bytes.
lpcbNeeded
The number of bytes required to store all module handles in the lphModule
array.
...
It is a good idea to specify a large array of HMODULE values, because it is hard to predict how many modules there will be in the process at the time you call EnumProcessModules
. To determine if the lphModule
array is too small to hold all module handles for the process, compare the value returned in lpcbNeeded
with the value specified in cb
. If lpcbNeeded
is greater than cb
, increase the size of the array and call EnumProcessModules
again.
To determine how many modules were enumerated by the call to EnumProcessModules
, divide the resulting value in the lpcbNeeded
parameter by sizeof(HMODULE)
.
最后我找到了解决方案,但在 Java 或 JNA 中找不到。
我使用 C++ 编写了这段代码,我将像 Java.
中的 dll 一样使用它
这是我的 C++ 代码:
#include <conio.h>
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <psapi.h>
using namespace std;
DWORD_PTR GetProcessBaseAddress(DWORD processID)
{
DWORD_PTR baseAddress = 0;
HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
HMODULE* moduleArray;
LPBYTE moduleArrayBytes;
DWORD bytesRequired;
if (processHandle)
{
if (EnumProcessModules(processHandle, NULL, 0, &bytesRequired))
{
if (bytesRequired)
{
moduleArrayBytes = (LPBYTE)LocalAlloc(LPTR, bytesRequired);
if (moduleArrayBytes)
{
unsigned int moduleCount;
moduleCount = bytesRequired / sizeof(HMODULE);
moduleArray = (HMODULE*)moduleArrayBytes;
if (EnumProcessModules(processHandle, moduleArray, bytesRequired, &bytesRequired))
{
baseAddress = (DWORD_PTR)moduleArray[0];
}
LocalFree(moduleArrayBytes);
}
}
}
CloseHandle(processHandle);
}
return baseAddress;
}
DWORD GetProcessId(LPCTSTR ProcessName) // non-conflicting function name
{
PROCESSENTRY32 pt;
HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hsnap, &pt)) { // must call this first
do {
if (!lstrcmpi(pt.szExeFile, ProcessName)) {
CloseHandle(hsnap);
return pt.th32ProcessID;
}
} while (Process32Next(hsnap, &pt));
}
CloseHandle(hsnap); // close handle on failure
return 0;
}
uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName)
{
uintptr_t modBaseAddr = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if (Module32First(hSnap, &modEntry))
{
do
{
if (!_wcsicmp(modEntry.szModule, modName))
{
modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
break;
}
} while (Module32Next(hSnap, &modEntry));
}
}
CloseHandle(hSnap);
return modBaseAddr;
}
int main()
{
DWORD pid = GetProcessId(TEXT("war3.exe"));
cout << "Process ID of war3.exe: "<< pid << endl;
DWORD_PTR war3_exe_base_addr = GetProcessBaseAddress(pid);
cout <<"Base address of war3.exe: "<< war3_exe_base_addr << endl;
uintptr_t gameDllBaseAddress = GetModuleBaseAddress(pid, TEXT("game.dll"));
cout <<"Base address of game.dll: " << gameDllBaseAddress << endl;
}
结果是:
已更新:请参阅问题机器人的更新
我想获取 war3.exe 进程内的 game.dll
的基地址。
我正在尝试通过 JNA 库版本 5.9.0 来实现,但没有成功。
我遇到的问题:我无法从 war3.exe 进程中获取 game.dll 模块。 我尝试使用:
int pid = getProcessId("Warcraft III");
openProcess(PROCESS_ALL_ACCESS, pid);
WinDef.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle("game.dll")
但是hMod
的结果是null
。
我也尝试获取 war3.exe 进程拥有的所有模块。如您所见,它仅包含 5 个模块,并且不包含 game.dll
。但是当我通过 Process Explorer 打开 war3.exe 时,我看到的肯定不止 5 个。
使用 Intellij Idea 执行:
取自 Process Explorer:
请分享您的意见和想法,为什么我只从 IDE 获得 5 个模块。
任何有关如何通过 JNA 获取 game.dll
模块及其基地址的建议将不胜感激。
更新:
根据 Remy 的回答,我又尝试了 EnumProcessModules()
。
这是我的代码片段:
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Psapi;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import java.util.Arrays;
import java.util.List;
import static com.sun.jna.platform.win32.WinNT.PROCESS_ALL_ACCESS;
import static handler.memory.MemoryHandler.openProcess;
public class MemoryHandler {
static final User32 user32 = User32.INSTANCE;
static final Psapi psapi = Psapi.INSTANCE;
public static void main(String[] args) {
int pid = getProcessId("Warcraft III");
HANDLE process = openProcess(PROCESS_ALL_ACCESS, pid);
HMODULE[] hMods = new HMODULE[1024];
psapi.EnumProcessModules(process, hMods, hMods.length, new IntByReference(1024));
List<HMODULE> hModList = Arrays.asList(hMods);
hModList.forEach(hMod ->
System.out.println(Pointer.nativeValue(hMod.getPointer())));
}
public static int getProcessId(String window) {
IntByReference pid = new IntByReference(0);
user32.GetWindowThreadProcessId(user32.FindWindow(null, window), pid);
return pid.getValue();
}
}
结果如下:
据我所知,我得到了一些指示。但是我应该如何理解他们中哪一个与game.dll
相关呢?我假设我应该以某种方式获得模块列表,在那里我可以看到它们的名称和基址。
此外,如果我将 System.out.println(Pointer.nativeValue(hMod.getPointer())));
更改为 hModList.forEach(System.out::println);
,我会看到以下指针和大量空值(大约 1000 个)。
这些地址是否包含game.dll
的地址?
GetModuleHandle()
只查看调用进程。由于game.dll
没有在自己的进程中加载,所以GetModuleHandle()
找不到。
要查找在另一个进程中加载的模块,您需要使用:
EnumProcessModules()
/EnumProcessModulesEx()
, usingGetModuleFileNameEx()
to get their file names. See Enumerating All Modules for a Process.CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32)
, usingModule32First()
/Module32Next()
to enumerate the snapshot. See Traversing the Module List.
Kernel32Utils.getModules()
使用 CreateToolhelp32Snapshot(TH32CS_SNAPMODULE)
,因此如果您的 Java 应用是 运行 作为 64 位应用,那么它将仅枚举 64 位模块。但是 war3.exe
在您的屏幕截图中是 运行 作为 32 位进程,因此如果您在 64 位进程中使用 CreateToolhelp32Snapshot()
那么您需要使用 TH32CS_SNAPMODULE32
代替。
更新:
正如我上面提到的,如果你采用 EnumProcessModules()
方法,你可以使用 GetModuleFileNameEx()
来确定每个模块的文件名。这样,您就可以找到 game.dll
.
更重要的是:
您缺少对每个系统调用的错误处理。始终测试 return 失败值。
本身不是错误,但您确实不应该使用
openProcess()
请求PROCESS_ALL_ACCESS
权限。仅请求您实际需要的权限,仅此而已。在这种情况下,请改用PROCESS_QUERY_INFORMATION | PROCESS_VM_READ
。你不是在查看
EnumProcessModules()
的第 4 个参数的输出来了解数组中实际存储了多少个模块。你输入的
EnumProcessModules()
第3、4个参数的值是错误的,需要用bytes表示,而不是元素.
根据 EnumProcessModules()
documentation:
cb
The size of the lphModule array, in bytes.
lpcbNeeded
The number of bytes required to store all module handles in thelphModule
array....
It is a good idea to specify a large array of HMODULE values, because it is hard to predict how many modules there will be in the process at the time you call
EnumProcessModules
. To determine if thelphModule
array is too small to hold all module handles for the process, compare the value returned inlpcbNeeded
with the value specified incb
. IflpcbNeeded
is greater thancb
, increase the size of the array and callEnumProcessModules
again.To determine how many modules were enumerated by the call to
EnumProcessModules
, divide the resulting value in thelpcbNeeded
parameter bysizeof(HMODULE)
.
最后我找到了解决方案,但在 Java 或 JNA 中找不到。 我使用 C++ 编写了这段代码,我将像 Java.
中的 dll 一样使用它这是我的 C++ 代码:
#include <conio.h>
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <psapi.h>
using namespace std;
DWORD_PTR GetProcessBaseAddress(DWORD processID)
{
DWORD_PTR baseAddress = 0;
HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
HMODULE* moduleArray;
LPBYTE moduleArrayBytes;
DWORD bytesRequired;
if (processHandle)
{
if (EnumProcessModules(processHandle, NULL, 0, &bytesRequired))
{
if (bytesRequired)
{
moduleArrayBytes = (LPBYTE)LocalAlloc(LPTR, bytesRequired);
if (moduleArrayBytes)
{
unsigned int moduleCount;
moduleCount = bytesRequired / sizeof(HMODULE);
moduleArray = (HMODULE*)moduleArrayBytes;
if (EnumProcessModules(processHandle, moduleArray, bytesRequired, &bytesRequired))
{
baseAddress = (DWORD_PTR)moduleArray[0];
}
LocalFree(moduleArrayBytes);
}
}
}
CloseHandle(processHandle);
}
return baseAddress;
}
DWORD GetProcessId(LPCTSTR ProcessName) // non-conflicting function name
{
PROCESSENTRY32 pt;
HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hsnap, &pt)) { // must call this first
do {
if (!lstrcmpi(pt.szExeFile, ProcessName)) {
CloseHandle(hsnap);
return pt.th32ProcessID;
}
} while (Process32Next(hsnap, &pt));
}
CloseHandle(hsnap); // close handle on failure
return 0;
}
uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName)
{
uintptr_t modBaseAddr = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if (Module32First(hSnap, &modEntry))
{
do
{
if (!_wcsicmp(modEntry.szModule, modName))
{
modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
break;
}
} while (Module32Next(hSnap, &modEntry));
}
}
CloseHandle(hSnap);
return modBaseAddr;
}
int main()
{
DWORD pid = GetProcessId(TEXT("war3.exe"));
cout << "Process ID of war3.exe: "<< pid << endl;
DWORD_PTR war3_exe_base_addr = GetProcessBaseAddress(pid);
cout <<"Base address of war3.exe: "<< war3_exe_base_addr << endl;
uintptr_t gameDllBaseAddress = GetModuleBaseAddress(pid, TEXT("game.dll"));
cout <<"Base address of game.dll: " << gameDllBaseAddress << endl;
}
结果是: