Last active
September 7, 2017 16:46
-
-
Save Yamakaja/241dfa48801504c6349d64640a07e793 to your computer and use it in GitHub Desktop.
Custom String
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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