动态附加Java代理不起作用
我为编码挑战编写了以下代码。该程序的目的是将程序启动后附加到另一个Java过程并加载仪器引擎。这通常是在Java中通过在您的代理JAR文件中实现AgentMain方法来完成的。我在下面的代码中生成了所有这些内容:
在运行玩具程序的JVM上看到错误,并且线索是由于某种原因认为代理类文件名是代理$ 1。我评论了我对字节带纸的使用情况,只是尝试使用内置库加载代理文件,但仍然失败。
heartbeat : 373 pid = 21992
heartbeat : 374 pid = 21992
Exception in thread "Attach Listener" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:491)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:513)
Caused by: java.lang.NoClassDefFoundError: Agent$1
at Agent.agentmain(Agent.java:8)
... 6 more
Caused by: java.lang.ClassNotFoundException: Agent$1
... 7 more
Agent failed to start!
import com.sun.tools.attach.VirtualMachine;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.implementation.FixedValue;
import java.io.*;
import java.lang.instrument.Instrumentation;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class Thief {
public static void main(String[] args) throws Exception {
Thief thief = new Thief();
VirtualMachine jvm = VirtualMachine.attach("21992");
File agentFile = new File("agent.jar");
jvm.loadAgent(agentFile.getAbsolutePath());
//thief.guessSecurityCode("24472");
}
public String guessSecurityCode(final String pid) throws Exception {
File jarFile = createAgent();
ByteBuddyAgent.attach(jarFile, pid);
return "0000";
}
private static String generateSimpleAgent2() {
return "import java.lang.instrument.ClassFileTransformer;" + "\n" +
"import java.lang.instrument.Instrumentation;" + "\n" +
"import java.security.ProtectionDomain;" + "\n" +
"\n\n" +
"public class Agent {" +"\n" +
" public static void agentmain(String argument, Instrumentation inst) {" +"\n" +
" }" +"\n" +
"}" +"\n";
}
private static String generateSimpleAgent() {
return "import java.lang.instrument.ClassFileTransformer;" + "\n" +
"import java.lang.instrument.Instrumentation;" + "\n" +
"import java.security.ProtectionDomain;" + "\n" +
"\n\n" +
"public class Agent {" +"\n" +
" public static void agentmain(String argument, Instrumentation inst) {" +"\n" +
" inst.addTransformer(new ClassFileTransformer() {" +"\n" +
" @Override" +"\n" +
" public byte[] transform(" +"\n" +
" ClassLoader loader," +"\n" +
" String className," +"\n" +
" Class<?> classBeingRedefined," +"\n" +
" ProtectionDomain protectionDomain," +"\n" +
" byte[] classFileBuffer) {" +"\n" +
" System.out.println(\"transform on : \" +className);" +"\n" +
" return classFileBuffer;" +"\n" +
" }" +"\n" +
" });" +"\n" +
" }" +"\n" +
"}" +"\n";
}
private static String generateAgentManifest() {
return String.join("\n", "Agent-Class: Agent",
"Can-Retransform-Classes: true",
"Can-Redefine-Classes: true",
"Premain-Class: Agent"
);
}
private static String generateAgentManifest2() {
return String.join("\n",
"Manifest-Version: 1.0",
"Agent-Class: Agent",
"Permissions: all-permissions"
);
}
private static String generateTransformer() {
return String.join("\n",
"import java.lang.instrument.ClassFileTransformer;",
"import java.security.ProtectionDomain;",
"import java.util.Arrays;",
"public class Transformer implements ClassFileTransformer {",
" public byte[] transform(ClassLoader loader, String className, Class<?> cls, ProtectionDomain dom, byte[] buf) {",
" return null;",
" }",
"}"
);
}
private static void writeFile(String path, String data) throws IOException {
final PrintWriter out = new PrintWriter(path);
out.print(data);
out.close();
}
private static void runCommand(String cmd) throws Exception {
System.out.println("[commmand] " + cmd);
String s;
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((s = out.readLine()) != null) {
System.out.println("[out] " + s);
}
out = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((s = out.readLine()) != null) {
System.out.println("[err] " + s);
}
p.waitFor();
System.out.println("[exit status] " + p.exitValue());
p.destroy();
}
private static File createAgent() throws Exception {
writeFile("Agent.java", generateSimpleAgent2());
writeFile("Transformer.java", generateTransformer());
writeFile("manifest.mf", generateAgentManifest2());
runCommand("javac Agent.java Transformer.java");
runCommand("jar -cfm agent.jar manifest.mf Agent.class Transformer.class");
return new File("agent.jar");
}
}
有人知道我在这里做错了吗?
I wrote the following code for a coding challenge. The purpose of the program is to attach to another java process and load an instrumentation engine after the program has been started. This is usually done in Java by implementing an agentmain method in your agent jar file. I generate this all in the code below:
The error is seen on the JVM running the toy program and the clue is it thinks the Agent class file name is Agent$1 for some reason. I comment out my usage of ByteBuddy and just try to load the agent file using the built in libraries and it still fails.
heartbeat : 373 pid = 21992
heartbeat : 374 pid = 21992
Exception in thread "Attach Listener" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:491)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:513)
Caused by: java.lang.NoClassDefFoundError: Agent$1
at Agent.agentmain(Agent.java:8)
... 6 more
Caused by: java.lang.ClassNotFoundException: Agent$1
... 7 more
Agent failed to start!
import com.sun.tools.attach.VirtualMachine;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.implementation.FixedValue;
import java.io.*;
import java.lang.instrument.Instrumentation;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class Thief {
public static void main(String[] args) throws Exception {
Thief thief = new Thief();
VirtualMachine jvm = VirtualMachine.attach("21992");
File agentFile = new File("agent.jar");
jvm.loadAgent(agentFile.getAbsolutePath());
//thief.guessSecurityCode("24472");
}
public String guessSecurityCode(final String pid) throws Exception {
File jarFile = createAgent();
ByteBuddyAgent.attach(jarFile, pid);
return "0000";
}
private static String generateSimpleAgent2() {
return "import java.lang.instrument.ClassFileTransformer;" + "\n" +
"import java.lang.instrument.Instrumentation;" + "\n" +
"import java.security.ProtectionDomain;" + "\n" +
"\n\n" +
"public class Agent {" +"\n" +
" public static void agentmain(String argument, Instrumentation inst) {" +"\n" +
" }" +"\n" +
"}" +"\n";
}
private static String generateSimpleAgent() {
return "import java.lang.instrument.ClassFileTransformer;" + "\n" +
"import java.lang.instrument.Instrumentation;" + "\n" +
"import java.security.ProtectionDomain;" + "\n" +
"\n\n" +
"public class Agent {" +"\n" +
" public static void agentmain(String argument, Instrumentation inst) {" +"\n" +
" inst.addTransformer(new ClassFileTransformer() {" +"\n" +
" @Override" +"\n" +
" public byte[] transform(" +"\n" +
" ClassLoader loader," +"\n" +
" String className," +"\n" +
" Class<?> classBeingRedefined," +"\n" +
" ProtectionDomain protectionDomain," +"\n" +
" byte[] classFileBuffer) {" +"\n" +
" System.out.println(\"transform on : \" +className);" +"\n" +
" return classFileBuffer;" +"\n" +
" }" +"\n" +
" });" +"\n" +
" }" +"\n" +
"}" +"\n";
}
private static String generateAgentManifest() {
return String.join("\n", "Agent-Class: Agent",
"Can-Retransform-Classes: true",
"Can-Redefine-Classes: true",
"Premain-Class: Agent"
);
}
private static String generateAgentManifest2() {
return String.join("\n",
"Manifest-Version: 1.0",
"Agent-Class: Agent",
"Permissions: all-permissions"
);
}
private static String generateTransformer() {
return String.join("\n",
"import java.lang.instrument.ClassFileTransformer;",
"import java.security.ProtectionDomain;",
"import java.util.Arrays;",
"public class Transformer implements ClassFileTransformer {",
" public byte[] transform(ClassLoader loader, String className, Class<?> cls, ProtectionDomain dom, byte[] buf) {",
" return null;",
" }",
"}"
);
}
private static void writeFile(String path, String data) throws IOException {
final PrintWriter out = new PrintWriter(path);
out.print(data);
out.close();
}
private static void runCommand(String cmd) throws Exception {
System.out.println("[commmand] " + cmd);
String s;
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((s = out.readLine()) != null) {
System.out.println("[out] " + s);
}
out = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((s = out.readLine()) != null) {
System.out.println("[err] " + s);
}
p.waitFor();
System.out.println("[exit status] " + p.exitValue());
p.destroy();
}
private static File createAgent() throws Exception {
writeFile("Agent.java", generateSimpleAgent2());
writeFile("Transformer.java", generateTransformer());
writeFile("manifest.mf", generateAgentManifest2());
runCommand("javac Agent.java Transformer.java");
runCommand("jar -cfm agent.jar manifest.mf Agent.class Transformer.class");
return new File("agent.jar");
}
}
Does anyone know what I'm doing wrong here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用
generatesImpleagent2()
,它起作用。它不会以相同的方式失败,就像您在 ewramner 的答案下的评论中所说的那样。那应该给你一个线索。此外,如果您只是阅读异常并相信它告诉您的内容,那么您就会知道该怎么做。再次:ie,
generatesImpleagent()
创建两个类文件,一个用于代理本身,一个用于匿名类。这正是 javac 有望做的。只需检查输出目录,您就会看到它。只需将丢失的类文件添加到JAR上并感到高兴:现在,具有匿名变压器类的代理也可以工作。我测试了它。
With
generateSimpleAgent2()
, it works. It does not fail the same way, like you said in your comment under ewramner's answer. That should give you a clue. Furthermore, if you simply read the exception and believe what it is telling you, you know what to do. Again:I.e.,
generateSimpleAgent()
creates two class files, one for the agent itself and one for its anonymous class. That is exactly what javac is expected to do. Just inspect the output directory, and you will see it. Simply add the missing class file to the JAR and be happy:Now the agent with the anonymous transformer class also works. I tested it.
代理$ 1
是一个匿名类,因此它必须是您在这里创建的一个:关于为什么找不到它以及如何修复它我不知道,也许您可以生成一个真实的名字命名在引用之前,上课?
Agent$1
is an anonymous class, so it must be the one you create here:As for why it is not found and how you can fix it I don't know, perhaps you can generate a real named class for it before it is referenced?