I'm writing a game hack which uses memory manipulation to work and decided to do it in Java for the FUD aspect (native hacks can be detected almost immediatly).
I have this method which reads a memory object from the windows call ReadProcessMemory
public static Memory readMemory(Pointer process, long address, int bytesToRead) {
Memory output = new Memory(bytesToRead);
KERNEL32.ReadProcessMemory(process, address, output, bytesToRead, 0);
return output;
}
Memory output = new Memory(bytesToRead);
Takes about 0-5+ms to execute sometimes
KERNEL32.ReadProcessMemory(process, address, output, bytesToRead, 0);
Takes about 0-5+ms as well to execute.
The program that reads this calls these methods about 1k times per cycle (16ms cycles).
Edit: I wrote a basic test class to test how long 5000 calls would be
public final class Test {
public static final int AMOUNT_OF_CALLS = 5000;
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
for (int i = 0; i < AMOUNT_OF_CALLS; i++) {
Memory m = readMemory(new Pointer(1), 0xFFFFFFF, ThreadLocalRandom.current().nextInt(1, 8)); //Random between a byte read, or long
m.dispose();
}
System.out.println("Took " + (System.currentTimeMillis() - start) + "ms todo " + AMOUNT_OF_CALLS + " readMemory calls.");
}
public static Memory readMemory(Pointer process, long address, int bytesToRead) {
Memory output = new Memory(bytesToRead);
Kernel32.INSTANCE.ReadProcessMemory(process, address, output, bytesToRead, 0);
return output;
}
}
Is there any other way of doing the readMemory method so that it takes less than 32ms to execute all 5000calls?
You want to do 5000 calls in 32ms. That's roughly 6us per call. Can you do that in pure C
code (no Java involved)? Can you do that in raw JNI? If not, there's not much point in trying to get it to work with JNA. Not only do you have to do the data transfer, but you need some time to do processing of that data.
Memory
is just a Java representation of a malloc
'ed chunk of memory that gets freed on GC. Pre-allocate the number of different blocks that you need, or create a direct NIO buffer (which may allow tweaks to the native backing memory more efficiently).
After pre-allocation, make sure you're using direct mapping, then profile again to see where you're spending time.
public class MyKernel32 {
static { Native.register(NativeLibrary.getInstance("kernel32", W32APIOptions.DEFAULT_OPTIONS)); }
public static native long ReadProcessMemory(HANDLE process, long address, Pointer buffer, int size, IntByReference numRead);
}
You might get some gains by using long
in place of Pointer
, but YMMV, and always measure the effects of added complexity.