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: * * @@ -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