gpt4 book ai didi

java - ByteBuddy 附加到本地正在运行的进程

转载 作者:行者123 更新时间:2023-11-30 05:44:53 27 4
gpt4 key购买 nike

我正在尝试使用 ByteBuddy 附加到我的计算机上运行的正在运行的进程。我希望在附加到正在运行的程序时,我的代理将导致重新加载已加载的类并显示我的 Transformer 的打印语句。

相反,当我停止正在附加的正在运行的进程时,我会看到来自 Transformer 的一些 JDK 类的打印语句。

代码贴在下面:

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.implementation.FixedValue;

import java.io.*;

import static net.bytebuddy.matcher.ElementMatchers.named;

public class Thief {

public static void main(String[] args) throws Throwable {
String pid = "86476"; // <-- modify this to attach to any java process running on your computer
System.out.println(new Thief().guessSecurityCode(pid));
}

public String guessSecurityCode(final String pid) throws Throwable {
File jarFile = createAgent();
ByteBuddyAgent.attach(jarFile, pid);
return "0000";
}


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 Throwable {
writeFile("Agent.java", generateSimpleAgent());
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");
}
}

最佳答案

仅添加变压器不会导致重新加载已加载的类。默认情况下,您的变压器只会看到新加载的类,因此您在退出时看到一些类的原因是这些类之前没有使用过,而是专门为关闭过程加载的。

要重新转换类,您首先必须使用 addTransformer(yourTransformer, true)进行注册,然后调用 retransformClasses与您想要转换的类。注意 getAllLoadedClasses 的存在和 getInitiatedClasses(ClassLoader)

作为补充说明,我强烈反对采用将 Java 代理作为源代码字符串嵌入的方法,需要将它们写入临时文件、调用编译器并最终创建 jar 文件。您可以轻松地将代理类集成到普通源代码中。然后,要生成仅包含 Agent 类的 jar 文件,您只需将现有的 .class 文件从应用程序的代码库复制到 Agent jar 即可。对于简单的情况,您可以同时使应用程序 jar 文件成为有效的代理 jar 文件,然后直接使用它,无需任何额外的复制步骤。

此外,请记住,对于所有未更改的类,ClassFileTransformer 应始终返回 null。返回原始类文件字节在语义上是相同的,但调用方需要付出额外的努力才能发现您没有更改它。对于将为每个加载的类调用但通常只对少数几个类感兴趣(或者只想打印信息而不更改任何内容)的代码,此类性能问题很重要。

关于java - ByteBuddy 附加到本地正在运行的进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55029961/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com