Initial commit

This commit is contained in:
Mark Vainomaa 2016-12-15 07:45:09 +02:00
parent d2fc40f0a7
commit 1a965bd4e9
6 changed files with 272 additions and 0 deletions

2
.gitignore vendored
View File

@ -12,3 +12,5 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid* hs_err_pid*
.idea/
.iml

104
pom.xml Normal file
View 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>

View File

@ -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;
}
}
}
}

View 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();
}
}

View 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;
}
}

View File

@ -0,0 +1,8 @@
package eu.mikroskeem.bytecodehackery;
import java.util.List;
public interface TestInterface {
String a();
List<String> b();
}