Initial commit
This commit is contained in:
parent
d2fc40f0a7
commit
1a965bd4e9
2
.gitignore
vendored
2
.gitignore
vendored
@ -12,3 +12,5 @@
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
.idea/
|
||||
.iml
|
||||
|
104
pom.xml
Normal file
104
pom.xml
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>eu.mikroskeem</groupId>
|
||||
<artifactId>bytecodehackery</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!--<plugin>
|
||||
<groupId>com.github.wvengen</groupId>
|
||||
<artifactId>proguard-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>proguard</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<options>
|
||||
<option>-keepattributes *Annotation*</option>
|
||||
<option>-allowaccessmodification</option>
|
||||
</options>
|
||||
<libs>
|
||||
<lib>${java.home}/lib/rt.jar</lib>
|
||||
<lib>${java.home}/lib/jce.jar</lib>
|
||||
</libs>
|
||||
</configuration>
|
||||
</plugin>-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.4.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/LICENSE</exclude>
|
||||
<exclude>META-INF/DEPENDENCIES</exclude>
|
||||
<exclude>META-INF/NOTICE</exclude>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
<exclude>META-INF/*.properties</exclude>
|
||||
<exclude>META-INF/maven/**</exclude>
|
||||
<exclude>META-INF/services/**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<mainClass>eu.mikroskeem.redpowder.leviathan.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<defaultGoal>clean compile package</defaultGoal>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-all</artifactId>
|
||||
<version>5.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,63 @@
|
||||
package eu.mikroskeem.bytecodehackery;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class GeneratedClassLoader extends ClassLoader {
|
||||
|
||||
/*
|
||||
* Note: "Stolen: from Techcable's Event4j,
|
||||
* https://github.com/Techcable/Event4J/blob/master/src/main/java/net/techcable/event4j/asm/ASMEventExecutorFactory.java
|
||||
*/
|
||||
|
||||
private static final ConcurrentMap<ClassLoader, GeneratedClassLoader> loaders = new ConcurrentHashMap<>();
|
||||
public static GeneratedClassLoader getLoader(ClassLoader parent) {
|
||||
return loaders.computeIfAbsent(Objects.requireNonNull(parent, "Null parent class-loader"), GeneratedClassLoader::new);
|
||||
}
|
||||
|
||||
public Class<?> defineClass(String name, byte[] data) {
|
||||
name = Objects.requireNonNull(name, "Null name").replace('/', '.');
|
||||
synchronized (getClassLoadingLock(name)) {
|
||||
if (hasClass(name)) throw new IllegalStateException(name + " already defined");
|
||||
Class<?> c = this.define(name, Objects.requireNonNull(data, "Null data"));
|
||||
if (!c.getName().equals(name)) throw new IllegalArgumentException("class name " + c.getName() + " != requested name " + name);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
protected GeneratedClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
private Class<?> define(String name, byte[] data) {
|
||||
synchronized (getClassLoadingLock(name)) {
|
||||
if (hasClass(name)) throw new IllegalStateException("Already has class: " + name);
|
||||
Class<?> c;
|
||||
try {
|
||||
c = defineClass(name, data, 0, data.length);
|
||||
} catch (ClassFormatError e) {
|
||||
throw new IllegalArgumentException("Illegal class data", e);
|
||||
}
|
||||
resolveClass(c);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getClassLoadingLock(String name) {
|
||||
return super.getClassLoadingLock(name);
|
||||
}
|
||||
|
||||
public boolean hasClass(String name) {
|
||||
synchronized (getClassLoadingLock(name)) {
|
||||
try {
|
||||
Class.forName(name);
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
77
src/main/java/eu/mikroskeem/bytecodehackery/Main.java
Normal file
77
src/main/java/eu/mikroskeem/bytecodehackery/Main.java
Normal file
@ -0,0 +1,77 @@
|
||||
package eu.mikroskeem.bytecodehackery;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class Main {
|
||||
private Main() throws Exception {
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
|
||||
/* Generate class */
|
||||
cw.visit(V1_8, ACC_PUBLIC, (getClass().getPackage().getName() +".kek.Topkek").replaceAll("\\.", "/"),
|
||||
null, "java/lang/Object", new String[]{Type.getInternalName(TestInterface.class)});
|
||||
|
||||
/* Generate constructor */
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
|
||||
/* Must-have for all classes */
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
|
||||
/* Generate toString method */
|
||||
String toStringDesc = String.format("(%s)%s", "", Type.getDescriptor(String.class));
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "toString", toStringDesc, null, null);
|
||||
mv.visitLdcInsn("TOPKEK LMAUUU");
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
|
||||
/* Generate a() method */
|
||||
String aDesc = String.format("(%s)%s", "", Type.getDescriptor(String.class));
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "a", aDesc, null, null);
|
||||
mv.visitLdcInsn("some a() call");
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
|
||||
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "b", "()Ljava/util/List;", "()Ljava/util/List<Ljava/lang/String;>;", null);
|
||||
mv.visitCode();
|
||||
mv.visitTypeInsn(NEW, "java/util/ArrayList");
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V", false);
|
||||
mv.visitVarInsn(ASTORE, 1);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitLdcInsn("kek");
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitLdcInsn("ayy lmao");
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true);
|
||||
mv.visitInsn(POP);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
|
||||
/* Class end */
|
||||
cw.visitEnd();
|
||||
|
||||
/* Load that class */
|
||||
Class<?> a = GeneratedClassLoader.getLoader(this.getClass().getClassLoader())
|
||||
.defineClass(getClass().getPackage().getName() +".kek.Topkek", cw.toByteArray());
|
||||
|
||||
TestInterface b = (TestInterface) a.newInstance();
|
||||
System.out.println(b.toString());
|
||||
System.out.println(b.a());
|
||||
System.out.println(b.b());
|
||||
}
|
||||
public static void main(String... a) throws Exception {
|
||||
new Main();
|
||||
}
|
||||
}
|
18
src/main/java/eu/mikroskeem/bytecodehackery/TestClass.java
Normal file
18
src/main/java/eu/mikroskeem/bytecodehackery/TestClass.java
Normal file
@ -0,0 +1,18 @@
|
||||
package eu.mikroskeem.bytecodehackery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TestClass {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TestClass lel";
|
||||
}
|
||||
|
||||
public List<String> get(){
|
||||
List<String> r = new ArrayList<>();
|
||||
r.add("kek");
|
||||
r.add("kek2");
|
||||
return r;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package eu.mikroskeem.bytecodehackery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TestInterface {
|
||||
String a();
|
||||
List<String> b();
|
||||
}
|
Loading…
Reference in New Issue
Block a user