Java 如何在jar文件中动态搜索.class文件?
我有一个jar文件的URL列表,还有一个完整的路径类名,比如Java 如何在jar文件中动态搜索.class文件?,java,bytecode,Java,Bytecode,我有一个jar文件的URL列表,还有一个完整的路径类名,比如com.mycompany.myproject.Test,如何在这些jar文件中搜索并在其中获取.class文件?我用它来反编译 String classname = "com.mycompany.myproject.Test"; URI uri = Tool.searchClass(jarList, classname); // decompile .class ... 有这样的示例代码吗 添加: Shell脚本很好,但是java代
com.mycompany.myproject.Test
,如何在这些jar文件中搜索并在其中获取.class文件?我用它来反编译
String classname = "com.mycompany.myproject.Test";
URI uri = Tool.searchClass(jarList, classname);
// decompile .class
...
有这样的示例代码吗
添加:
Shell脚本很好,但是java代码中有什么方法可以完成这项工作吗?
Add:我刚刚用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;
}
/**
*如果找到并指定了文件夹,则按jarFile中指定的类名搜索类
*将.class文件复制到包含整个路径的文件夹中。
*@param classname
*@param-jarFile
*@param dest文件夹
*@返回
*/
公共静态文件搜索压缩文件(字符串类名称、文件jarFile、字符串文件夹){
试一试{
//将类名“.”更改为“/”
if(classname.contains(“.”){
classname=classname.replace(“.”,“/”);
}
JarFile jarF=新的JarFile(JarFile);
枚举jarEntries=jarF.entries();
while(jarEntries.hasMoreElements()){
JarEntry JarEntry=jarEntries.nextElement();
if(jarEntry.getName().indexOf(classname)>=0){
字符串filePath=jarFile.getAbsolutePath();
System.out.println(classname+”位于“+filePath+”--“+jarEntry.getName());
如果(destFolder!=null&&!“.equals(destFolder)){
//如果dest文件夹不存在,则创建文件夹。
文件destF=新文件(destFolder);
如果(!destF.exists()){
destF.mkdirs();
}
File f=新文件(destFolder+File.separator+jarEntry.getName());
如果(!f.getParentFile().exists()){
f、 getParentFile().mkdirs();
}
InputStream is=jarF.getInputStream(jarEntry);
FileOutputStream fos=新java.io.FileOutputStream(f);
while(is.available()>0){
fos.write(is.read());
}
fos.close();
is.close();
返回f;
}
}
}
}捕获(IOE异常){
e、 printStackTrace();
}
System.out.println(“在jar中找不到类”);
返回null;
}
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){
}
}
}
我还发现另一个使用类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){
}
}
}
我还找到了另一个使用类的答案我在~/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文件目录特别大,则可能需要一段时间才能找到。我已经在数百个罐子中使用过它,速度很慢,但很有效。我在~/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文件目录特别大,则可能需要一段时间才能找到。我已经将它用于数百个jar,速度很慢,但很有效。我正在使用简单的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
我正在使用简单的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
使用的
loadClass()
方法。使用的loadClass()
方法。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();
URLClassLoader classLoader=newurlclassloader(list.toArray(newurl[0]);
Class clazz=classLoader.loadClass(路径);
File tmp=new File(System.getProperty(“java.io.tmpdir”)、path.replace(“.”、“”)+“.class”);
FileChannel tmpcchannel=newfileoutputstream(tmp).getChannel();
InputStream是=clazz.getResourceAsStream(“/”+path.replace(“.”,“/”+class”);
tmpcchannel.transferFrom(Channels.newChannel(is),0,Long.MAX_值);
URI=tmp.toURI();
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();
URLClassLoader classLoader=newurlclassloader(list.toArray(newurl[0]);
Class clazz=classLoader.loadClass(路径);
File tmp=new File(System.getProperty(“java.io.tmpdir”)、path.replace(“.”、“”)+“.class”);
FileChannel tmpcchannel=newfileoutputstream(tmp).getChannel();
InputStream是=clazz.getResourceAsStream(“/”+path.replace(“.”,“/”+class”);
tmpcchannel.transferFrom(Channels.newChannel(is),0,Long.MAX_值);
URI=tmp.toURI();
谢谢你的脚本,但我不擅长bash,如果我想在java代码中使用你的脚本,我该怎么做?输入是jar文件URL和类名,你能把源代码还给我吗?我的脚本名为“decode”,我在命令shell下使用它,如下所示:$forjarfile in*.jar;解码$jar文件;完成代码>谢谢你的脚本,但我不擅长bash,如果我想在java代码中使用你的脚本,我该怎么做?输入是jar文件URL和类名,你能把源代码还给我吗?我的脚本名为“decode”,我在命令shell下使用它,如下所示:$forjarfile in*.jar;解码$jar文件;完成代码>谢谢你的回复。我不擅长shell,我必须用java代码调用脚本,因此如果我将第一个参数传递给您:所有jar文件位置拆分为“,”第二个是classname,我如何调用您的脚本并获得java中的.class文件?谢谢您的回复。我不擅长shell,我必须用java代码调用脚本,所以如果我向您传递第一个参数:所有jar文件的位置用“,”分割