【发布时间】:2020-10-01 15:35:24
【问题描述】:
我正在尝试从名为Age of Empires II: Definitive Edition 的进程中的指针读取(浮点)值。
这是我的代码:
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
public class Main {
final static long baseAddress = 0x02BC6620L;
final static Pointer baseAddressPointer = new Pointer(baseAddress);
final static int[] offsets = new int[]{0x00, 0x1A8, 0x00, 0x158, 0x28, 0x270};
static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32",Kernel32.class);
static User32 user32 = (User32) Native.loadLibrary("user32", User32.class);
public static int PROCESS_VM_READ = 0x0010;
public static int PROCESS_VM_WRITE = 0x0020;
public static int PROCESS_VM_OPERATION = 0x0008;
public static interface User32 extends StdCallLibrary
{
final User32 instance = (User32) Native.loadLibrary ("user32", User32.class);
WinDef.HWND FindWindowExA(WinDef.HWND hwndParent, WinDef.HWND childAfter, String className, String windowName);
WinDef.HWND FindWindowA(String className, String windowName);
void GetWindowThreadProcessId(WinDef.HWND hwnd, IntByReference intByReference);
}
public static void main(String[] args) {
System.out.println("System.getProperty(\"sun.arch.data.model\") = " + System.getProperty("sun.arch.data.model"));
int pid = getProcessId("Age of Empires II: Definitive Edition");
System.out.println("pid = " + pid);
com.sun.jna.platform.win32.WinNT.HANDLE process = openProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, pid);
long theDynAddress = findDynAddress(process, offsets);
System.out.println("theDynAddress = " + theDynAddress);
Pointer dynAddress = new Pointer(theDynAddress);
Memory scoreMem = readMemory(process, dynAddress, 4);
float score = scoreMem.getFloat(0);
System.out.println(score);
}
public static Memory readMemory(com.sun.jna.platform.win32.WinNT.HANDLE process, Pointer address, int bytesToRead) {
IntByReference read = new IntByReference(0);
Memory output = new Memory(bytesToRead);
boolean readProcessMemorySucceeded = kernel32.ReadProcessMemory(process, address, output, bytesToRead, read);
System.out.println("readProcessMemorySucceeded = " + readProcessMemorySucceeded);
if (!readProcessMemorySucceeded) {
int lasterrorReadMemory = kernel32.GetLastError();
System.out.println("lasterror = " + lasterrorReadMemory);
}
return output;
}
public static int getProcessId(String window) {
IntByReference pid = new IntByReference(0);
user32.GetWindowThreadProcessId(user32.FindWindowA(null, window), pid);
return pid.getValue();
}
public static com.sun.jna.platform.win32.WinNT.HANDLE openProcess(int permissions, int pid) {
return kernel32.OpenProcess(permissions, true, pid);
}
public static long findDynAddress(com.sun.jna.platform.win32.WinNT.HANDLE process, int[] offsets)
{
int size = 4;
Memory pTemp = new Memory(size);
long pointerAddress = 0;
for(int i = 0; i < offsets.length; i++)
{
if(i == 0)
{
boolean test = kernel32.ReadProcessMemory(process, baseAddressPointer, pTemp, size, null);
int lasterror = kernel32.GetLastError();
System.out.println("test = " + test + ", lasterror = " + lasterror);
}
pointerAddress = ((pTemp.getInt(0)+offsets[i]));
if(i != offsets.length-1)
kernel32.ReadProcessMemory(process, new Pointer(pointerAddress), pTemp, size, null);
}
return pointerAddress;
}
}
这是运行jar后的终端输出:
System.getProperty("sun.arch.data.model") = 64
pid = 2192
test = false, lasterror = 299
theDynAddress = 1177510878
readProcessMemorySucceeded = false
lasterror = 299
1.64011448E10
请注意:
- 如您所见,jar 编译为 64 位。
- 我以管理权限运行 jar。
- 我尝试访问的进程也是 64 位的。
我收到错误 299,标记为 ERROR_PARTIAL_COPY。我得到的价值似乎是随机的。我能做些什么来防止这种情况发生?
使用作弊引擎访问相同的值没有问题:
【问题讨论】:
-
您说您正在读取
float值,但您调用的是scoreMem.getInt(0);而不是getFloat()。您确定lasterror来自最后一次通话,而不是之前的通话吗? -
@DanielWiddis 你是对的!我将其更改为
scoreMem.getFloat(0)并更新了代码。但是,关于lasterror,它是在scoreMem的getInt(0)/getFloat(0)之前执行的,所以lasterror不可能是这样,对吧?我还添加了test的打印值以确保 - 正如您所看到的test的值是false,所以ReadProcessMemory(...)失败了。