Created
September 8, 2015 09:25
-
-
Save jsyeo/87ec523a58f860952f75 to your computer and use it in GitHub Desktop.
ASM and Reflection
This file contains 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
/* | |
* © Copyright 2015 - SourceClear Inc | |
*/ | |
import com.codepoetics.protonpack.StreamUtils; | |
import org.objectweb.asm.ClassReader; | |
import org.objectweb.asm.Opcodes; | |
import org.objectweb.asm.Type; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.jar.JarEntry; | |
import java.util.jar.JarInputStream; | |
import java.util.stream.Stream; | |
/** | |
* | |
*/ | |
public class Main { | |
public static void main(String[] args) throws IOException { | |
InputStream is = Main.class.getClassLoader().getResourceAsStream("dotclass.jar"); | |
List<Type> reflectedClasses = new ArrayList<>(); | |
List<String> reflectedMethods = new ArrayList<>(); | |
StreamUtils.takeUntil(jarToClassReaders(is), x -> x == null). | |
forEach(cr -> cr.accept(new ReflectionClassVisitor(Opcodes.ASM5, reflectedClasses, reflectedMethods), Opcodes.ASM5)); | |
is = Main.class.getClassLoader().getResourceAsStream("classForName.jar"); | |
StreamUtils.takeUntil(jarToClassReaders(is), x -> x == null). | |
forEach(cr -> cr.accept(new ReflectionClassVisitor(Opcodes.ASM5, reflectedClasses, reflectedMethods), Opcodes.ASM5)); | |
System.out.println(reflectedClasses); | |
System.out.println(reflectedMethods); | |
} | |
static Stream<ClassReader> jarToClassReaders(InputStream jar) throws IOException { | |
JarInputStream jis = new JarInputStream(jar); | |
return Stream.generate(() -> { | |
try { | |
JarEntry jarEntry = jis.getNextJarEntry(); | |
if (jarEntry != null && | |
!jarEntry.isDirectory() && | |
jarEntry.getName().toLowerCase().endsWith(".class")) { | |
ClassReader cr = new ClassReader(jis); | |
return cr; | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
return null; | |
}); | |
} | |
} |
This file contains 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
/* | |
* © Copyright 2015 - SourceClear Inc | |
*/ | |
import org.objectweb.asm.ClassVisitor; | |
import org.objectweb.asm.MethodVisitor; | |
import org.objectweb.asm.Type; | |
import java.util.Collection; | |
/** | |
* | |
*/ | |
public class ReflectionClassVisitor extends ClassVisitor { | |
///////////////////////////// Class Attributes \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
////////////////////////////// Class Methods \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
//////////////////////////////// Attributes \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
private final int version; | |
private final Collection<Type> reflectedClasses; | |
private final Collection<String> reflectedMethods; | |
/////////////////////////////// Constructors \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
public ReflectionClassVisitor(int version, Collection<Type> reflectedClasses, Collection<String> reflectedMethods) { | |
super(version); | |
this.version = version; | |
this.reflectedClasses = reflectedClasses; | |
this.reflectedMethods = reflectedMethods; | |
} | |
////////////////////////////////// Methods \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
//------------------------ Implements: | |
//------------------------ Overrides: | |
@Override | |
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { | |
return new ReflectionMethodVisitor(version, reflectedClasses, reflectedMethods); | |
} | |
//---------------------------- Abstract Methods ----------------------------- | |
//---------------------------- Utility Methods ------------------------------ | |
//---------------------------- Property Methods ----------------------------- | |
} |
This file contains 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
/* | |
* © Copyright 2015 - SourceClear Inc | |
*/ | |
import org.objectweb.asm.MethodVisitor; | |
import org.objectweb.asm.Opcodes; | |
import org.objectweb.asm.Type; | |
import java.util.Collection; | |
import java.util.regex.Pattern; | |
/** | |
* | |
*/ | |
public class ReflectionMethodVisitor extends MethodVisitor { | |
///////////////////////////// Class Attributes \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
////////////////////////////// Class Methods \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
//////////////////////////////// Attributes \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
private final Collection<Type> reflectedClasses; | |
private final Collection<String> reflectedMethods; | |
private String currentLoadedString; | |
/////////////////////////////// Constructors \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
public ReflectionMethodVisitor(int version, Collection<Type> reflectedClasses, Collection<String> reflectedMethods) { | |
super(version); | |
this.reflectedClasses = reflectedClasses; | |
this.reflectedMethods = reflectedMethods; | |
} | |
////////////////////////////////// Methods \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ | |
//------------------------ Implements: | |
//------------------------ Overrides: | |
@Override | |
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { | |
if (opcode == Opcodes.INVOKEVIRTUAL && | |
owner.equals("java/lang/Class") && | |
name.equals("getMethod") && | |
desc.equals("(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;")) { | |
reflectedMethods.add(currentLoadedString); | |
} else if (opcode == Opcodes.INVOKEVIRTUAL && | |
owner.equals("java/lang/reflect/Method") && | |
name.equals("invoke") && | |
desc.equals("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")) { | |
System.out.println("invoke called!"); | |
} else if (opcode == Opcodes.INVOKESTATIC && | |
owner.equals("java/lang/Class") && | |
name.equals("forName") && | |
desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) { | |
reflectedClasses.add(Type.getObjectType(classNameToInternalName(currentLoadedString))); | |
} | |
} | |
private String classNameToInternalName(String className) { | |
return className.replaceAll(Pattern.quote("."), "/"); | |
} | |
@Override | |
public void visitLdcInsn(Object arg) { | |
if (arg instanceof Type) { | |
Type type = (Type) arg; | |
if (type.getSort() == Type.OBJECT) { | |
reflectedClasses.add(type); | |
} | |
} else if (arg instanceof String) { | |
currentLoadedString = (String) arg; | |
} | |
} | |
//---------------------------- Abstract Methods ----------------------------- | |
//---------------------------- Utility Methods ------------------------------ | |
//---------------------------- Property Methods ----------------------------- | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment