0

Hello I recently ran into an issue with a JNA program I am writing.

If I run the following code with a 64bit JVM it runs fun:

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());
    }

}

But if I run the same code with a 32bit JVM I get the following error:

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)

Here is my read process memory method:

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));
    }

}

Edit so it turns out the 32bit jvm was trying to use Kernel32 which is a 64bit library since I'm using a 64bit os and they don't agree with each other.

So the new question is, could it be possible via JNA direct mapping to specify to use a 32bit kernel32 (in syswow64) if they are running with a 32bit JVM, or use the 64bit kernel32 (in system32) if they are using 64bit JVM?

Jonathan Beaudoin
  • 2,158
  • 4
  • 27
  • 63
  • At a guess, the native code you are accessing is 64-bit. The 32-bit JVM can't access 64-bit native code, nor can the 64-bit JVM access 32-bit native code. So unless you have both 64-bit and 32-bit versions of the native code you'll need to use the JVM that matches your native code's bits. – neuronaut Sep 17 '15 at 22:38
  • The process I am reading from is 32bit. Since my OS is 64bit, could it be the Kernel32 is a 64bit dll and that's the issue? – Jonathan Beaudoin Sep 17 '15 at 22:45
  • Yep, that sounds like it. For some reason Microsoft decided to keep the '32' in the names of many of the system DLLs even on the 64-bit version of the OS, which I've always found to be misleading. – neuronaut Sep 17 '15 at 22:48
  • Is there any 32bit copies on Kernel32 stored on a 64bit windows so that I can make my program work regardless of what architecture their JVM is. – Jonathan Beaudoin Sep 17 '15 at 22:51
  • Not that I'm aware of (though I'm no Windows expert). However, as long as a user is using the JVM that matches the OS's bits (e.g. 32-bit JVM on 32-bit OS) your code should work. Perhaps you could catch the exception and terminate gracefully with a message informing the user to use the right JVM? – neuronaut Sep 17 '15 at 22:57
  • Can you extract the kernel32 error code using GetLastError()? what is your intention to read at the address 0x178832cc with only 4 bytes of data? – ecle Sep 18 '15 at 01:46
  • Try to confirm the process is really running on 32-bit or 64-bit with IsWow64Process(): http://stackoverflow.com/questions/20068219/readprocessmemory-on-a-64-bit-proces-always-returns-error-299 – ecle Sep 18 '15 at 01:49
  • ReadProcessMemory64() if detected as 64-bit process http://stackoverflow.com/questions/5714297/is-it-possible-to-read-process-memory-of-a-64-bit-process-from-a-32bit-app – ecle Sep 18 '15 at 01:50
  • The process im writing too is 100% 32bit – Jonathan Beaudoin Sep 18 '15 at 11:30

1 Answers1

3

I fixed this issue myself by changing address from long to Pointer. I assume it's due to the long size difference between Java and C

Changed:

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

To:

   public static native boolean ReadProcessMemory(Pointer process, Pointer address, ByteBuffer memory, int size, int written);
Jonathan Beaudoin
  • 2,158
  • 4
  • 27
  • 63
  • 1
    It is indeed due to the size difference of a pointer on 32- vs 64-bit systems. Java `long` is 64 bits, always, while JNA `Pointer` uses a size appropriate for the target system (as does `NativeLong` and Java `char`). – technomage Sep 19 '15 at 10:19