├── .gitattributes ├── .gitignore ├── README.md ├── pom.xml └── src └── main └── java └── dev └── sim0n └── antiagent └── Example.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files we want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.java text 7 | *.xml text 8 | *.yml text 9 | README.md text 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse stuff 2 | .classpath 3 | .project 4 | .settings/ 5 | 6 | # netbeans 7 | nbproject/ 8 | nbactions.xml 9 | 10 | # we use maven! 11 | build.xml 12 | 13 | # maven 14 | target/ 15 | dependency-reduced-pom.xml 16 | 17 | # vim 18 | .*.sw[a-p] 19 | 20 | # various other potential build files 21 | build/ 22 | bin/ 23 | dist/ 24 | manifest.mf 25 | 26 | # Mac filesystem dust 27 | .DS_Store/ 28 | 29 | # intellij 30 | *.iml 31 | *.ipr 32 | *.iws 33 | .idea/ 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## anti-java-agent 2 | This is a basic example of preventing instrumentation via attaching a [Java Agent](https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html). This can be bypassed pretty easily but should still prevent the skids. 3 | 4 | ### How does it work? 5 | It works by loading our own class, which is a fake of Sun's Java side JPLIS implementation. Now, to make sure we always create that class we need to make sure no one is loading an agent at the start, so we check the VM options before we load our class. -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | dev.sim0n 9 | anti-java-agent 10 | 1.0-SNAPSHOT 11 | 12 | anti-java-agent 13 | 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 3.8.0 21 | 22 | 8 23 | 8 24 | 25 | 26 | 27 | 28 | org.apache.maven.plugins 29 | maven-jar-plugin 30 | 31 | 32 | 33 | dev.sim0n.antiagent.Example 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 8 44 | 8 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/main/java/dev/sim0n/antiagent/Example.java: -------------------------------------------------------------------------------- 1 | package dev.sim0n.antiagent; 2 | 3 | import sun.misc.Unsafe; 4 | 5 | import java.lang.management.ManagementFactory; 6 | import java.lang.reflect.Field; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | public class Example { 12 | private static final List BAD_INPUT_FLAGS = Arrays.asList( 13 | "-javaagent", 14 | "-agentlib" 15 | ); 16 | 17 | private static final byte[] EMPTY_CLASS_BYTES = 18 | { 19 | -54, -2, -70, -66, 0, 0, 0, 49, 0, 5, 1, 0, 34, 115, 117, 110, 20 | 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 47, 73, 21 | 110, 115, 116, 114, 117, 109, 101, 110, 116, 97, 116, 105, 111, 22 | 110, 73, 109, 112, 108, 7, 0, 1, 1, 0, 16, 106, 97, 118, 97, 47, 23 | 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 7, 0, 3, 0, 1, 24 | 0, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0 25 | }; 26 | 27 | public static void main(String[] args) { 28 | Optional inputFlag = ManagementFactory.getRuntimeMXBean().getInputArguments().stream() 29 | .filter(input -> BAD_INPUT_FLAGS.stream().anyMatch(input::contains)) 30 | .findFirst(); 31 | 32 | // if there's a bad input flag present in the vm options 33 | // then InstrumentationImpl will already have been loaded 34 | if (inputFlag.isPresent()) { 35 | throw new IllegalArgumentException(String.format("Bad VM option \"%s\"", inputFlag.get())); 36 | } 37 | 38 | Unsafe unsafe = Example.getUnsafe(); 39 | 40 | unsafe.defineClass("sun.instrument.InstrumentationImpl", EMPTY_CLASS_BYTES, 0, EMPTY_CLASS_BYTES.length, null, null); 41 | 42 | // this is for testing purposes to make sure it's actually loaded 43 | try { 44 | Class.forName("sun.instrument.InstrumentationImpl"); 45 | } catch (ClassNotFoundException e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | 50 | private static Unsafe getUnsafe() { 51 | try { 52 | Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 53 | 54 | unsafeField.setAccessible(true); 55 | 56 | return (Unsafe) unsafeField.get(null); 57 | } catch (NoSuchFieldException | IllegalAccessException e) { 58 | e.printStackTrace(); 59 | return null; 60 | } 61 | } 62 | } 63 | --------------------------------------------------------------------------------