基于ASM开发的一个关于class文件加密程序,可对整个jar进行加密且不影响资源文件

来源:互联网 发布:本.西蒙斯数据 编辑:程序博客网 时间:2024/05/19 03:20
本插件利用ASM对class文件可修改功能而实现的下面展现一下实现的源代码:
第一部分辅助代码:
package com.test.encypt;
/**
* 用于保存字段原始名称和加密后的名称
* @author 陈双
*
*/
public class Field {
private String oldName;
private String newName;
public Field()
{
 
}
public Field(String oldName,String newName)
{
  this.oldName=oldName;
  this.newName=newName;
}
public String getOldName() {
  return oldName;
}
public void setOldName(String oldName) {
  this.oldName = oldName;
}
public String getNewName() {
  return newName;
}
public void setNewName(String newName) {
  this.newName = newName;
}
}
package com.test.encypt;
/**
* 用于保存方法的原始名称和加密名称
* @author 陈双
*
*/
public class Method {
private String oldName;
private String newName;
public Method()
{
 
}
public Method(String oldName,String newName)
{
  this.oldName=oldName;
  this.newName=newName;
}
public String getOldName() {
  return oldName;
}
public void setOldName(String oldName) {
  this.oldName = oldName;
}
public String getNewName() {
  return newName;
}
public void setNewName(String newName) {
  this.newName = newName;
}
}

第二部分核心代码:

package com.test.encypt;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;

/**
 * 对class文件中的字段全部加密(子类、父类、接口、父接口以及类的成员关系引用),字段对应的get、set方法加密,其他方法保留。
 * @author 陈双
 * 目前应用范围只限于一个jar的加密与所有未加密jar包应用,以后可能扩展到加密jar与加密jar相互应用
 * 操作步骤
 * 1.新建source(原目录)将待加密jar包解压到source下,
 * 2.新建dest(目标目录)
 * 3.调用加密方法如:EncryptTool.startEncypt(new File("D:\\source"),new File("D:\\dest"), "test.jar", 150);其中test.jar是加密后的jar包名称
 */
