diff --git a/lib/attach.dll b/lib/attach.dll new file mode 100644 index 0000000..10421f1 Binary files /dev/null and b/lib/attach.dll differ diff --git a/lib/tools.jar b/lib/tools.jar new file mode 100644 index 0000000..884a0d0 Binary files /dev/null and b/lib/tools.jar differ diff --git a/releases/memEaterBug-1.0.zip b/releases/memEaterBug-1.0.zip new file mode 100644 index 0000000..fb5f27a Binary files /dev/null and b/releases/memEaterBug-1.0.zip differ diff --git a/res/examples/SpaceInvaders.jar b/res/examples/SpaceInvaders.jar new file mode 100644 index 0000000..644dd86 Binary files /dev/null and b/res/examples/SpaceInvaders.jar differ diff --git a/res/examples/SpaceInvadersInjection.jar b/res/examples/SpaceInvadersInjection.jar new file mode 100644 index 0000000..dfdcfd9 Binary files /dev/null and b/res/examples/SpaceInvadersInjection.jar differ diff --git a/src/de/zabuza/memeaterbug/MemEaterBug.java b/src/de/zabuza/memeaterbug/MemEaterBug.java index 4f5e379..629b306 100644 --- a/src/de/zabuza/memeaterbug/MemEaterBug.java +++ b/src/de/zabuza/memeaterbug/MemEaterBug.java @@ -2,6 +2,8 @@ import com.sun.jna.platform.win32.WinNT.HANDLE; +import de.zabuza.memeaterbug.exceptions.NotHookedException; +import de.zabuza.memeaterbug.injection.Injector; import de.zabuza.memeaterbug.locale.ErrorMessages; import de.zabuza.memeaterbug.memory.MemManipulator; import de.zabuza.memeaterbug.util.Masks; @@ -26,6 +28,10 @@ */ public final class MemEaterBug { + /** + * Injector for the current process handle, if hooked, null else. + */ + private Injector mInjector; /** * If the current process runs in an 64 bit environment or not. Can only be * accessed after the the Mem-Eater-Bug was hooked to a process using @@ -73,6 +79,7 @@ public MemEaterBug(final int processId) { mIsHooked = false; mProcessHandle = null; mMemManipulator = null; + mInjector = null; if (processId == 0) { throw new IllegalArgumentException(ErrorMessages.PROCESS_NOT_FOUND); @@ -115,6 +122,21 @@ public MemEaterBug(final String processClassName, final String windowTitle) { this(User32Util.getWindowThreadProcessIdByClassAndTitle(processClassName, windowTitle).getValue()); } + /** + * Gets an object for injecting code into the hooked process. + * + * @return An object for injecting code into the hooked process. + * @throws IllegalStateException + * If the Mem-Eater-Bug is not hooked to a process + */ + public Injector getInjector() throws IllegalStateException { + ensureIsHooked(); + if (mInjector == null) { + mInjector = new Injector(mProcessId, mProcessHandle); + } + return mInjector; + } + /** * Gets an object for memory manipulation of the hooked process. * @@ -224,6 +246,7 @@ public void unhookProcess() { } mProcessHandle = null; mMemManipulator = null; + mInjector = null; mIsHooked = false; } @@ -236,7 +259,7 @@ public void unhookProcess() { */ private void ensureIsHooked() throws IllegalStateException { if (!mIsHooked) { - throw new IllegalStateException(ErrorMessages.UNABLE_SINCE_NOT_HOOKED); + throw new NotHookedException(ErrorMessages.UNABLE_SINCE_NOT_HOOKED); } } diff --git a/src/de/zabuza/memeaterbug/examples/SoliScorer.java b/src/de/zabuza/memeaterbug/examples/SoliScorer.java index 0884534..4619fdd 100644 --- a/src/de/zabuza/memeaterbug/examples/SoliScorer.java +++ b/src/de/zabuza/memeaterbug/examples/SoliScorer.java @@ -50,4 +50,11 @@ public static void main(final String[] args) { // Unhook from the game memEaterBug.unhookProcess(); } + + /** + * Utility class. No implementation. + */ + private SoliScorer() { + + } } diff --git a/src/de/zabuza/memeaterbug/examples/SpaceInvadersInjection.java b/src/de/zabuza/memeaterbug/examples/SpaceInvadersInjection.java new file mode 100644 index 0000000..95a8bb7 --- /dev/null +++ b/src/de/zabuza/memeaterbug/examples/SpaceInvadersInjection.java @@ -0,0 +1,41 @@ +package de.zabuza.memeaterbug.examples; + +import java.lang.instrument.Instrumentation; + +/** + * Hack for the popular game Space Invaders that displays various information on + * the game screen by jar-injection.
+ *
+ * This is the agent as jar that gets injected inside the Space Invaders + * jar-file. + * + * @author Zabuza + * + */ +public final class SpaceInvadersInjection { + + /** + * JVM hook to dynamically load this agent at runtime. + * + * @param args + * Passed arguments, not supported + * @param inst + * Object used for ByteCode manipulation + */ + public static void agentmain(final String args, final Instrumentation inst) { + try { + System.out.println("Injected the agent."); + } catch (Exception e) { + // Catch and print every exception as they would otherwise be + // ignored in an agentmain method + e.printStackTrace(); + } + } + + /** + * Utility class. No implementation. + */ + private SpaceInvadersInjection() { + + } +} diff --git a/src/de/zabuza/memeaterbug/examples/SpaceInvadersInjector.java b/src/de/zabuza/memeaterbug/examples/SpaceInvadersInjector.java new file mode 100644 index 0000000..458778a --- /dev/null +++ b/src/de/zabuza/memeaterbug/examples/SpaceInvadersInjector.java @@ -0,0 +1,48 @@ +package de.zabuza.memeaterbug.examples; + +import de.zabuza.memeaterbug.MemEaterBug; +import de.zabuza.memeaterbug.injection.Injector; + +/** + * Hack for the popular game Space Invaders that displays various information on + * the game screen by jar-injection. + * + * @author Zabuza + * + */ +public final class SpaceInvadersInjector { + /** + * Demonstrates the usage of the Mem-Eater-Bug for jar-injection by + * displaying various information on the game screen of the game Space + * Invaders.
+ *
+ * The program was tested on a Windows 10 64-bit system using the provided + * SpaceInvaders.jar file. + * + * @param args + * Not supported + */ + public static void main(final String[] args) { + // Constants + String windowTitle = "Space Invaders 101"; + String pathToInjectionAgent = "C:\\Users\\Zabuza\\Desktop\\SpaceInvadersInjection.jar"; + + // Hook to the game + MemEaterBug memEaterBug = new MemEaterBug(null, windowTitle); + memEaterBug.hookProcess(); + Injector injector = memEaterBug.getInjector(); + + // Inject the agent jar into the target jar + injector.injectJarIntoJar(pathToInjectionAgent); + + // Unhook from the game + memEaterBug.unhookProcess(); + } + + /** + * Utility class. No implementation. + */ + private SpaceInvadersInjector() { + + } +} diff --git a/src/de/zabuza/memeaterbug/exceptions/NotHookedException.java b/src/de/zabuza/memeaterbug/exceptions/NotHookedException.java new file mode 100644 index 0000000..512ca29 --- /dev/null +++ b/src/de/zabuza/memeaterbug/exceptions/NotHookedException.java @@ -0,0 +1,35 @@ +package de.zabuza.memeaterbug.exceptions; + +/** + * Thrown when a method could not be executed since the + * {@link de.zabuza.memeaterbug.MemEaterBug MemEaterBug} was not hooked to a + * process. + * + * @author Zabuza + * + */ +public final class NotHookedException extends RuntimeException { + + /** + * Serial UID. + */ + private static final long serialVersionUID = 1L; + + /** + * Creates a new exception without a detailed description. + */ + public NotHookedException() { + super(); + } + + /** + * Creates a new exception with a given description. + * + * @param description + * Description of the exception + */ + public NotHookedException(final String description) { + super(description); + } + +} diff --git a/src/de/zabuza/memeaterbug/exceptions/UnableToInjectException.java b/src/de/zabuza/memeaterbug/exceptions/UnableToInjectException.java new file mode 100644 index 0000000..40683a4 --- /dev/null +++ b/src/de/zabuza/memeaterbug/exceptions/UnableToInjectException.java @@ -0,0 +1,34 @@ +package de.zabuza.memeaterbug.exceptions; + +/** + * Thrown when an {@link de.zabuza.memeaterbug.injection.Injector Injector} + * method could not inject code into the given process. + * + * @author Zabuza + * + */ +public final class UnableToInjectException extends RuntimeException { + + /** + * Serial UID. + */ + private static final long serialVersionUID = 1L; + + /** + * Creates a new exception without a detailed description. + */ + public UnableToInjectException() { + super(); + } + + /** + * Creates a new exception with a given description. + * + * @param description + * Description of the exception + */ + public UnableToInjectException(final String description) { + super(description); + } + +} diff --git a/src/de/zabuza/memeaterbug/exceptions/package-info.java b/src/de/zabuza/memeaterbug/exceptions/package-info.java new file mode 100644 index 0000000..6afe2b9 --- /dev/null +++ b/src/de/zabuza/memeaterbug/exceptions/package-info.java @@ -0,0 +1,4 @@ +/** + * This is the core package for exceptions and error handling for Mem-Eater-Bug. + */ +package de.zabuza.memeaterbug.exceptions; \ No newline at end of file diff --git a/src/de/zabuza/memeaterbug/injection/Injector.java b/src/de/zabuza/memeaterbug/injection/Injector.java new file mode 100644 index 0000000..2b15649 --- /dev/null +++ b/src/de/zabuza/memeaterbug/injection/Injector.java @@ -0,0 +1,115 @@ +package de.zabuza.memeaterbug.injection; + +import java.io.IOException; + +import com.sun.jna.platform.win32.WinNT.HANDLE; +import com.sun.tools.attach.AgentInitializationException; +import com.sun.tools.attach.AgentLoadException; +import com.sun.tools.attach.AttachNotSupportedException; +import com.sun.tools.attach.VirtualMachine; + +import de.zabuza.memeaterbug.exceptions.UnableToInjectException; +import de.zabuza.memeaterbug.locale.ErrorMessages; +import de.zabuza.memeaterbug.winapi.Process; +import de.zabuza.memeaterbug.winapi.jna.util.PsapiUtil; + +/** + * Provides various methods for injecting code into a given process. + * + * @author Zabuza + * + */ +public final class Injector { + + /** + * Name of the attach library that is used for attaching to a virtual + * machine. + */ + private static final String ATTACH_LIBRARY_NAME = "attach"; + + /** + * The process this object belongs to. + */ + private final Process mProcess; + + /** + * Creates a new object that is able to inject code into the given process. + * + * @param processId + * Id of the process to inject into + */ + public Injector(final int processId) { + this(processId, null); + } + + /** + * Creates a new object that is able to inject code into the given process. + * + * @param processId + * Id of the process to inject into + * @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 Injector(final int processId, final HANDLE processHandle) { + mProcess = PsapiUtil.getProcessById(processId); + if (processHandle != null) { + mProcess.setHandle(processHandle); + } + loadAttachLibrary(); + } + + /** + * Loads the native attach library into the built path. It is used for + * attaching to a virtual machine. + */ + private void loadAttachLibrary() { + System.loadLibrary(ATTACH_LIBRARY_NAME); + } + + /** + * Injects a given agent jar-file into the hooked process. The hooked + * process also needs to be a jar-file. + * + * @param pathToAgentJar + * Path to the agent jar-file to inject. The agent jar-file needs + * to specify an agentmain-method and must have the Agent-Class + * key accordingly. + * @throws UnableToInjectException + * If the operation was unable to inject the agent jar-file into + * the target jar-file + */ + public void injectJarIntoJar(final String pathToAgentJar) throws UnableToInjectException { + try { + VirtualMachine vm = VirtualMachine.attach("" + mProcess.getPid()); + vm.loadAgent(pathToAgentJar); + vm.detach(); + } catch (AttachNotSupportedException | AgentLoadException | AgentInitializationException | IOException e) { + throw new UnableToInjectException(ErrorMessages.UNABLE_TO_INJECT_JAR_INTO_JAR); + } + } + + /** + * Injects a given agent library into the hooked process. The hooked process + * needs to be a jar-file. + * + * @param pathToAgentLibrary + * Path to the agent library to inject. The agent library needs + * to specify all needed agent-methods via the native agent + * interface. + * @throws UnableToInjectException + * If the operation was unable to inject the agent library into + * the target jar-file + */ + public void injectLibraryIntoJar(final String pathToAgentLibrary) throws UnableToInjectException { + try { + VirtualMachine vm = VirtualMachine.attach("" + mProcess.getPid()); + vm.loadAgentLibrary(pathToAgentLibrary); + vm.detach(); + } catch (AttachNotSupportedException | AgentLoadException | AgentInitializationException | IOException e) { + throw new UnableToInjectException(ErrorMessages.UNABLE_TO_INJECT_LIBRARY_INTO_JAR); + } + } +} diff --git a/src/de/zabuza/memeaterbug/injection/package-info.java b/src/de/zabuza/memeaterbug/injection/package-info.java new file mode 100644 index 0000000..67083af --- /dev/null +++ b/src/de/zabuza/memeaterbug/injection/package-info.java @@ -0,0 +1,4 @@ +/** + * This is the core package for injecting code into processes. + */ +package de.zabuza.memeaterbug.injection; \ No newline at end of file diff --git a/src/de/zabuza/memeaterbug/locale/ErrorMessages.java b/src/de/zabuza/memeaterbug/locale/ErrorMessages.java index cbe629f..95cb8c2 100644 --- a/src/de/zabuza/memeaterbug/locale/ErrorMessages.java +++ b/src/de/zabuza/memeaterbug/locale/ErrorMessages.java @@ -40,6 +40,16 @@ public final class ErrorMessages { * process. */ public static final String UNABLE_SINCE_NOT_HOOKED = "Unable to execute since not hooked to a process. First hook, then try again."; + /** + * Thrown when an {@link de.zabuza.memeaterbug.injection.Injector Injector} + * method could not inject an agent jar file into a target jar file. + */ + public static final String UNABLE_TO_INJECT_JAR_INTO_JAR = "Unable to inject the agent jar into the target jar. Ensure the target process is a jar-file and you have all needed permissions. Also make sure the agent jar specifies an agentmain-method and has set the Agent-Class key accordingly."; + /** + * Thrown when an {@link de.zabuza.memeaterbug.injection.Injector Injector} + * method could not inject an agent jar file into a target jar file. + */ + public static final String UNABLE_TO_INJECT_LIBRARY_INTO_JAR = "Unable to inject the agent library into the target jar. Ensure the target process is a jar-file and you have all needed permissions. Also make sure the agent library specifies all needed agent-methods via the native agent interface."; /** * Utility class. No implementation.