是的,所以我想做的是获取运行时由 jvm 加载的每个加载类的类字节。仪器在这种情况下不起作用,因为我尝试加载的程序已经加密了他的类文件并使用自己的类加载器加载它。
这是我的尝试:https://gist.github.com/MalikDz/944cae9c168fa05fbd0a
这里的输出(错误):https://gist.github.com/MalikDz/fdf20df16b951d41cb78
非常感谢!
最佳答案
您可以使用 Java 代理来完成此技巧:
代理非常简单:它注册一个类转换器,可以访问字节码:
import java.lang.instrument.Instrumentation;
import java.lang.instrument.ClassFileTransformer;
public class ClassDumpAgent
{
/**
* This method is called before the application’s main-method is called, when
* this agent is specified to the Java VM.
**/
public static void premain(String agentArgs, Instrumentation inst)
{
ClassFileTransformer trans = new ClassDumpTransformer();
inst.addTransformer(trans);
}
}
所使用的 ClassFileTransformer 只是将带有字节码的字节数组转储到文件系统:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class ClassDumpTransformer implements ClassFileTransformer
{
private File rootFolder = new File("C:\\temp\\dump");
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException
{
File dumpFile = new File(rootFolder,className+".class");
dumpFile.getParentFile().mkdirs();
try {
FileOutputStream out = new FileOutputStream(dumpFile);
try {
out.write(classfileBuffer);
} finally {
out.close();
}
} catch (IOException e) {
throw new IllegalClassFormatException(e.getMessage());
}
return classfileBuffer;
}
}
要打包此类转储代理,您需要将这两个类打包并包含此代理的 MANIFEST.MF:
Manifest-Version: 1.0
PreMain-Class: ClassDumpAgent
要使用此代理运行应用程序,请使用如下命令行:
java -javaagent:cldumpagent.jar MyApplication
关于解决方案的一些评论:
- 这些类被转储到硬编码文件夹 (C:\TEMP\DUMP) 中,您可以 可能想改变这一点。
- 转换器将转储所有类,包括 JDK 运行时。您可能想要过滤转储哪些包。
- 小心逆向工程,在某些国家/地区这可能被视为非法。
巴里
关于java - 重写类加载器以获取每个加载的类字节和名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27115371/