我有一个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;
}
答案 0 :(得分: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
的答案答案 1 :(得分: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文件目录特别大,可能需要一段时间才能找到。我已经将它与数百个罐子一起使用了,它很慢但很有效。
答案 2 :(得分:1)
使用java.net.URLClassLoader
的loadClass()
方法。
答案 3 :(得分:1)
EJP的提示是一个参考点。这是一个真实的案例,你有非本地网址,所以创建一个类加载器,加载一个类,并获得它的字节码是更正确的。也许是这样的:
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();
答案 4 :(得分: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