Java 解析Jar文件并查找类之间的关系?
如何检测jar文件中的类是否扩展了其他类,或者是否有对其他类对象的方法调用,或者是否创建了其他类对象? 然后系统确定哪个类扩展哪个类,哪个类从哪个类调用方法 我正在使用Classparser来解析jar。以下是我的部分代码:Java 解析Jar文件并查找类之间的关系?,java,reverse-engineering,reverse,bcel,Java,Reverse Engineering,Reverse,Bcel,如何检测jar文件中的类是否扩展了其他类,或者是否有对其他类对象的方法调用,或者是否创建了其他类对象? 然后系统确定哪个类扩展哪个类,哪个类从哪个类调用方法 我正在使用Classparser来解析jar。以下是我的部分代码: String jarfile = "C:\\Users\\OOOO\\Desktop\\Sample.Jar"; jar = new JarFile(jarfile); Enumeration<JarEntry>
String jarfile = "C:\\Users\\OOOO\\Desktop\\Sample.Jar";
jar = new JarFile(jarfile);
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (!entry.getName().endsWith(".class")) {
continue;
}
ClassParser parser = new ClassParser(jarfile, entry.getName());
JavaClass javaClass = parser.parse();
String jarfile=“C:\\Users\\ooooo\\Desktop\\Sample.Jar”;
jar=新的JarFile(JarFile);
枚举条目=jar.entries();
while(entries.hasMoreElements()){
JarEntry=entries.nextElement();
如果(!entry.getName().endsWith(“.class”)){
继续;
}
ClassParser=newClassParser(jarfile,entry.getName());
JavaClass=parser.parse();
有人投票把这个问题说成“太广”了。我不确定这是否是一个恰当的原因,但它可能是,因为我们可以考虑这个问题(这是一个后续的问题),只是要求别人为你做一些工作。
但是,要回答如何使用BCEL检测单个JAR文件中类之间的引用这一基本问题,请执行以下操作:
您可以从JarFile
获取JavaClass
对象列表。对于每个JavaClass
对象,您可以检查方法
对象及其指令列表
。在这些指令中,您可以选择调用指令
对象,并进一步检查它们以找到ut在那里实际调用了哪个类上的哪个方法
下面的程序打开一个JAR文件(出于明显的原因,它是bcel-5.2.JAR
-您无论如何都需要它…)并按上述方式处理。对于JAR文件的每个JavaClass
,它创建一个从所有引用的JavaClass
对象到在这些类上调用的方法的列表的映射,并相应地打印信息:
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.apache.bcel.classfile.ClassFormatException;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;
public class BCELRelationships
{
public static void main(String[] args) throws Exception
{
JarFile jarFile = null;
try
{
String jarName = "bcel-5.2.jar";
jarFile = new JarFile(jarName);
findReferences(jarName, jarFile);
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
if (jarFile != null)
{
try
{
jarFile.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
private static void findReferences(String jarName, JarFile jarFile)
throws ClassFormatException, IOException, ClassNotFoundException
{
Map<String, JavaClass> javaClasses =
collectJavaClasses(jarName, jarFile);
for (JavaClass javaClass : javaClasses.values())
{
System.out.println("Class "+javaClass.getClassName());
Map<JavaClass, Set<Method>> references =
computeReferences(javaClass, javaClasses);
for (Entry<JavaClass, Set<Method>> entry : references.entrySet())
{
JavaClass referencedJavaClass = entry.getKey();
Set<Method> methods = entry.getValue();
System.out.println(
" is referencing class "+
referencedJavaClass.getClassName()+" by calling");
for (Method method : methods)
{
System.out.println(
" "+method.getName()+" with arguments "+
Arrays.toString(method.getArgumentTypes()));
}
}
}
}
private static Map<String, JavaClass> collectJavaClasses(
String jarName, JarFile jarFile)
throws ClassFormatException, IOException
{
Map<String, JavaClass> javaClasses =
new LinkedHashMap<String, JavaClass>();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements())
{
JarEntry entry = entries.nextElement();
if (!entry.getName().endsWith(".class"))
{
continue;
}
ClassParser parser =
new ClassParser(jarName, entry.getName());
JavaClass javaClass = parser.parse();
javaClasses.put(javaClass.getClassName(), javaClass);
}
return javaClasses;
}
public static Map<JavaClass, Set<Method>> computeReferences(
JavaClass javaClass, Map<String, JavaClass> knownJavaClasses)
throws ClassNotFoundException
{
Map<JavaClass, Set<Method>> references =
new LinkedHashMap<JavaClass, Set<Method>>();
ConstantPool cp = javaClass.getConstantPool();
ConstantPoolGen cpg = new ConstantPoolGen(cp);
for (Method m : javaClass.getMethods())
{
String fullClassName = javaClass.getClassName();
String className =
fullClassName.substring(0, fullClassName.length()-6);
MethodGen mg = new MethodGen(m, className, cpg);
InstructionList il = mg.getInstructionList();
if (il == null)
{
continue;
}
InstructionHandle[] ihs = il.getInstructionHandles();
for(int i=0; i < ihs.length; i++)
{
InstructionHandle ih = ihs[i];
Instruction instruction = ih.getInstruction();
if (!(instruction instanceof InvokeInstruction))
{
continue;
}
InvokeInstruction ii = (InvokeInstruction)instruction;
ReferenceType referenceType = ii.getReferenceType(cpg);
if (!(referenceType instanceof ObjectType))
{
continue;
}
ObjectType objectType = (ObjectType)referenceType;
String referencedClassName = objectType.getClassName();
JavaClass referencedJavaClass =
knownJavaClasses.get(referencedClassName);
if (referencedJavaClass == null)
{
continue;
}
String methodName = ii.getMethodName(cpg);
Type[] argumentTypes = ii.getArgumentTypes(cpg);
Method method =
findMethod(referencedJavaClass, methodName, argumentTypes);
Set<Method> methods = references.get(referencedJavaClass);
if (methods == null)
{
methods = new LinkedHashSet<Method>();
references.put(referencedJavaClass, methods);
}
methods.add(method);
}
}
return references;
}
private static Method findMethod(
JavaClass javaClass, String methodName, Type argumentTypes[])
throws ClassNotFoundException
{
for (Method method : javaClass.getMethods())
{
if (method.getName().equals(methodName))
{
if (Arrays.equals(argumentTypes, method.getArgumentTypes()))
{
return method;
}
}
}
for (JavaClass superClass : javaClass.getSuperClasses())
{
Method method = findMethod(superClass, methodName, argumentTypes);
if (method != null)
{
return method;
}
}
return null;
}
}
对toString
的调用实际上发生在MyClass
的实例上。但是由于多态性,它只能被识别为对“某些对象
上的此方法的调用.免责声明:严格来说,这不是对您的问题的回答,因为它使用not but。不过,您可能会发现我的经验和代码很有用
几年前,我写过e Maven插件(我称之为插件)就是为了这个目的——分析JARs文件中不必要或不需要的依赖关系
请看这个问题:
我也很喜欢它
虽然这个插件很好用,但我从来没有发布过。现在我只是想让其他人可以访问它
您询问如何解析JAR以分析.class
文件中的代码
:
final JarFile artifactJarFile=新JarFile(artifactFile);
最终枚举jarEntries=artifactJarFile
.entries();
while(jarEntries.hasMoreElements()){
final JarEntry JarEntry=jarEntries.nextElement();
if(jarEntry.getName().endsWith(“.class”)){
InputStream=null;
CtClass CtClass=null;
试一试{
is=artifactJarFile.getInputStream(jarEntry);
ctClass=classPool.makeClass(is);
}捕获(IOException ioex1){
抛出新的MojoExecutionException异常(
“无法从JAR条目[]加载类”
+artifactFile.getAbsolutePath()
+“/”+jarEntry.getName()+“].”;
}最后{
试一试{
如果(is!=null)
is.close();
}捕获(忽略IOException){
//忽略
}
}
// ...
}
}
查找引用的类:
final Collection referencedClassNames=ctClass.getRefClasses();
总的来说,我使用Javassist完成类似任务的经验是非常积极的。我希望这能有所帮助
void call() {
MyClass m = new MyClass();
callToString(m);
}
void callToString(Object object) {
object.toString();
}
final JarFile artifactJarFile = new JarFile(artifactFile);
final Enumeration<JarEntry> jarEntries = artifactJarFile
.entries();
while (jarEntries.hasMoreElements()) {
final JarEntry jarEntry = jarEntries.nextElement();
if (jarEntry.getName().endsWith(".class")) {
InputStream is = null;
CtClass ctClass = null;
try {
is = artifactJarFile.getInputStream(jarEntry);
ctClass = classPool.makeClass(is);
} catch (IOException ioex1) {
throw new MojoExecutionException(
"Could not load class from JAR entry ["
+ artifactFile.getAbsolutePath()
+ "/" + jarEntry.getName() + "].");
} finally {
try {
if (is != null)
is.close();
} catch (IOException ignored) {
// Ignore
}
}
// ...
}
}
final Collection<String> referencedClassNames = ctClass.getRefClasses();