作者sbrhsieh (十年一梦)
看板java
标题[投稿123] bytecode engineering
时间Fri Sep 27 17:08:51 2013
基本上这个作法原理同 bleed1979,只是不必手动去修改(与修改 bytecode 细节上
不同)。
为了简化程式码,没有限定 target class,所以基本上不限定 class Output123,
执行任何 class 都会输出 123(不论它原本有没有 main method),只要这个 class
是可以被 transform 的。
1. 至 ASM 官网下载 asm 4.0 版。
http://asm.ow2.org/download/index.html
2. 编译公告中的 Output123.java
3. 编译文末的程式码并打包成 agent_out123.jar,此 jar 中的 manifest 内容:
Manifest-Version: 1.0
Premain-Class: cc.ptt.java.Output123Only
4. 执行 class Output123
令 CP 包含 asm-4.0.jar 的路径与 Output123.class 所在档案夹
令 AGENT 为 agent_out123.jar 的完整路径
java -cp %CP% -javaagent:%AGENT% Output123
or
java -cp $CP -javaagent:$AGENT Output123
***********************************************************************
package cc.ptt.java;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class Output123Only implements ClassFileTransformer {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new Output123Only(), true);
}
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
ClassReader reader = new ClassReader(classfileBuffer);
ClassWriter writer = new ClassWriter(reader,
ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
MainMethodInjector injector = new MainMethodInjector(writer);
reader.accept(injector, 0);
return writer.toByteArray();
}
static class MainMethodInjector extends ClassVisitor {
private ClassWriter writer;
MainMethodInjector(ClassWriter writer) {
super(Opcodes.ASM4, writer);
this.writer = writer;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
if (name.equals("main") &&
desc.equals("([Ljava/lang/String;)V")) {
// found the 'main' method, skip it
return null;
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
@Override
public void visitEnd() {
injectMainMethod();
super.visitEnd();
}
protected void injectMainMethod() {
MethodVisitor method = writer.visitMethod(
Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
"main",
"([Ljava/lang/String;)V",
null,
null);
method.visitCode();
method.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/System", "out", "Ljava/io/PrintStream;");
method.visitLdcInsn("123");
method.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/io/PrintStream", "println", "(Ljava/lang/String;)V");
method.visitInsn(Opcodes.RETURN);
method.visitMaxs(0, 0);
method.visitEnd();
}
}
}
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 218.173.234.148
※ 编辑: sbrhsieh 来自: 218.173.234.148 (09/27 17:09)
※ 编辑: sbrhsieh 来自: 218.173.234.148 (09/27 17:11)
1F:推 PsMonkey:好可怕,没一个 class 是看过的 Orz 09/27 17:53
2F:推 luoqr:用cglib 算同一招吗 XD 09/27 22:19
3F:推 PsMonkey:刚刚看了一下,理论上应该算同一招 XDXD 09/27 22:25
4F:推 tomoyaken14:好强大... 09/28 23:10