【问题标题】:JNA Invalid memory access When Running With 32bit JVM使用 32 位 JVM 运行时 JNA 内存访问无效
【发布时间】:2015-09-17 22:26:38
【问题描述】:

您好,我最近在编写 JNA 程序时遇到了问题。

如果我使用 64 位 JVM 运行以下代码,它运行起来很有趣:

public final class UWot {

    public static void main(String[] args) {
        final int size = 4;

        GameProcess process = Processes.get("csgo.exe");

        ByteBuffer buff = Buffers.allocate(size).order(ByteOrder.nativeOrder());
        Kernel32Direct.ReadProcessMemory(process.handle().getPointer(), 0x178832cc, buff, size, 0);

        System.out.println(buff.getInt());
    }

}

但如果我使用 32 位 JVM 运行相同的代码,我会收到以下错误:

Exception in thread "main" java.lang.Error: Invalid memory access
at baro.natives.Kernel32Direct.ReadProcessMemory(Native Method)
at temp.hi.main(UWot.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

这是我的读取过程记忆方法:

public final class Kernel32Direct {

    public static native int ReadProcessMemory(Pointer process, long address, ByteBuffer memory, int size, int written);

    static {
        Native.register(NativeLibrary.getInstance("Kernel32", W32APIOptions.UNICODE_OPTIONS));
    }

}

编辑结果是 32 位 jvm 正在尝试使用 Kernel32,这是一个 64 位库,因为我使用的是 64 位操作系统并且它们彼此不同意。

所以新问题是,如果它们使用 32 位 JVM 运行,是否可以通过 JNA 直接映射指定使用 32 位内核 32(在 syswow64 中),或者如果它们正在使用,则使用 64 位内核32(在 system32 中) 64位JVM?

【问题讨论】:

  • 猜测一下,您访问的本机代码是 64 位的。 32 位 JVM 不能访问 64 位本机代码,64 位 JVM 也不能访问 32 位本机代码。因此,除非您同时拥有 64 位和 32 位版本的本机代码,否则您需要使用与本机代码位匹配的 JVM。
  • 我正在读取的进程是 32 位的。由于我的操作系统是 64 位的,难道 Kernel32 是一个 64 位的 dll,这就是问题所在?
  • 是的,听起来像。出于某种原因,Microsoft 决定在许多系统 DLL 的名称中保留“32”,即使在 64 位版本的操作系统上也是如此,我一直认为这具有误导性。
  • Kernel32 上是否有任何 32 位副本存储在 64 位窗口上,这样我就可以让我的程序工作,无论他们的 JVM 是什么架构。
  • 我不知道(尽管我不是 Windows 专家)。但是,只要用户使用与操作系统位匹配的 JVM(例如 32 位操作系统上的 32 位 JVM),您的代码就应该可以工作。也许您可以捕获异常并优雅地终止,并发出一条消息,通知用户使用正确的 JVM?

标签: java memory jna


【解决方案1】:

我通过将 address 从 long 更改为 Pointer 自己解决了这个问题。我认为这是由于 Java 和 C 之间的大小差异很大

改变:

   public static native int ReadProcessMemory(Pointer process, long address, ByteBuffer memory, int size, int written);

收件人:

   public static native boolean ReadProcessMemory(Pointer process, Pointer address, ByteBuffer memory, int size, int written);

【讨论】:

  • 这确实是由于 32 位和 64 位系统上指针的大小差异。 Java long 始终是 64 位,而 JNA Pointer 使用适合目标系统的大小(NativeLong 和 Java char 也是如此)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多