├── .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 |
--------------------------------------------------------------------------------