1

我有一个 jar 文件的 URL 列表,我也有整个路径类名com.mycompany.myproject.Test,我如何在这些 jar 文件中搜索并获取其中的 .class 文件?我用它来反编译。

String classname = "com.mycompany.myproject.Test";
URI uri = Tool.searchClass(jarList, classname);
// decompile .class
...

有这样的示例代码吗?

补充:Shell脚本很好,但是java代码中有没有办法可以完成这项工作?

补充:我刚刚写了一个静态方法java.util.jar.JarFile来处理这个,希望这对其他人有帮助

以下代码经过测试并且可以正常工作:

/**
 * Search the class by classname specified in jarFile, if found and destFolder specified
 * Copy the .class file into destFolder with whole path.
 * @param classname
 * @param jarFile
 * @param destFolder
 * @return
 */
public static File searchCompressedFile(String classname, File jarFile, String destFolder) {
    try {
        // change classname "." to "/"
        if(classname.contains(".")){
            classname = classname.replace(".", "/");
        }

        JarFile jarF = new JarFile(jarFile);
        Enumeration<JarEntry> jarEntries = jarF.entries();

        while (jarEntries.hasMoreElements()) {
            JarEntry jarEntry = jarEntries.nextElement();
            if (jarEntry.getName().indexOf(classname) >= 0) {
                String filePath = jarFile.getAbsolutePath();
                System.out.println(classname + " is in " + filePath + "--" + jarEntry.getName());

                if (destFolder != null && !"".equals(destFolder)) {
                    // Make folder if dest folder not existed.
                    File destF = new File(destFolder);
                    if (!destF.exists()) {
                        destF.mkdirs();
                    }

                    File f = new File(destFolder + File.separator + jarEntry.getName());
                    if(!f.getParentFile().exists()){
                        f.getParentFile().mkdirs();
                    }
                    InputStream is = jarF.getInputStream(jarEntry);
                    FileOutputStream fos = new java.io.FileOutputStream(f);
                    while (is.available() > 0) {
                        fos.write(is.read());
                    }
                    fos.close();
                    is.close();

                    return f;
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    System.out.println("Class not found in jar");
    return null;
}
4

5 回答 5

1

jar 文件实际上是一个.zip. 可以使用java.util.zip.ZipInputStream如下方式进行搜索:

import java.util.zip.ZipInputStream;
import java.util.zip.ZipEntry;

public class Test {

    public static void main(String args[]){ 
        try{
                CodeSource src = Main.class.getProtectionDomain().getCodeSource();
                if( src != null ) {
                  URL jar = src.getLocation();  
                  ZipInputStream zip = new ZipInputStream(jar.openStream());                      
                  ZipEntry zipEntry = null;
                  while((zipEntry = zip.getNextEntry()) != null){
                    String entryName = zipEntry.getName();
                    // do what you want
                  }
                }
        }
        catch (Exception e){            
        }       
    }   
}

我还找到了另一个使用JarFile类的答案

于 2012-07-02T04:15:10.670 回答
1

我的 ~/bin 文件夹中有这个名为 findClass.sh 的 shell 脚本:

echo "Finding $2 in $1."
for jar in `find $1 -name \*.jar`
do
   echo -n "."
   for class in `jar tf $jar`
   do
     if [[ "`echo $class | grep $2`" = ""  ]] 
     then
        grep test /dev/null 
     else 
        echo -e "\n$jar : $class"
     fi
     done

 done

如果您的 .jar 文件目录特别大,可能需要一段时间才能找到。我已经将它与数百个罐子一起使用,它很慢,但很有效。

于 2012-07-02T04:16:35.173 回答
1

使用 的loadClass()方法java.net.URLClassLoader

于 2012-07-02T04:29:53.347 回答
1

EJP 的尖端是一个参考点。这是一个你有非本地 url 的真实案例,所以创建一个类加载器、加载一个类并获取它的字节码更正确。也许以某种方式是这样的:

    URLClassLoader classLoader = new URLClassLoader(list.toArray(new URL[0]));
    Class<?> clazz = classLoader.loadClass(path);
    File tmp = new File(System.getProperty("java.io.tmpdir"), path.replace(".", "_") + ".class");
    FileChannel tmpChannel = new FileOutputStream(tmp).getChannel();
    InputStream is = clazz.getResourceAsStream("/" + path.replace(".", "/") + ".class");
    tmpChannel.transferFrom(Channels.newChannel(is), 0, Long.MAX_VALUE);
    URI uri = tmp.toURI();
于 2012-07-02T05:30:08.603 回答
0

我正在使用简单的 bash 脚本进行反编译。

#!/bin/bash

if [ -z "$1" ] ; then
    echo "There is no argument please enter jar file name"
    exit -1
fi

FNAME=$1
FNAME_SHORT=`basename $1`
DNAME=${FNAME_SHORT/.*/}_jar

CLASS_DIR=${DNAME}/cls
SRC_DIR=${DNAME}/java

mkdir -p $CLASS_DIR
mkdir -p $SRC_DIR
echo "Unpacking ${FNAME}.."
( cd ${CLASS_DIR} ; unzip -o ../../${FNAME} ) > /dev/null 2>&1 || exit -1
CLASSES="$(cd $DNAME ; find cls -name "*.class" -print)"
if [ ! -z "$CLASSES" ] ; then
    for C in $CLASSES ; do
        CNAME=${C/.*/}
        CNAME=${CNAME#cls/}
        JFILE=$SRC_DIR/${CNAME}.java
        CNAME=${CNAME//\//.}
        if [ -f $JFILE ] ; then
            echo "Skipping $C..."
            continue
        fi
        echo -n "Decompile $C to $DNAME..."
        jad -o -f -d $DNAME/java -lnc -s .java -r $DNAME/$C > /dev/null 2>&1
        if [ $? != 0 ] ; then
            echo "FAILED"
            javap -c -classpath $CLASS_DIR ${CNAME} > $JFILE
        else
            echo "OK"
        fi
    done
fi
于 2012-07-02T04:19:48.093 回答