修改jar包里面的class文件
错误信息
Exception in thread "main" java.lang.SecurityException: class "xxx.xxx.xx"'s signer information does not match signer information of other classes in the same package
at java.lang.ClassLoader.checkCerts(ClassLoader.java:898)
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:668)
at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
由于 jar 包签名加密了,使用反编译软件 Java decompiler 或者 idea 等其它软件可以看到在jar 的 MATE-INF 目录下面有 *RSA,,*.SF文件,需要去除这些文件才能替换jar包里面的class
文件.
去除jar包签名
https://stackoverflow.com/questions/7757083/how-do-i-unsign-a-jar/34331144#34331144
代码如下
import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; public class JarUnsigner { private static final String MANIFEST = "META-INF/MANIFEST.MF"; public static void main(String[] args){ String infile = “xxx.jar”; // 签名的jar String outfile = "xxx-unnsigned.jar"; // 去除 *.RSA、*.SF 之后的jar if ((new File(outfile)).exists()){ System.out.println("Output file already exists:" + outfile); System.exit(1); } try{ ZipFile zipFile = new ZipFile(infile); final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outfile)); for (Enumeration e = zipFile.entries(); e.hasMoreElements();) { ZipEntry entryIn = (ZipEntry) e.nextElement(); if (! exclude_file( entryIn.getName() ) ) { /* copy the entry as-is */ zos.putNextEntry( new ZipEntry( entryIn.getName() )); InputStream is = zipFile.getInputStream(entryIn); byte[] buf = new byte[1024]; int len; while ((len = (is.read(buf))) > 0) { zos.write(buf, 0, len); } zos.closeEntry(); } else { if (MANIFEST.equals(entryIn.getName())){ /* if MANIFEST, adjust the entry */ zos.putNextEntry(new ZipEntry(MANIFEST)); // manifest entries until first empty line. i.e. the 'MainAttributes' section // (this method is used so to keep the formatting exactly the same) InputStream mIS = zipFile.getInputStream(entryIn); BufferedReader in = new BufferedReader(new InputStreamReader(mIS)); String line = in.readLine(); byte[] mNL = " ".getBytes("UTF-8"); while( line != null && !line.trim().isEmpty() ) { zos.write( line.getBytes("UTF-8")); zos.write( mNL ); line = in.readLine(); } zos.write( mNL ); zos.closeEntry(); }else{ /* else: Leave out the Signature files */ } } } zos.close(); System.out.println("Successfully unsigned " + outfile); }catch(IOException ex){ System.err.println("Error for file: " + infile); ex.printStackTrace(); System.exit(1); } } /** * Exclude .SF signature file * Exclude .RSA and DSA (signed version of .SF file) * Exclude SIG- files (unknown sign types for signed .SF file) * Exclude Manifest file * @param filename * @return */ public static boolean exclude_file(String filename){ return filename.equals("META-INF/MANIFEST.MF") || filename.startsWith("META-INF/SIG-") || filename.startsWith("META-INF/") && ( filename.endsWith(".SF") || filename.endsWith(".RSA") || filename.endsWith(".DSA") ); } }
运行之后,再去修改jar包中的class文件、
还有一种更简单的方式,用压缩软件打开 jar, 删除相关的 *.SF, *.RSA, *.DSA 文件