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
|
# 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
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