Java tutorial
/* * Copyright 2009-2012 Michael Dalton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jtaint; import java.util.List; import java.util.ArrayList; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; public class ClassLoaderAdapter extends ClassAdapter implements Opcodes { private String className; private static final List methodList; static { List l = new ArrayList(); l.add(new MethodDecl(ACC_PRIVATE, "defineClass0", "(Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;")); if (VmInfo.version() >= VmInfo.VERSION1_5) { l.add(new MethodDecl(ACC_PRIVATE, "defineClass1", "(Ljava/lang/String;[BIILjava/security/ProtectionDomain;Ljava/lang/String;)Ljava/lang/Class;")); l.add(new MethodDecl(ACC_PRIVATE, "defineClass2", "(Ljava/lang/String;Ljava/nio/ByteBuffer;IILjava/security/ProtectionDomain;Ljava/lang/String;)Ljava/lang/Class;")); } methodList = l; } public ClassLoaderAdapter(ClassVisitor cv) { super(cv); } public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { this.className = name; cv.visit(version, access, name, signature, superName, interfaces); } public MethodVisitor visitMethod(final int access, final String name, final String desc, String signature, String[] exceptions) { return new WrapDefineClassCallAdapter(cv.visitMethod(access, name, desc, signature, exceptions)); } private void addDefineClassWrapper(String methodName, String methodDesc) { MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, ByteCodeUtil.internalName("defineClass"), methodDesc, null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); /* This */ mv.visitVarInsn(ALOAD, 1); /* String name */ mv.visitVarInsn(ALOAD, 2); /* Buffer (byte[] or ByteBuffer */ mv.visitVarInsn(ILOAD, 3); /* offset */ mv.visitVarInsn(ILOAD, 4); /* len */ Type[] args = Type.getArgumentTypes(methodDesc); Type[] newArgs = new Type[3]; System.arraycopy(args, 1, newArgs, 0, 3); /* Buffer, offset, len */ String newDesc = Type.getMethodDescriptor(newArgs[0], newArgs); mv.visitMethodInsn(INVOKESTATIC, "jtaint/InstrumentationUtils", "instrument", newDesc); if ("Ljava/nio/ByteBuffer;".equals(newArgs[0].getDescriptor())) { mv.visitInsn(DUP); mv.visitMethodInsn(INVOKEVIRTUAL, "java/nio/ByteBuffer", "position", "()I"); mv.visitInsn(SWAP); mv.visitInsn(DUP_X1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/nio/ByteBuffer", "remaining", "()I"); } else { mv.visitInsn(DUP); mv.visitInsn(ARRAYLENGTH); mv.visitInsn(ICONST_0); mv.visitInsn(SWAP); } /* Now push all additional arguments */ int l = 5; for (int i = 4; i < args.length; l += args[i].getSize(), i++) mv.visitVarInsn(args[i].getOpcode(ILOAD), l); mv.visitMethodInsn(INVOKESPECIAL, className, methodName, methodDesc); mv.visitInsn(ARETURN); mv.visitMaxs(l, l); mv.visitEnd(); } private void addExportWrapper() { String desc = "(Ljava/lang/String;)Ljava/lang/Class;"; MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, ByteCodeUtil.internalName("findLoadedClass"), desc, null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, className, "findLoadedClass", desc); mv.visitInsn(ARETURN); mv.visitMaxs(2, 2); mv.visitEnd(); } public void visitEnd() { for (int i = 0; i < methodList.size(); i++) { MethodDecl m = (MethodDecl) methodList.get(i); addDefineClassWrapper(m.name(), m.type()); } addExportWrapper(); cv.visitEnd(); } private static class WrapDefineClassCallAdapter extends MethodAdapter { public WrapDefineClassCallAdapter(MethodVisitor mv) { super(mv); } public void visitMethodInsn(int opcode, String owner, String name, String desc) { if (opcode != INVOKESPECIAL || !"java/lang/ClassLoader".equals(owner) || !methodList.contains(new MethodDecl(ACC_PRIVATE, name, desc))) { mv.visitMethodInsn(opcode, owner, name, desc); return; } mv.visitMethodInsn(opcode, owner, ByteCodeUtil.internalName("defineClass"), desc); } } public static InstrumentationBuilder builder() { return Builder.getInstance(); } private static class Builder implements InstrumentationBuilder { private static final Builder b = new Builder(); public static InstrumentationBuilder getInstance() { return b; } public ClassVisitor build(ClassVisitor cv) { return new ClassLoaderAdapter(cv); } } }