diff --git a/src/de/zabuza/memeaterbug/MemEaterBug.java b/src/de/zabuza/memeaterbug/MemEaterBug.java
index 6192f58..4f5e379 100644
--- a/src/de/zabuza/memeaterbug/MemEaterBug.java
+++ b/src/de/zabuza/memeaterbug/MemEaterBug.java
@@ -3,10 +3,11 @@
import com.sun.jna.platform.win32.WinNT.HANDLE;
import de.zabuza.memeaterbug.locale.ErrorMessages;
+import de.zabuza.memeaterbug.memory.MemManipulator;
import de.zabuza.memeaterbug.util.Masks;
import de.zabuza.memeaterbug.util.SystemProperties;
-import de.zabuza.memeaterbug.winapi.api.Process;
import de.zabuza.memeaterbug.winapi.jna.util.User32Util;
+import de.zabuza.memeaterbug.winapi.Process;
import de.zabuza.memeaterbug.winapi.jna.util.Kernel32Util;
import de.zabuza.memeaterbug.winapi.jna.util.PsapiUtil;
@@ -14,7 +15,11 @@
* Provides various methods for memory manipulation on Windows systems using
* JNA. After creation it needs to be hooked to the given process, by using
* {@link #hookProcess()}. Before shutdown the process handle should be closed
- * by using {@link #unhookProcess()}.
+ * by using {@link #unhookProcess()}.
+ *
+ * If using for 32-bit applications on a 64-bit system, you should use a 32-bit
+ * Java Runtime Environment to ensure proper execution. You may check this by
+ * using {@link #is64BitProcess()}.
*
* @author Zabuza
*
@@ -31,6 +36,11 @@ public final class MemEaterBug {
* If the Mem-Eater-Bug is hooked to a process or not.
*/
private boolean mIsHooked;
+ /**
+ * Memory manipulator for the current process handle, if hooked,
+ * null else.
+ */
+ private MemManipulator mMemManipulator;
/**
* Handle to the current process, if hooked, null else.
*/
@@ -62,6 +72,7 @@ public MemEaterBug(final int processId) {
mIsHooked = false;
mProcessHandle = null;
+ mMemManipulator = null;
if (processId == 0) {
throw new IllegalArgumentException(ErrorMessages.PROCESS_NOT_FOUND);
@@ -104,6 +115,21 @@ public MemEaterBug(final String processClassName, final String windowTitle) {
this(User32Util.getWindowThreadProcessIdByClassAndTitle(processClassName, windowTitle).getValue());
}
+ /**
+ * Gets an object for memory manipulation of the hooked process.
+ *
+ * @return An object for memory manipulation of the hooked process.
+ * @throws IllegalStateException
+ * If the Mem-Eater-Bug is not hooked to a process
+ */
+ public MemManipulator getMemManipulator() throws IllegalStateException {
+ ensureIsHooked();
+ if (mMemManipulator == null) {
+ mMemManipulator = new MemManipulator(mProcessId, mProcessHandle);
+ }
+ return mMemManipulator;
+ }
+
/**
* Hooks the Mem-Eater-Bug to the given process. After that, it is able to
* interact with the process and, for example, manipulate its memory. Before
@@ -111,14 +137,13 @@ public MemEaterBug(final String processClassName, final String windowTitle) {
*
* It requests the following permissions for interaction with the process:
*
- * -
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_INFORMATION
+ *
- {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_QUERY_INFORMATION
* PROCESS_QUERY_INFORMATION}
- * - {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_READ
+ *
- {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_READ
* PROCESS_VM_READ}
- * - {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_WRITE
+ *
- {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_WRITE
* PROCESS_VM_WRITE}
- * - {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_OPERATION
+ *
- {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_OPERATION
* PROCESS_VM_OPERATION}
*
*
@@ -169,9 +194,7 @@ public void hookProcess(final int permissions) {
* If the Mem-Eater-Bug is not hooked to a process
*/
public boolean is64BitProcess() {
- if (!mIsHooked) {
- throw new IllegalStateException(ErrorMessages.UNABLE_SINCE_NOT_HOOKED);
- }
+ ensureIsHooked();
return mIs64BitProcess;
}
@@ -200,9 +223,23 @@ public void unhookProcess() {
throw new IllegalStateException(ErrorMessages.PROCESS_UNABLE_TO_UNHOOK_SINCE_NOT_HOOKED);
}
mProcessHandle = null;
+ mMemManipulator = null;
mIsHooked = false;
}
+ /**
+ * Ensures that the Mem-Eater-Bug is hooked to a process by
+ * {@link #hookProcess()}.
+ *
+ * @throws IllegalStateException
+ * If the Mem-Eater-Bug is not hooked to a process
+ */
+ private void ensureIsHooked() throws IllegalStateException {
+ if (!mIsHooked) {
+ throw new IllegalStateException(ErrorMessages.UNABLE_SINCE_NOT_HOOKED);
+ }
+ }
+
/**
* Ensures that the operating system is a Windows system.
*
diff --git a/src/de/zabuza/memeaterbug/examples/SoliScorer.java b/src/de/zabuza/memeaterbug/examples/SoliScorer.java
index c3bb163..0884534 100644
--- a/src/de/zabuza/memeaterbug/examples/SoliScorer.java
+++ b/src/de/zabuza/memeaterbug/examples/SoliScorer.java
@@ -1,121 +1,53 @@
package de.zabuza.memeaterbug.examples;
-import java.util.List;
-
-import com.sun.jna.Memory;
-import com.sun.jna.Pointer;
-import com.sun.jna.platform.win32.WinDef.HMODULE;
-import com.sun.jna.platform.win32.WinNT.HANDLE;
-
-import de.zabuza.memeaterbug.winapi.api.Module;
-import de.zabuza.memeaterbug.winapi.jna.util.Kernel32Util;
-import de.zabuza.memeaterbug.winapi.jna.util.PsapiUtil;
-import de.zabuza.memeaterbug.winapi.jna.util.User32Util;
+import de.zabuza.memeaterbug.MemEaterBug;
+import de.zabuza.memeaterbug.memory.MemManipulator;
/**
- * Hack for the popular game Solitaire that allows arbitrary changes of the user score.
+ * Hack for the popular game Solitaire that allows arbitrary changes of the user
+ * score.
*
* @author Zabuza
*
*/
public final class SoliScorer {
-
- // final static long baseAddress = 0x10002AFA8L;
- final static long baseAddress = 0x341B220L;
- final static int[] offsets = new int[] { 0x50, 0x14 };
-
- public static int PROCESS_VM_READ = 0x0010;
- public static int PROCESS_VM_WRITE = 0x0020;
- public static int PROCESS_VM_OPERATION = 0x0008;
- public static int PROCESS_ALL_ACCESS = 0x001F0FFF;
- public static int PROCESS_QUERY_INFORMATION = 0x0400;
-
/**
+ * Demonstrates the usage of the Mem-Eater-Bug by reading and changing the
+ * user score in the popular game Solitaire.
+ *
+ * The program was tested on a Windows 10 64-bit system using the default
+ * 64-bit Solitaire.exe from Windows 7.
*
* @param args
* Not supported
*/
public static void main(final String[] args) {
- int pid = User32Util.getWindowThreadProcessIdByClass("Solitaire").getValue();
- System.out.println("PID: " + pid);
- if (pid == 0) {
- throw new RuntimeException("Process with window class not found: Solitaire");
- }
- HANDLE process = openProcess(
- PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, pid);
- long baseAddress = getBaseAddress(process);
- if (baseAddress == -1) {
- throw new RuntimeException("Error while finding base address.");
- }
- System.out.println("Base adress is: 0x" + Long.toHexString(baseAddress));
- System.out.println("Offsetting base: 0x" + Long.toHexString(baseAddress) + " + 0xBAFA8 = " + Long.toHexString(baseAddress + 0xBAFA8));
- baseAddress += 0xBAFA8;
- long dynAddress = findDynAddress(process, offsets, baseAddress);
- System.out.println("DynAddress: 0x" + Long.toHexString(dynAddress));
-
- Memory scoreMem = Kernel32Util.readMemory(process, dynAddress, 4);
- int score = scoreMem.getInt(0);
- System.out.println("Score: " + score);
-
- byte[] newScore = new byte[] { 0x22, 0x22, 0x22, 0x22 };
- Kernel32Util.writeMemory(process, dynAddress, newScore);
-
- scoreMem = Kernel32Util.readMemory(process, dynAddress, 4);
- score = scoreMem.getInt(0);
- System.out.println("New score: " + score);
- }
-
- public static HANDLE openProcess(int permissions, int pid) {
- HANDLE process = Kernel32Util.openProcess(permissions, true, pid);
- return process;
- }
-
- public static long findDynAddress(HANDLE process, int[] offsets, long baseAddress) {
- int size = Pointer.SIZE;
- Memory pTemp = new Memory(size);
- long pointerAddress = -1;
-
- for (int i = 0; i < offsets.length; i++) {
- if (i == 0) {
- pTemp = Kernel32Util.readMemory(process, baseAddress, size);
- System.out.println(">Finding dyn address...");
- System.out.println("\tStarting at [0x" + Long.toHexString(baseAddress) + "] = 0x" + Long.toHexString(pTemp.getInt(0)));
- }
-
- pointerAddress = pTemp.getInt(0) + offsets[i];
-
- if (i != offsets.length - 1) {
- System.out.print("\tNext is [0x" + Long.toHexString(pTemp.getInt(0)) + " + 0x" + Long.toHexString(offsets[i]) + " = 0x" + Long.toHexString(pointerAddress) + "] =");
- pTemp = Kernel32Util.readMemory(process, pointerAddress, size);
- System.out.println(" 0x" + Long.toHexString(pTemp.getInt(0)));
- }
- }
-
- System.out.println(">Found dyn address 0x" + Long.toHexString(pTemp.getInt(0)) + " + 0x" + Long.toHexString(offsets[offsets.length - 1]) + " = 0x" + Long.toHexString(pointerAddress));
-
- return pointerAddress;
- }
-
- public static long getBaseAddress(HANDLE process) {
- try {
- // TODO 64 or 32? 64 seems to yield wrong addresses, 32 yields error 299...
- // Solitaire seems to be a 64bit application on 64bit windows.
- List hModulePointer = PsapiUtil.enumProcessModules(process);
-
- for (HMODULE hModule : hModulePointer) {
- Module module = new Module(process, hModule);
- System.out.println("Name: " + module.getFileName());
- if (module.getFileName().contains("Solitaire.exe")) {
- System.out.println((module.getFileName() + ": entry point at - 0x"
- + Long.toHexString(Pointer.nativeValue(module.getEntryPoint()))));
- System.out.println("Base of dll : " + module.getLpBaseOfDll());
- System.out.println("0x" + Long.toHexString(Pointer.nativeValue(module.getLpBaseOfDll())));
- return Long.valueOf("" + Pointer.nativeValue(module.getLpBaseOfDll()));
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return -1;
+ // Constants
+ String exeFileName = "Solitaire.exe";
+ int nextScore = 1500;
+ // Offsets are found with a MemReader like CheatEngine
+ int scoreBaseAddressOffset = 0xBAFA8;
+ int[] scoreOffsets = new int[] { 0x50, 0x14 };
+
+ // Hook to the game
+ MemEaterBug memEaterBug = new MemEaterBug(exeFileName);
+ memEaterBug.hookProcess();
+ MemManipulator memManipulator = memEaterBug.getMemManipulator();
+
+ // Find the dynamic address of the score
+ long scoreBaseAddress = memManipulator.getBaseAddress() + scoreBaseAddressOffset;
+ long scoreDynAddress = memManipulator.findDynAddress(scoreOffsets, scoreBaseAddress);
+
+ // Read the current score
+ int score = memManipulator.readInt(scoreDynAddress);
+ System.out.println("The current score is: " + score);
+
+ // Write to the current score
+ memManipulator.writeInt(scoreDynAddress, nextScore);
+ int readScore = memManipulator.readInt(scoreDynAddress);
+ System.out.println("Now the score is: " + readScore);
+
+ // Unhook from the game
+ memEaterBug.unhookProcess();
}
}
diff --git a/src/de/zabuza/memeaterbug/examples/package-info.java b/src/de/zabuza/memeaterbug/examples/package-info.java
index 52cc23b..1de4200 100644
--- a/src/de/zabuza/memeaterbug/examples/package-info.java
+++ b/src/de/zabuza/memeaterbug/examples/package-info.java
@@ -1,4 +1,5 @@
/**
- * This is the core package for examples of the Mem-Eater-Bug, e.g. small applications using the API.
+ * This is the core package for examples of the Mem-Eater-Bug, e.g. small
+ * applications using the API.
*/
package de.zabuza.memeaterbug.examples;
\ No newline at end of file
diff --git a/src/de/zabuza/memeaterbug/memory/MemManipulator.java b/src/de/zabuza/memeaterbug/memory/MemManipulator.java
new file mode 100644
index 0000000..90db8bc
--- /dev/null
+++ b/src/de/zabuza/memeaterbug/memory/MemManipulator.java
@@ -0,0 +1,250 @@
+package de.zabuza.memeaterbug.memory;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+import com.sun.jna.Memory;
+import com.sun.jna.Pointer;
+import com.sun.jna.platform.win32.WinNT.HANDLE;
+
+import de.zabuza.memeaterbug.winapi.Process;
+import de.zabuza.memeaterbug.winapi.jna.util.Kernel32Util;
+import de.zabuza.memeaterbug.winapi.jna.util.PsapiUtil;
+
+/**
+ * Provides various methods for memory manipulation of a given process.
+ *
+ * @author Zabuza
+ *
+ */
+public final class MemManipulator {
+
+ /**
+ * The process this object belongs to.
+ */
+ private final Process mProcess;
+
+ /**
+ * Creates a new object that is able to manipulate the memory of the given
+ * process.
+ *
+ * @param processId
+ * Id of the process to manipulate
+ */
+ public MemManipulator(final int processId) {
+ this(processId, null);
+ }
+
+ /**
+ * Creates a new object that is able to manipulate the memory of the given
+ * process.
+ *
+ * @param processId
+ * Id of the process to manipulate
+ * @param processHandle
+ * An optional previously created handle object that must
+ * correspond to the same process that is specified by processId.
+ * Using null results in the creation of a default
+ * handle, that has all access rights.
+ */
+ public MemManipulator(final int processId, final HANDLE processHandle) {
+ mProcess = PsapiUtil.getProcessById(processId);
+ if (processHandle != null) {
+ mProcess.setHandle(processHandle);
+ }
+ }
+
+ /**
+ * Finds a dynamic address given by its offsets from the process base
+ * address. It is assumed that the value stored at the base address is a
+ * pointer. It is also assumed that the pointer received by this stored
+ * pointer plus the first offset stores another pointer. The same principle
+ * must hold for all offsets. The resulting dynamic address is the pointer
+ * stored at this location.
+ *
+ * @param offsets
+ * Offsets that need to be followed
+ * @return The dynamic address received by following all offsets starting at
+ * the base address
+ */
+ public long findDynAddress(final int[] offsets) {
+ return findDynAddress(offsets, getBaseAddress());
+ }
+
+ /**
+ * Finds a dynamic address given by its offsets from the given starting
+ * address. It is assumed that the value stored at the base address is a
+ * pointer. It is also assumed that the pointer received by this stored
+ * pointer plus the first offset stores another pointer. The same principle
+ * must hold for all offsets. The resulting dynamic address is the pointer
+ * stored at this location.
+ *
+ * @param offsets
+ * Offsets that need to be followed
+ * @param startingAddress
+ * Address from which to start following the offsets
+ * @return The dynamic address received by following all offsets starting at
+ * the given starting address
+ */
+ public long findDynAddress(final int[] offsets, final long startingAddress) {
+ int size = Pointer.SIZE;
+ Memory pTemp = new Memory(size);
+ long pointerAddress = -1;
+
+ for (int i = 0; i < offsets.length; i++) {
+ if (i == 0) {
+ pTemp = Kernel32Util.readMemory(mProcess.getHandle(), startingAddress, size);
+ }
+
+ pointerAddress = pTemp.getInt(0) + offsets[i];
+
+ if (i != offsets.length - 1) {
+ pTemp = Kernel32Util.readMemory(mProcess.getHandle(), pointerAddress, size);
+ }
+ }
+ return pointerAddress;
+ }
+
+ /**
+ * Gets the load address of this process module.
+ *
+ * @return The load address of this process module
+ */
+ public long getBaseAddress() {
+ return Pointer.nativeValue(mProcess.getBase());
+ }
+
+ /**
+ * Reads an integer from the given address.
+ *
+ * @param address
+ * Address to start reading from
+ * @return The integer read from the given address.
+ */
+ public int readInt(final long address) {
+ Memory value = readMemory(address, MemSize.getIntSize());
+ return value.getInt(0);
+ }
+
+ /**
+ * Reads a number of bytes starting from a given address.
+ *
+ * @param address
+ * Address to start reading from
+ * @param bytesToRead
+ * Number of bytes to read
+ * @return Object holding the read bytes
+ */
+ public Memory readMemory(final long address, final int bytesToRead) {
+ return Kernel32Util.readMemory(mProcess.getHandle(), address, bytesToRead);
+ }
+
+ /**
+ * Reads a string from the given address using the default platform
+ * encoding.
+ *
+ * @param address
+ * Address to start reading from
+ * @param size
+ * The size of the string to read, in bytes
+ * @return The string read from the given address
+ */
+ public String readString(final long address, final int size) {
+ Memory output = Kernel32Util.readMemory(mProcess.getHandle(), address, size);
+ return output.getString(0);
+ }
+
+ /**
+ * Reads a string from the given address using the given encoding.
+ *
+ * @param address
+ * Address to start reading from
+ * @param encoding
+ * Encoding to use
+ * @param length
+ * Length of the string to read, as amount of characters
+ * @param sizeOfOneChar
+ * The size of one character in the given encoding, in bytes
+ * @return The string read from the given address
+ * @throws UnsupportedEncodingException
+ * If the given encoding is not supported
+ */
+ public String readString(final long address, final String encoding, final int length, final int sizeOfOneChar)
+ throws UnsupportedEncodingException {
+ if (!Charset.availableCharsets().keySet().contains(encoding)) {
+ throw new UnsupportedEncodingException();
+ }
+ Memory output = Kernel32Util.readMemory(mProcess.getHandle(), address, sizeOfOneChar * length);
+ return output.getString(0, encoding);
+ }
+
+ /**
+ * Writes the given integer to the given address.
+ *
+ * @param address
+ * The address to write at
+ * @param valueToWrite
+ * The value to write
+ */
+ public void writeInt(final long address, final int valueToWrite) {
+ byte[] bytesToWriteReversed = ByteBuffer.allocate(MemSize.getIntSize()).putInt(valueToWrite).array();
+ writeMemoryReversely(address, bytesToWriteReversed);
+ }
+
+ /**
+ * Writes the given bytes to the given address.
+ *
+ * @param address
+ * The address to write at
+ * @param bytesToWrite
+ * The bytes to write. Read from left to right, i.e. from the
+ * lower to the higher indices.
+ */
+ public void writeMemory(final long address, final byte[] bytesToWrite) {
+ Kernel32Util.writeMemory(mProcess.getHandle(), address, bytesToWrite);
+ }
+
+ /**
+ * Writes the given bytes reversely to the given address.
+ *
+ * @param address
+ * The address to write at
+ * @param bytesToWrite
+ * The bytes to write reversely. Read from right to left, i.e.
+ * from the higher to the lower indices.
+ */
+ public void writeMemoryReversely(final long address, final byte[] bytesToWrite) {
+ Kernel32Util.writeMemoryReversely(mProcess.getHandle(), address, bytesToWrite);
+ }
+
+ /**
+ * Writes the given string to the given address using the default platform
+ * encoding.
+ *
+ * @param address
+ * The address to write at
+ * @param toWrite
+ * The string to write
+ */
+ public void writeString(final long address, final String toWrite) {
+ writeMemory(address, toWrite.getBytes());
+ }
+
+ /**
+ * Writes the given string to the given address using the given encoding.
+ *
+ * @param address
+ * The address to write at
+ * @param toWrite
+ * The string to write
+ * @param encoding
+ * The encoding to use for decoding the string
+ * @throws UnsupportedEncodingException
+ * If the given encoding is not supported
+ */
+ public void writeString(final long address, final String toWrite, final String encoding)
+ throws UnsupportedEncodingException {
+ writeMemory(address, toWrite.getBytes(encoding));
+ }
+}
diff --git a/src/de/zabuza/memeaterbug/memory/MemSize.java b/src/de/zabuza/memeaterbug/memory/MemSize.java
new file mode 100644
index 0000000..f1ea000
--- /dev/null
+++ b/src/de/zabuza/memeaterbug/memory/MemSize.java
@@ -0,0 +1,68 @@
+package de.zabuza.memeaterbug.memory;
+
+import com.sun.jna.Native;
+import com.sun.jna.platform.win32.WinDef.HMODULE;
+import com.sun.jna.platform.win32.WinNT.HANDLE;
+
+import de.zabuza.memeaterbug.winapi.jna.util.Kernel32Util;
+
+/**
+ * Provides methods for getting the size of different data types that are used
+ * at memory interaction.
+ *
+ * @author Zabuza
+ *
+ */
+public final class MemSize {
+
+ /**
+ * Cached constant for the size of an integer in bytes.
+ */
+ private static int intSize = -1;
+
+ /**
+ * Size of a module handle {@link HMODULE} in a 32 bit process.
+ */
+ private static final int MODULE_SIZE_32 = 4;
+
+ /**
+ * Size of a module handle {@link HMODULE} in a 64 bit process.
+ */
+ private static final int MODULE_SIZE_64 = 8;
+
+ /**
+ * Gets the size of an integer in bytes on the current platform.
+ *
+ * @return The size of an integer in bytes
+ */
+ public static int getIntSize() {
+ if (intSize == -1) {
+ intSize = Native.getNativeSize(int.class);
+ }
+ return intSize;
+ }
+
+ /**
+ * Gets the size of a module handle {@link HMODULE} in the given process. It
+ * is determined by the architecture the process is using.
+ *
+ * @param hProcess
+ * Handle to the process
+ * @return The size of a module handle {@link HMODULE} in the given process,
+ * in bytes
+ */
+ public static int getSizeOfModule(final HANDLE hProcess) {
+ if (Kernel32Util.is64Bit(hProcess)) {
+ return MODULE_SIZE_64;
+ } else {
+ return MODULE_SIZE_32;
+ }
+ }
+
+ /**
+ * Utility class. No implementation.
+ */
+ private MemSize() {
+
+ }
+}
diff --git a/src/de/zabuza/memeaterbug/memory/package-info.java b/src/de/zabuza/memeaterbug/memory/package-info.java
new file mode 100644
index 0000000..f68c687
--- /dev/null
+++ b/src/de/zabuza/memeaterbug/memory/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * This is the core package for memory interaction with Mem-Eater-Bug.
+ */
+package de.zabuza.memeaterbug.memory;
\ No newline at end of file
diff --git a/src/de/zabuza/memeaterbug/util/Masks.java b/src/de/zabuza/memeaterbug/util/Masks.java
index 9afb708..fdba8f6 100644
--- a/src/de/zabuza/memeaterbug/util/Masks.java
+++ b/src/de/zabuza/memeaterbug/util/Masks.java
@@ -12,6 +12,10 @@ public final class Masks {
* system.
*/
public static final String OS_NAME_WINDOWS = "windows";
+ /**
+ * Search mask for a 32-bit processor architecture.
+ */
+ public static final String PRC_ARCH_32BIT = "x86";
/**
* Utility class. No implementation.
diff --git a/src/de/zabuza/memeaterbug/util/SystemProperties.java b/src/de/zabuza/memeaterbug/util/SystemProperties.java
index 3baa0e4..ae45fc3 100644
--- a/src/de/zabuza/memeaterbug/util/SystemProperties.java
+++ b/src/de/zabuza/memeaterbug/util/SystemProperties.java
@@ -2,7 +2,7 @@
/**
* Utility class that provides system property keys for usage with
- * {@link System#getProperty(String)}.
+ * {@link System#getProperty(String)} or similar methods.
*
* @author Zabuza
*
@@ -12,6 +12,10 @@ public final class SystemProperties {
* Property key for the name of the operating system.
*/
public static final String OS_NAME = "os.name";
+ /**
+ * Property key for the processor architecture.
+ */
+ public static final String PRC_ARCH = "PROCESSOR_ARCHITECTURE";
/**
* Utility class. No implementation.
diff --git a/src/de/zabuza/memeaterbug/winapi/api/Module.java b/src/de/zabuza/memeaterbug/winapi/Module.java
similarity index 85%
rename from src/de/zabuza/memeaterbug/winapi/api/Module.java
rename to src/de/zabuza/memeaterbug/winapi/Module.java
index 24e0470..1dcc1cf 100644
--- a/src/de/zabuza/memeaterbug/winapi/api/Module.java
+++ b/src/de/zabuza/memeaterbug/winapi/Module.java
@@ -1,11 +1,10 @@
-package de.zabuza.memeaterbug.winapi.api;
+package de.zabuza.memeaterbug.winapi;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import de.zabuza.memeaterbug.winapi.jna.Psapi.LPMODULEINFO;
-import de.zabuza.memeaterbug.winapi.jna.util.Kernel32Util;
import de.zabuza.memeaterbug.winapi.jna.util.PsapiUtil;
/**
@@ -19,33 +18,6 @@
*
*/
public final class Module {
-
- /**
- * Size of a module handle {@link HMODULE} in a 32 bit process.
- */
- private static final int MODULE_SIZE_32 = 4;
- /**
- * Size of a module handle {@link HMODULE} in a 64 bit process.
- */
- private static final int MODULE_SIZE_64 = 8;
-
- /**
- * Gets the size of a module handle {@link HMODULE} in the given process. It
- * is determined by the architecture the process is using.
- *
- * @param hProcess
- * Handle to the process
- * @return The size of a module handle {@link HMODULE} in the given process,
- * in bytes
- */
- public static int getSizeOfModule(final HANDLE hProcess) {
- if (Kernel32Util.is64Bit(hProcess)) {
- return MODULE_SIZE_64;
- } else {
- return MODULE_SIZE_32;
- }
- }
-
/**
* The entry point of the module.
*
diff --git a/src/de/zabuza/memeaterbug/winapi/api/Process.java b/src/de/zabuza/memeaterbug/winapi/Process.java
similarity index 96%
rename from src/de/zabuza/memeaterbug/winapi/api/Process.java
rename to src/de/zabuza/memeaterbug/winapi/Process.java
index 4a68aa1..27b7c17 100644
--- a/src/de/zabuza/memeaterbug/winapi/api/Process.java
+++ b/src/de/zabuza/memeaterbug/winapi/Process.java
@@ -1,4 +1,4 @@
-package de.zabuza.memeaterbug.winapi.api;
+package de.zabuza.memeaterbug.winapi;
import java.io.File;
import java.util.LinkedList;
@@ -556,4 +556,22 @@ public void readProcessMemory(final int pAddress, final Pointer outputBuffer, fi
final IntByReference outNumberOfBytesRead) {
Kernel32Util.readProcessMemory(getHandle(), pAddress, outputBuffer, nSize, outNumberOfBytesRead);
}
+
+ /**
+ * Sets the handle to this process. It must be ensured that the handle
+ * belongs to the same process that was used at construction of this object.
+ * It must also be ensured that it has all necessary access rights.
+ *
+ * If the process already contained another handle object, it will
+ * automatically closed to free resources.
+ *
+ * @param processHandle
+ * Handle to this process
+ */
+ public void setHandle(final HANDLE processHandle) {
+ if (mHandleCache != null) {
+ Kernel32Util.closeHandle(mHandleCache);
+ }
+ mHandleCache = processHandle;
+ }
}
diff --git a/src/de/zabuza/memeaterbug/winapi/api/ProcessList.java b/src/de/zabuza/memeaterbug/winapi/ProcessList.java
similarity index 89%
rename from src/de/zabuza/memeaterbug/winapi/api/ProcessList.java
rename to src/de/zabuza/memeaterbug/winapi/ProcessList.java
index 88fa739..c47275e 100644
--- a/src/de/zabuza/memeaterbug/winapi/api/ProcessList.java
+++ b/src/de/zabuza/memeaterbug/winapi/ProcessList.java
@@ -1,4 +1,4 @@
-package de.zabuza.memeaterbug.winapi.api;
+package de.zabuza.memeaterbug.winapi;
import java.util.HashMap;
import java.util.Iterator;
@@ -9,8 +9,8 @@
import com.sun.jna.platform.win32.WinDef.HWND;
/**
- * List that holds {@link de.zabuza.memeaterbug.winapi.api.Process Process}
- * objects. Implemented as linked and hashed map.
+ * List that holds {@link de.zabuza.memeaterbug.winapi.Process Process} objects.
+ * Implemented as linked and hashed map.
*
* @author Zabuza
*
diff --git a/src/de/zabuza/memeaterbug/winapi/jna/Kernel32.java b/src/de/zabuza/memeaterbug/winapi/jna/Kernel32.java
index 47d881e..944f08f 100644
--- a/src/de/zabuza/memeaterbug/winapi/jna/Kernel32.java
+++ b/src/de/zabuza/memeaterbug/winapi/jna/Kernel32.java
@@ -19,35 +19,6 @@ public interface Kernel32 extends com.sun.jna.platform.win32.Kernel32 {
*/
public Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, W32APIOptions.DEFAULT_OPTIONS);
- /**
- * Determines whether the specified process is running under
- * WOW64.
- *
- * @see
- * MSDN webpage#IsWow64Process function
- *
- * @param hProcess
- * A handle to the process. The handle must have the
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_INFORMATION
- * PROCESS_QUERY_INFORMATION} or
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_LIMITED_INFORMATION
- * PROCESS_QUERY_LIMITED_INFORMATION} access right.
- * @param Wow64Process
- * A pointer to a value that is set to true if the
- * process is running under WOW64. If the process is running
- * under 32-bit Windows, the value is set to false. If
- * the process is a 64-bit application running under 64-bit
- * Windows, the value is also set to false.
- * @return If the function succeeds, the return value is a nonzero value.
- *
- *
- * If the function fails, the return value is zero. To get extended
- * error information, call {@link #Native.GetLastError()}.
- */
- public boolean IsWow64Process(final HANDLE hProcess, final boolean Wow64Process);
-
/**
* Reads data from an area of memory in a specified process. The entire area
* to be read must be accessible or the operation fails.
@@ -59,7 +30,7 @@ public interface Kernel32 extends com.sun.jna.platform.win32.Kernel32 {
* @param hProcess
* A handle to the process with memory that is being read. The
* handle must have
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_READ
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_READ
* PROCESS_VM_READ} access to the process.
* @param lpBaseAddress
* The base address in the specified process from which to read.
@@ -100,9 +71,9 @@ public boolean ReadProcessMemory(final HANDLE hProcess, final long lpBaseAddress
* @param hProcess
* A handle to the process memory to be modified. The handle must
* have
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_WRITE
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_WRITE
* PROCESS_VM_WRITE} and
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_OPERATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_OPERATION
* PROCESS_VM_OPERATION} access to the process.
* @param lpBaseAddress
* The base address in the specified process to which data is
diff --git a/src/de/zabuza/memeaterbug/winapi/jna/Psapi.java b/src/de/zabuza/memeaterbug/winapi/jna/Psapi.java
index 6ad6b89..828f7d7 100644
--- a/src/de/zabuza/memeaterbug/winapi/jna/Psapi.java
+++ b/src/de/zabuza/memeaterbug/winapi/jna/Psapi.java
@@ -179,9 +179,9 @@ public boolean EnumProcessModulesEx(final HANDLE hProcess, final HMODULE[] lphMo
* A handle to the process that contains the module.
*
* The handle must have the
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_INFORMATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_QUERY_INFORMATION
* PROCESS_QUERY_INFORMATION} and
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_READ
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_READ
* PROCESS_VM_READ} access rights.
* @param hModule
* A handle to the module.
@@ -207,9 +207,9 @@ public boolean GetModuleInformation(final HANDLE hProcess, final HMODULE hModule
*
* @param hProcess
* A handle to the process. The handle must have the
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_INFORMATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_QUERY_INFORMATION
* PROCESS_QUERY_INFORMATION} or
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_LIMITED_INFORMATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_QUERY_LIMITED_INFORMATION
* PROCESS_QUERY_LIMITED_INFORMATION} access right.
* @param lpImageFileName
* A pointer to a buffer that receives the full path to the
diff --git a/src/de/zabuza/memeaterbug/winapi/jna/util/Kernel32Util.java b/src/de/zabuza/memeaterbug/winapi/jna/util/Kernel32Util.java
index 26445fb..5ea969b 100644
--- a/src/de/zabuza/memeaterbug/winapi/jna/util/Kernel32Util.java
+++ b/src/de/zabuza/memeaterbug/winapi/jna/util/Kernel32Util.java
@@ -18,8 +18,10 @@
import com.sun.jna.platform.win32.WinNT.MEMORY_BASIC_INFORMATION;
import com.sun.jna.ptr.IntByReference;
-import de.zabuza.memeaterbug.winapi.api.Process;
-import de.zabuza.memeaterbug.winapi.api.ProcessList;
+import de.zabuza.memeaterbug.util.Masks;
+import de.zabuza.memeaterbug.util.SystemProperties;
+import de.zabuza.memeaterbug.winapi.Process;
+import de.zabuza.memeaterbug.winapi.ProcessList;
import de.zabuza.memeaterbug.winapi.jna.Kernel32;
import de.zabuza.memeaterbug.winapi.jna.User32;
@@ -166,15 +168,16 @@ public static ProcessList getProcessList() throws Win32Exception {
* If the operation was not successful
*/
public static boolean is64Bit(final HANDLE hProcess) throws Win32Exception {
- if (System.getenv("PROCESSOR_ARCHITECTURE") == "x86") {
+ if (System.getenv(SystemProperties.PRC_ARCH) == Masks.PRC_ARCH_32BIT) {
return false;
}
- boolean isWow64 = false;
+
+ IntByReference isWow64 = new IntByReference();
boolean success = Kernel32.INSTANCE.IsWow64Process(hProcess, isWow64);
if (!success) {
throw new Win32Exception(Native.getLastError());
}
- return !isWow64;
+ return isWow64.getValue() == 0;
}
/**
@@ -252,7 +255,7 @@ public static Memory readMemory(final HANDLE process, final long address, final
* @param hProcess
* A handle to the process with memory that is being read. The
* handle must have
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_READ
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_READ
* PROCESS_VM_READ} access to the process.
* @param pAddress
* The base address in the specified process from which to read.
@@ -291,7 +294,7 @@ public static void readProcessMemory(final HANDLE hProcess, final long pAddress,
* @param hProcess
* A handle to the process whose memory information is queried.
* The handle must have been opened with the
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_INFORMATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_QUERY_INFORMATION
* PROCESS_QUERY_INFORMATION} access right, which enables using
* the handle to read information from the process object.
* @param lpAddress
@@ -324,9 +327,9 @@ public static MEMORY_BASIC_INFORMATION virtualQueryEx(final HANDLE hProcess, fin
* @param process
* A handle to the process memory to be modified. The handle must
* have
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_WRITE
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_WRITE
* PROCESS_VM_WRITE} and
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_OPERATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_OPERATION
* PROCESS_VM_OPERATION} access to the process.
* @param address
* A pointer to the base address in the specified process to
@@ -336,7 +339,8 @@ public static MEMORY_BASIC_INFORMATION virtualQueryEx(final HANDLE hProcess, fin
* not accessible, the function fails.
* @param data
* A buffer that contains data to be written in the address space
- * of the specified process.
+ * of the specified process. Read from left to right, i.e. from
+ * the lower to the higher indices.
* @throws Win32Exception
* If the operation was not successful
*/
@@ -351,6 +355,46 @@ public static void writeMemory(final HANDLE process, final long address, final b
Kernel32Util.writeProcessMemory(process, address, toWrite, size, null);
}
+ /**
+ * Writes data reversely to an area of memory in a specified process. The
+ * entire area to be written to must be accessible or the operation fails.
+ *
+ * @see
+ * MSDN webpage#WriteProcessMemory function
+ * @param process
+ * A handle to the process memory to be modified. The handle must
+ * have
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_WRITE
+ * PROCESS_VM_WRITE} and
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_OPERATION
+ * PROCESS_VM_OPERATION} access to the process.
+ * @param address
+ * A pointer to the base address in the specified process to
+ * which data is written. Before data transfer occurs, the system
+ * verifies that all data in the base address and memory of the
+ * specified size is accessible for write access, and if it is
+ * not accessible, the function fails.
+ * @param data
+ * A buffer that contains data to be written reversely in the
+ * address space of the specified process. Read from right to
+ * left, i.e. from the higher to the lower indices.
+ * @throws Win32Exception
+ * If the operation was not successful
+ */
+ public static void writeMemoryReversely(final HANDLE process, final long address, final byte[] data)
+ throws Win32Exception {
+ int size = data.length;
+ Memory toWrite = new Memory(size);
+
+ int lastIndex = size - 1;
+ for (int i = 0; i < size; i++) {
+ toWrite.setByte(i, data[lastIndex - i]);
+ }
+
+ Kernel32Util.writeProcessMemory(process, address, toWrite, size, null);
+ }
+
/**
* Writes data to an area of memory in a specified process. The entire area
* to be written to must be accessible or the operation fails.
@@ -362,9 +406,9 @@ public static void writeMemory(final HANDLE process, final long address, final b
* @param hProcess
* A handle to the process memory to be modified. The handle must
* have
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_WRITE
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_WRITE
* PROCESS_VM_WRITE} and
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_OPERATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_OPERATION
* PROCESS_VM_OPERATION} access to the process.
* @param lpBaseAddress
* A pointer to the base address in the specified process to
diff --git a/src/de/zabuza/memeaterbug/winapi/jna/util/PsapiUtil.java b/src/de/zabuza/memeaterbug/winapi/jna/util/PsapiUtil.java
index b7bd123..b59ac6d 100644
--- a/src/de/zabuza/memeaterbug/winapi/jna/util/PsapiUtil.java
+++ b/src/de/zabuza/memeaterbug/winapi/jna/util/PsapiUtil.java
@@ -11,10 +11,10 @@
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
-import de.zabuza.memeaterbug.winapi.api.Module;
+import de.zabuza.memeaterbug.memory.MemSize;
+import de.zabuza.memeaterbug.winapi.Process;
import de.zabuza.memeaterbug.winapi.jna.Psapi;
import de.zabuza.memeaterbug.winapi.jna.Psapi.LPMODULEINFO;
-import de.zabuza.memeaterbug.winapi.api.Process;
/**
* Provides various utility methods that use the JNA interface for Windows
@@ -80,7 +80,7 @@ public static List enumProcessModules(final HANDLE hProcess) throws Win
*/
public static List enumProcessModulesEx(final HANDLE hProcess, final Integer listFlag)
throws Win32Exception {
- int moduleSize = Module.getSizeOfModule(hProcess);
+ int moduleSize = MemSize.getSizeOfModule(hProcess);
List list = new LinkedList();
HMODULE[] lphModule = new HMODULE[MODULE_BUFFER_AMOUNT * moduleSize];
@@ -147,9 +147,9 @@ public static List enumProcessModulesEx64(final HANDLE hProcess) throws
* @param hProcess
* A handle to the process that contains the module. The handle
* must have the
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_INFORMATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_QUERY_INFORMATION
* PROCESS_QUERY_INFORMATION} and
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_READ
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_READ
* PROCESS_VM_READ} access rights.
* @param hModule
* A handle to the module. If this parameter is null,
@@ -179,9 +179,9 @@ public static String getModuleFileNameEx(final HANDLE hProcess, final HANDLE hMo
* A handle to the process that contains the module.
*
* The handle must have the
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_INFORMATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_QUERY_INFORMATION
* PROCESS_QUERY_INFORMATION} and
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_VM_READ
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_VM_READ
* PROCESS_VM_READ} access rights.
* @param hModule
* A handle to the module.
@@ -200,6 +200,25 @@ public static LPMODULEINFO getModuleInformation(final HANDLE hProcess, final HMO
return lpmodinfo;
}
+ /**
+ * Gets a process wrapper for the process given by its id.
+ *
+ * @param processId
+ * Id of the process to get the wrapper for
+ * @return Process wrapper for the process given by its id or null
+ * if not found
+ */
+ public static Process getProcessById(final int processId) {
+ Iterator processes = Kernel32Util.getProcessList().iterator();
+ while (processes.hasNext()) {
+ Process process = processes.next();
+ if (process.getPid() == processId) {
+ return process;
+ }
+ }
+ return null;
+ }
+
/**
* Retrieves the id of the process that belongs to the given exe-file name.
*
@@ -232,9 +251,9 @@ public static int getProcessIdBySzExeFile(final String szExeFile) {
* MSDN webpage#GetProcessImageFileName function
* @param hProcess
* A handle to the process. The handle must have the
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_INFORMATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_QUERY_INFORMATION
* PROCESS_QUERY_INFORMATION} or
- * {@link de.zabuza.memeaterbug.winapi.api.Process#PROCESS_QUERY_LIMITED_INFORMATION
+ * {@link de.zabuza.memeaterbug.winapi.Process#PROCESS_QUERY_LIMITED_INFORMATION
* PROCESS_QUERY_LIMITED_INFORMATION} access right.
* @return The name of the executable file for the specified process.
* @throws Win32Exception
diff --git a/src/de/zabuza/memeaterbug/winapi/api/package-info.java b/src/de/zabuza/memeaterbug/winapi/package-info.java
similarity index 64%
rename from src/de/zabuza/memeaterbug/winapi/api/package-info.java
rename to src/de/zabuza/memeaterbug/winapi/package-info.java
index 5bbc08c..1768fc7 100644
--- a/src/de/zabuza/memeaterbug/winapi/api/package-info.java
+++ b/src/de/zabuza/memeaterbug/winapi/package-info.java
@@ -1,4 +1,4 @@
-/**
- * This is the core package for interacting with windows API functions.
- */
-package de.zabuza.memeaterbug.winapi.api;
\ No newline at end of file
+/**
+ * This is the core package for interacting with windows API functions.
+ */
+package de.zabuza.memeaterbug.winapi;
\ No newline at end of file