Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ByteBuddy附加到本地正在运行的进程_Java_Byte Buddy_Bytecode Manipulation - Fatal编程技术网

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

Java ByteBuddy附加到本地正在运行的进程,java,byte-buddy,bytecode-manipulation,Java,Byte Buddy,Bytecode Manipulation,我正在尝试使用ByteBuddy连接到计算机上正在运行的进程。我希望在连接到正在运行的程序时,我的代理将导致重新加载加载的类,并显示Transformer的print语句 相反,当我停止所连接的正在运行的进程时,我看到一些来自Transformer的打印语句,用于一些JDK类 代码如下: import net.bytebuddy.ByteBuddy; import net.bytebuddy.agent.ByteBuddyAgent; import net.bytebuddy.dynamic.l

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

相反,当我停止所连接的正在运行的进程时,我看到一些来自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");
    }
}
导入net.bytebuddy.bytebuddy;
导入net.bytebuddy.agent.bytebuddy代理;
导入net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
导入net.bytebuddy.implementation.FixedValue;
导入java.io.*;
导入静态net.bytebuddy.matcher.ElementMatchers.named;
公盗{
公共静态void main(字符串[]args)抛出可丢弃的{

String pid=“86476”//仅添加一个转换器不会导致重新加载已加载的类。默认情况下,您的转换器只会看到新加载的类,因此您在退出时看到一些类的原因是这些类以前没有使用过,而是专门为关闭过程加载的

要重新转换类,首先必须使用注册,然后使用要转换的类调用

另外,我强烈反对将Java代理作为源代码字符串嵌入,需要将它们写入临时文件,调用编译器并最终创建jar文件。您可以轻松地将代理类集成到普通源代码中。然后,生成包含代理c的jar文件仅限lasses,您只需将已经存在的
.class
文件从应用程序的代码库复制到代理jar。对于简单的情况,您可以同时将应用程序jar文件设置为有效的代理jar文件,并且只需使用该文件,而无需任何额外的复制步骤


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

我建议您也添加您看到的错误。再现您的问题可能取决于各种因素,如您使用的JVM版本、操作系统等。仅源代码一个就可以,或者不可以。没有错误发生-我只是在连接到我的程序时没有看到代理的打印语句。我墨水问题的一部分是:在我的程序重新加载时已经加载的类吗?我认为答案是否定的。谢谢霍格尔的回应。这是一个编码挑战练习,而不是我会考虑做的IRL。再次感谢指导。