public class EncryptTool {
   private static char[] values;//数据字典
   private static Map<String,Map<String,String>> data=new HashMap<String,Map<String,String>>();//存放所有的变量
   private static  List<File> sourceList=new ArrayList<File>();//源class文件列表
   private static Map<String,File> mappingOfOld=new HashMap<String,File>();//源文件的映射,key是类的全路径,value是File
   private static Map<String,File> mappingOfNew=new HashMap<String,File>();//新文件的映射,key是类的全路径,value是File
   private static Map<String,String> mappingClass=new HashMap<String,String>();//子类与父类的映射,子类为key,父类为value
   private static int len;//加密长度
   public static void startEncypt(File sourceDir,File destDir,String destJarName,int length) throws IOException
   {
    len=length;
    List<File> newList=new ArrayList<File>();//新class文件列表
    List names=new ArrayList();//类文件的全路径
    getAll(sourceDir,sourceList,newList,names,sourceDir.getPath(),destDir.getPath());
    for(int i=0;i<sourceList.size();i++)
    {
     File classFile=sourceList.get(i);
     File newClassFile=newList.get(i);
     encrypt(classFile,newClassFile,length);//开始加密
    }
    JarOutputStream out=new JarOutputStream(new FileOutputStream(new File(destDir.getPath()+"\\"+destJarName)));
  for(int i=0;i<newList.size();i++)
  {
    jar(out,(File)newList.get(i),(String)names.get(i));
  }
  deleteDir(destDir);
  out.close();
   }
   private static void jar(JarOutputStream out, File file, String base)
   throws IOException {
    out.putNextEntry(new JarEntry(base));
    FileInputStream in = new FileInputStream(file);
    byte[] buffer = new byte[1024];
    int count = in.read(buffer);
    while (count != -1) {
     out.write(buffer, 0, count);
     count = in.read(buffer);
    }
    in.close();
   }
   private static void deleteDir(File dir)
  {
   if(dir.isDirectory())
   {//判断是否是目录
    File[] files=dir.listFiles();
    for(File f:files)
    {
     deleteDir(f);
    }
    dir.delete();
   }
   else
   {//删除文件
    if(!dir.getName().endsWith(".jar"))
    {
     dir.delete();
    }
   }
  }
   /**
    * 获取所有的class文件
    * @param sourceDir源目录
    * @param sourceList源class文件列表
    * @param newList新class文件列表
    * @param names Class文件的全路径
    * @param sourceDirName源目录名
    * @param newDirName新目录名
    * @throws IOException
    */
   private static void getAll(File sourceDir,List sourceList,List newList,List names,String sourceDirName,String newDirName) throws IOException
   {
    if(sourceDir.isDirectory())
    {
     File[] files=sourceDir.listFiles();
     for(int i=0;i<files.length;i++)
     {
      File f=files[i];
      getAll(f,sourceList,newList,names,sourceDirName,newDirName);
     }
    }
    else
    {
     sourceList.add(sourceDir);
     //构建新的class文件
     File newClass=new File(newDirName+sourceDir.getPath().substring(sourceDirName.length()));
     String path=newClass.getPath();
     path=path.substring(0,path.lastIndexOf("\\"));
     File dirs=new File(path);
     dirs.mkdirs();
     newList.add(newClass);
     String dirName=sourceDirName;
     String temp=null;
     if(dirName!=null)
     {
      dirName=dirName.replace("\\", "/");
      temp=sourceDir.getPath().replace("\\", "/").substring(dirName.length()+1);
      names.add(temp);
     }
     if(sourceDir.getName().endsWith(".class"))
     {
      String newName=temp.substring(0,temp.lastIndexOf("."));
      mappingOfOld.put(newName, sourceDir);
      mappingOfNew.put(newName, newClass);
     }
  
    }
   }
   /**
    * 加密
    * @param classFile原class文件
    * @param newClassFile新class文件
    * @param length 密文长度
    * @throws IOException
    */
   private static void encrypt(File classFile,File newClassFile,int length) throws IOException
   {
    byte[] b=null;
    FileInputStream in=new FileInputStream(classFile);
    if(classFile.getName().endsWith(".class"))
    {
     ClassReader cr=new ClassReader(in);
     if(data.containsKey(cr.getClassName()))
     {//如果已经存在就退出
      return;
     }
     String[] interfaces=cr.getInterfaces();//接口
     if(interfaces!=null&&interfaces.length>0)
     {
      for(int i=0;i<interfaces.length;i++)
      {
       File interfaceFile=mappingOfOld.get(interfaces[i]);
       File interfaceNewFile=mappingOfNew.get(interfaces[i]);
       if(interfaceFile!=null&&interfaceNewFile!=null)
       {
        encrypt(interfaceFile, interfaceNewFile, length);//递归到顶层接口
       }
      }
     }
     String superName=cr.getSuperName();//超类
     if(!superName.equals("java/lang/Object"))
     {
      File superFile=mappingOfOld.get(superName);
      File superNewFile=mappingOfNew.get(superName);
      if(superFile!=null&&superNewFile!=null)
      {
       mappingClass.put(cr.getClassName(), superName);//添加子类与父类的映射
       encrypt(superFile, superNewFile, length);//递归到顶层超类
      }
     }
     ClassWriter cw=new ClassWriter(0);
     List fields=new ArrayList();//字段名列表
     List methods=new ArrayList();//方法名列表
     CommonClassAdapter classAdapter=new CommonClassAdapter(cw,fields,methods,length,cr.getClassName());
     cr.accept(classAdapter,0);//过滤
     cw.visitEnd();
     b=cw.toByteArray();
    }
    else
    {
     b=new byte[in.available()];
     in.read(b);
     in.close();
    }
    //输出新class文件
    FileOutputStream out=new FileOutputStream(newClassFile);
    out.write(b);
    out.close();
   }
   /**
    * 从父类中查找字段或者方法,当且仅当子类使用this调用父类的字段或者方法时
    * @param owner 子类
    * @param name 字段或者方法旧名称
    * @return 字段或者方法新名称
    */
   private static String findSuperName(String owner,String name)
   {
    String superName=mappingClass.get(owner);
    if(superName!=null)
    {//父类存在
     Map<String,String> element=data.get(superName);
     String newName=element.get(name);//新名称
     if(newName==null)
     {//新名称为空就继续递归到顶层父类
      return findSuperName(superName, name);
     }
     else
     {
      return newName;
     }
    }
    return null;
   }
   /**
    * 查找父类的层级结构坐标
    * @param name 子类名称
    * @param index 默认索引
    * @return
    */
   private static int findSuperIndex(String name,int index)
   {
    String superName=mappingClass.get(name);
    if(superName!=null)
    {//父类存在
     return findSuperIndex(superName,++index);
    
    }
    return index;
   }
   static class CommonMethodAdapter extends MethodAdapter
   {
    private String name;//包名+类名
    private List fields;//字段名列表
    private List methods;//方法名列表
 public CommonMethodAdapter(MethodVisitor methodvisitor,List fields,List methods,String name) {
  super(methodvisitor);
  this.fields=fields;
  this.methods=methods;
  this.name=name;
  // TODO Auto-generated constructor stub
 }

