Skip to content

Instantly share code, notes, and snippets.

@Yamakaja
Last active September 7, 2017 16:46
Show Gist options
  • Save Yamakaja/241dfa48801504c6349d64640a07e793 to your computer and use it in GitHub Desktop.
Save Yamakaja/241dfa48801504c6349d64640a07e793 to your computer and use it in GitHub Desktop.
Custom String
package me.yamakaja.unsafe.classhacking;
import com.sun.management.HotSpotDiagnosticMXBean;
import sun.misc.Unsafe;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Created by Yamakaja on 9/6/17.
*/
public class ClassHacking {
public static final int MODIFIER_OFFSET = 152;
public static final int ACCESS_FLAG_OFFSET = 156;
public static void main(String[] args) {
Unsafe unsafe;
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
return;
}
System.out.println(ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class).getVMOption("UseCompressedOops").getValue());
long klassPointer = (unsafe.getInt("", 8L) & 0xFFFFFFFFL) << 3;
unsafe.putInt(klassPointer + MODIFIER_OFFSET, unsafe.getInt(klassPointer + MODIFIER_OFFSET) & ~Modifier.FINAL);
unsafe.putInt(klassPointer + ACCESS_FLAG_OFFSET, unsafe.getInt(klassPointer + ACCESS_FLAG_OFFSET) & ~Modifier.FINAL);
System.out.println(Modifier.toString(unsafe.getInt(klassPointer + MODIFIER_OFFSET)));
System.out.println(Modifier.toString(unsafe.getInt(klassPointer + ACCESS_FLAG_OFFSET)));
System.out.println(Modifier.toString(String.class.getModifiers()));
Class<?> clazz = new ASMClassLoader().load("me.yamakaja.unsafe.classhacking.SubStringImpl", StringGenerator.generateStringClass());
System.out.println("Loaded class!");
try {
String instance = (String) clazz.newInstance();
System.out.println("Instance created!");
System.out.println(instance);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
private static class ASMClassLoader extends ClassLoader {
public ASMClassLoader() {
super(ASMClassLoader.class.getClassLoader());
}
public Class<?> load(String name, byte[] data) {
return this.defineClass(name, data, 0, data.length);
}
}
}
package me.yamakaja.unsafe.classhacking;
import org.objectweb.asm.*;
import static org.objectweb.asm.Opcodes.*;
/**
* Created by Yamakaja on 9/6/17.
*/
public class StringGenerator {
public static byte[] generateStringClass() {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
cw.visit(52, ACC_PUBLIC + ACC_SUPER, "me/yamakaja/unsafe/classhacking/SubStringImpl", null, "java/lang/String", null);
cw.visitSource("SubString.java", null);
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(6, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "<init>", "()V", false);
mv.visitInsn(RETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "Lme/yamakaja/unsafe/classhacking/SubString;", null, l0, l1, 0);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(10, l0);
mv.visitLdcInsn("Linus Torvalds, a custom string!");
mv.visitInsn(ARETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "Lme/yamakaja/unsafe/classhacking/SubString;", null, l0, l1, 0);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "substringX", "(I)Ljava/lang/String;", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLdcInsn("Result of substring array!");
mv.visitInsn(ARETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "Lme/yamakaja/unsafe/classhacking/SubString;", null, l0, l1, 0);
mv.visitLocalVariable("start", "I", null, l0, l1, 1);
mv.visitMaxs(1, 2);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment