使用javassist修改.class文件,并重新打包

Javassist是一款字节码编辑工具,可以直接编辑和生成Java生成的字节码,以达到对.class文件进行动态修改的效果。熟练使用这套工具,可以让Java编程更接近与动态语言编程。

下面实现如何修改jar包里的方法

Javassist下载地址 ​​查看​

1.准备jar包

my/Solution.java

修改jar的.class文件,并重新打包_java修改jar的.class文件,并重新打包_jar_02

package my.tools; public class Solution{      public int lengthOfLongestSubstring(String s) {         int longSub = 0;         if(s.isEmpty()) return 0;         if(s.length()==1) return 1;         char[] arr = s.toCharArray();         String str = String.valueOf(arr[0]);         longSub = 1;         for(int i=1;i<s.length();i++){             int pos = str.indexOf(arr[i]);             if (pos !=-1) {                 str = str.substring(pos+1)+arr[i];             }else{                 str+=arr[i];             }             if(str.length()>longSub) longSub = str.length();         }         return longSub;     }      public int strStr(String haystack, String needle) {                  if(needle.isEmpty()||needle.equals(haystack)) return 0;         int l=needle.length();         int r = haystack.length()-l;         for(int i=0;i<r+1;i++){             String tempStr=haystack.substring(i,l+i);             if(tempStr.equals(needle))                 return i;         }         return -1;     }   }

View Code

my/Encrypt.java

修改jar的.class文件,并重新打包_java修改jar的.class文件,并重新打包_jar_02

package my.tools; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.IvParameterSpec; import java.math.BigInteger; import java.net.URLDecoder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;  public class Encrypt {     public static String md5(String plainText) {         byte[] secretBytes = null;         try {             MessageDigest md = MessageDigest.getInstance("MD5");             md.update(plainText.getBytes());             secretBytes = md.digest();         } catch (NoSuchAlgorithmException e) {             throw new RuntimeException("dont have algorithm");         }          String md5code = new BigInteger(1, secretBytes).toString(16);          for (int i = 0; i < 32 - md5code.length(); i++) {             md5code = "0" + md5code;         }         return md5code;     }      public static String decrypt(String message, String key) throws Exception {         byte[] bytesrc = convertHexString(message);         Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");         DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");         SecretKey secretKey = keyFactory.generateSecret(desKeySpec);         IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));          cipher.init(2, secretKey, iv);          byte[] retByte = cipher.doFinal(bytesrc);         return new String(retByte);     }      public static byte[] convertHexString(String ss) {         byte[] digest = new byte[ss.length() / 2];         for (int i = 0; i < digest.length; i++) {             String byteString = ss.substring(2 * i, 2 * i + 2);             int byteValue = Integer.parseInt(byteString, 16);             digest[i] = ((byte) byteValue);         }         return digest;     }      public static String decode(String value) {         try {             return URLDecoder.decode(decrypt(value, "Yst@2_BI"), "utf-8");         } catch (Exception e) {             e.printStackTrace();         }         return null;     } }

View Code

新建resource

编译 javac -sourcepath my my\tools\*.java -d resource

META-INF/MANIFEST.MF


Manifest-Version: 1.0 Created-By: 1.8.0_151 (Oracle Corporation)


进入resource打包 jar -cvfm mytools.jar META-INF\MANIFEST.MF *

使用


import my.tools.Solution;  public class Main {      public static void main(String[] args) {          System.out.println(new Solution().strStr("aacabseew", "ab"));     } }


输出:3

实现的查找第二个字符串出现的位置

2.修改编译后的class

修改jar的.class文件,并重新打包_i++_05


导入下载的Javassist里的javassist.jar


import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod;  public class Main {      public static void main(String[] args) {          try {             ClassPool.getDefault().insertClassPath("data/mytools.jar");             CtClass c2 = ClassPool.getDefault().getCtClass("my.tools.Solution");             CtMethod[] ms = c2.getDeclaredMethods();             for (CtMethod c : ms) {                 System.out.println(c.getName());                 CtClass[] ps = c.getParameterTypes();                 for (CtClass cx : ps) {                     System.out.println("\t" + cx.getName());                 }                 if (c.getName().equals("strStr") && ps.length == 2                         && ps[0].getName().equals("java.lang.String")                         && ps[1].getName().equals("java.lang.String")) {                     c.setBody("{System.out.println($1);return 0;}");                 }             }             c2.writeFile();          } catch (Exception e) {             e.printStackTrace();         }     } }


运行后会在项目根目录下生成修改后的class文件

修改jar的.class文件,并重新打包_i++_06


3.生成新的jar

将以前的jar包修改mytools.zip

解压mytools.zip为mytools1,将刚才生成的my/tools/Solution.class替换掉mytools1里的Solution.class,

压缩mytools1为mytools1.zip

修改文件名为mytools1.jar

修改jar的.class文件,并重新打包_i++_07

导入新的jar包

修改jar的.class文件,并重新打包_i++_08

测试


import my.tools.Solution;  public class Main {      public static void main(String[] args) {          System.out.println(new Solution().strStr("aacabseew","ab"));      } }


输出

aacabseew

0

完成