 public void visitFieldInsn(int insn, String owner, String name, String desc) {
  // TODO Auto-generated method stub
  boolean flag=false;
  for(int i=0;i<this.fields.size();i++)
  {
   Field field=(Field)this.fields.get(i);
   if(field.getOldName().equals(name))
   {//替换被调用的字段名称
    super.mv.visitFieldInsn(insn, owner, field.getNewName(), desc);
    flag=true;
    break;
   }
  }
  if(!owner.equals(this.name)&&data.containsKey(owner))
  {
   Map<String,String> element=data.get(owner);
   if(element!=null&&element.get(name)!=null)
   {
    super.mv.visitFieldInsn(insn, owner, element.get(name), desc);
    flag=true;
   }
  }
  else if(!owner.equals(this.name)&&!data.containsKey(owner))
  {//引用外部类
   File classFile=mappingOfOld.get(owner);
   File newClassFile=mappingOfNew.get(owner);
   if(classFile!=null&&newClassFile!=null)
   {
    try {
     encrypt(classFile, newClassFile, len);
     Map<String,String> element=data.get(owner);
     if(element!=null&&element.get(name)!=null)
     {
      super.mv.visitFieldInsn(insn, owner, element.get(name), desc);
      flag=true;
     }
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
  if(!flag)
  {//其他类中的字段
   //引用父类
   String newName=EncryptTool.findSuperName(owner, name);
   if(newName!=null)
   {
    super.mv.visitFieldInsn(insn, owner, newName, desc);
   }
   else
   {
    super.mv.visitFieldInsn(insn, owner, name, desc);
   }
  }
 }
 public void visitMethodInsn(int insn, String owner, String name, String desc) {
  // TODO Auto-generated method stub
  boolean flag=false;
  for(int i=0;i<methods.size();i++)
  {
   Method method=(Method)this.methods.get(i);
   if(method.getOldName().equals(name))
   { //检查get、set方法是否被调用并且替换被调用的get、set方法名称
    super.mv.visitMethodInsn(insn, owner, method.getNewName(), desc);
    flag=true;
    break;
   }
  }
  if(!owner.equals(this.name)&&data.containsKey(owner))
  {
   Map<String,String> element=data.get(owner);
   if(element!=null&&element.get(name)!=null)
   {
    super.mv.visitMethodInsn(insn, owner,element.get(name), desc);
    flag=true;
   }
  }
  else if(!owner.equals(this.name)&&!data.containsKey(owner))
  {//引用外部类
   File classFile=mappingOfOld.get(owner);
   File newClassFile=mappingOfNew.get(owner);
   if(classFile!=null&&newClassFile!=null)
   {
    try {
     encrypt(classFile, newClassFile, len);
     Map<String,String> element=data.get(owner);
     if(element!=null&&element.get(name)!=null)
     {
      super.mv.visitMethodInsn(insn, owner,element.get(name), desc);
      flag=true;
     }
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
  if(!flag)
  { //其他方法调用
   String newName=EncryptTool.findSuperName(owner, name);
   if(newName!=null)
   {
    super.mv.visitMethodInsn(insn, owner, newName, desc);
   }
   else
   {
    super.mv.visitMethodInsn(insn, owner, name, desc);
   }
  }
 }
 
   }
   static class CommonClassAdapter extends ClassAdapter
   {
 private String name;//包名+类名
    private List fields;//字段名列表
    private List methods;//方法名列表
    int index;//字段顺序
    int length;//密文长度
 public CommonClassAdapter(ClassVisitor classvisitor,List fields,List methods,int length,String name) {
  super(classvisitor);
  this.fields=fields;
  this.methods=methods;
  this.length=length;
  this.index=0;
  this.name=name;
  // TODO Auto-generated constructor stub
 }
   
 public FieldVisitor visitField(int access, String name, String desc, String signature,
   Object value) {
  // TODO Auto-generated method stub
  String newName=EncryptTool.getNewName(index,length,this.name); //获取新的字段名称
  fields.add(new Field(name,newName));//将源字段名称和新字段名称保存到Field中
  Map element=null;//类的字段和方法名称的全部信息
  //注册字段名称
  if(data.get(this.name)==null)
  {
      element=new HashMap<String,String>();
   element.put(name, newName);//原名称为key,新名称为value
   data.put(this.name, element);//类的完全名称为key,以类的字段名称和方法名称为Map的对象进行存储
  }
  else
  {
   element=data.get(this.name);
   element.put(name, newName);
  }
  index++;
  return super.cv.visitField(access, newName, desc, signature, value);
 }

 public MethodVisitor visitMethod(int access, String name, String desc,
   String signature, String[] exceptions) {
  // TODO Auto-generated method stub
  if(name.startsWith("set")||name.startsWith("get"))
  {//是否是get、set方法
   String str=name.substring(3).toLowerCase();
   String prefix=name.substring(0,3);
   for(int i=0;i<this.fields.size();i++)
   {
    Field field=(Field)this.fields.get(i);
    if(field.getOldName().equals(str))
    {//检查set、get对应的字段 
     String newName=prefix+field.getNewName();
     methods.add(new Method(name,newName));
     Map element=null;//类的字段和方法名称的全部信息
     //注册字段名称
     if(data.get(this.name)==null)
     {
         element=new HashMap<String,String>();
      element.put(name, newName);//原名称为key,新名称为value
      data.put(this.name, element);//类的完全名称为key,以类的字段名称和方法名称为Map的对象进行存储
     }
     else
     {
      element=data.get(this.name);
      element.put(name, newName);
     }
     //替换get、set方法名称
     return new CommonMethodAdapter(super.cv.visitMethod(access, newName, desc, signature, exceptions),this.fields,this.methods,this.name);
    }
   }
  }
  if(data.get(this.name)==null)
  {
   data.put(this.name, new HashMap<String,String>());
  }
  return new CommonMethodAdapter(super.cv.visitMethod(access, name, desc, signature, exceptions),this.fields,this.methods,this.name);
 }
   
   }
   /**
    * 获取字段对应密钥
    * @param index字段顺序
    * @param length密钥长度
    * @return
    */
   public static String getNewName(int index,int length,String name)
   {
    int len=values.length;
    char[] content=new char[length];//密文内容
    int rs=findSuperIndex(name,0);//查找父类坐标
    if(index>=len)
    { //如果字段顺序长度大于密码数据的长度
     int count=index/len;//求商
     int mod=index%len;//求余数
     for(int i=0;i<count;i++)
     {//密文映射
      content[i]=values[i];
     }
     content[count]=values[mod];//密文映射
     for(int j=count+1;j<length;j++)
     {
      content[j]='0';//补0操作
     }
   
    }
    else
    {//如果字段顺序长度小于密码数据的长度
     content[0]=values[index];//密文映射
     for(int i=1;i<length;i++)
     {
      content[i]='0';//补0操作
     }
    }
    String temp=new String(content);
    if(rs>-1&&rs<10)
    {//0-9之间
     return temp.substring(0, length-7)+"super0"+rs;
    }
    else if(rs>=0&&rs<100)
    {//10-99
     return temp.substring(0, length-7)+"super"+rs;
    }
    return temp;
   }
   static
   {
    values=new char[]{'A','B','C','D','E','F','G','H','I','J','K','L','M',
               'N', 'O','P','Q','R','S','T','U','V','W','X','Y','Z',
               };
   }
}

第三部分测试代码:

package com.test.encypt;
import java.io.File;
public class Test {
  /**
     * 用来加密class文件
      * 
      * @param args
      */ 
     public static void main(String[] args) { 
      try {
//把jar包放到source下解压,一次只能放一个jar包,test.jar是dest目录下加密之后的新的jar包名称,运行完成之后dest中将会产生一个test.jar
//本程序必须依赖asm-all-3.0.jar
  EncryptTool.startEncypt(new File("D:\\source"), new File("D:\\dest"),"test.jar", 150) ;
   } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
     }
   

第四部分运行效果展示:

package com.test.bean;
import java.lang.reflect.Method;
// Referenced classes of package com.test.bean:
//            InvocationHandler
public class Helloworld {
public Helloworld(InvocationHandler h) {
  A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 = h;
}
public String getC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000() {
  return C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
}
public void setC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000(
   String name) {
  C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 = name;
}
public int getD00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000() {
  return D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
}
public void setD00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000(
   int age) {
  D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 = age;
}
public Object start(Object name1, Object name2, String name3) {
  Object array[] = new Object[3];
  array[0] = name1;
  array[1] = name2;
  setC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000(name3);
  name3 = getC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000();
  array[2] = name3;
  return A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    .invoke(this, "start", null, array);
}
public void end(Object name1, Object name2, String name3) {
  Object array[] = new Object[3];
  array[0] = name1;
  array[1] = name2;
  array[2] = name3;
  A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    .invoke(this, "start", null, array);
}
public char hello(int age, String name, String desc) {
  String s = "a";
  String s1 = "b";
  String s2 = "c" + s1;
  String s3 = s + s1;
  String str = new String("str");
  String s4 = str + "d";
  String s5 = str + s1;
  int i = 1;
  Object o[] = new Object[10];
  o[0] = name;
  o[1] = desc;
  o[2] = Integer.valueOf(age);
  o[3] = Short.valueOf((short) 1);
  o[4] = Byte.valueOf((byte) 1);
  o[5] = Character.valueOf('c');
  o[6] = Float.valueOf(1.0F);
  o[7] = Long.valueOf(12L);
  o[8] = Double.valueOf(122D);
  o[9] = Boolean.valueOf(false);
  return A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    .invoke(this, s, null, new Object[] { "11", "22" }).toString()
    .toCharArray()[0];
}
private InvocationHandler A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
private static Method B00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
private String C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
private int D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
static {
  try {
   B00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 = Class
     .forName("com.test.bean.Student").getMethod("end",
       new Class[0]);
  } catch (Exception e) {
   e.printStackTrace();
  }
}
}
原创粉丝点击