[投稿123] bytecode engineering
基本上這個作法原理同 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)
推
09/27 17:53, , 1F
09/27 17:53, 1F
推
09/27 22:19, , 2F
09/27 22:19, 2F
推
09/27 22:25, , 3F
09/27 22:25, 3F
推
09/28 23:10, , 4F
09/28 23:10, 4F