博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

代码混淆方法之二(tomcat下面代码加密)

Posted on 2008-12-30 19:25  debao.wang  阅读(752)  评论(0编辑  收藏  举报
       上面说到代码混淆方法之混淆器使用,主要针对proguard进行了说明。其实,只要我们的类被其他地方的类调用到的话,那么代码混淆器就似乎没有办法了,因为代码混淆如果把代码的签名一起改了的话,其他地方是肯定调用不到,并会出错。而且,针对代码调用,有几点是我们肯定不能避免的:一是jsp页面,如果在jsp页面调用了某个类,那么如果类被混淆了的话,jsp页面肯定会出错;二是xml配置文件,比如在hibernate开发中,对于hbm.xml文件,就没办法了。不过,很庆幸的是,proguard的功能很强,可以通过配置,只针对私有方法、私有变量做混淆。但是,这种混淆效果肯定是不如所愿。下面将说明代码混淆方法之二(tomcat下面代码加密)

       应用服务器加密的方法不外就是通过修改该应用服务器的类转载器,来载入我们的类。首先我们通过一定算法,将我们的class文件加密,并部署到应用服务器。然后修改修改该应用服务器的类转载器,通过解密算法将class文件反编译并加载。从而达到class文件的加密。下面主要针对tomcat下面的加密、解密说明。

     首先得研究一下tomcat的类装载机制:tomcat的类装载机制主要分为下面几种:

   1、Bootstrap: 由虚拟机提供
   2、System:类路径等相关
   3、Common:tomcat下面的公共包
   4、Catalina:tomcat自己的包,比如server目录下面
   5、Shared:各个war包的共享包
   6、Webapp:各个war包自己的相关类包

   由于一般的典型情况是,我们是要加密自己的应用程序,那么,我们就要覆盖上面所说的Webapp类装载器。tomcat的Webapp类装载器位于${tomcat.home}\server\lib\catalina.jar下面的类org.apache.catalina.loader.WebappClassLoader。我们从tomcat的网站下面下载tomcat的源代码,WebappClassLoader的源代码位于目录\jakarta-tomcat-catalina\catalina\src\share\org\apache\catalina\loader下面,打开源代码,可以看到里面的调用机制是这样的:
     该类里面提供了很多诸如addRepository、addJar之类的方法,这是tomcat给类路径添加相应的目录和包,比如在启动时,tomcat会将我们的应用程序下面的WEB-INF/lib/*.jar和WEB-INF/classes/**.class添加到资源路径下面。
    
    首先,在加载类的时候,会调用loadClass方法。我们先定位到下面这个方法   
     public Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException 

     仔细观察该方法,可以发现,tomcat提供了很多缓存机制,首先分别从各个级别的缓存加载类,如果加载到类,就直接返回,否则会调用下面的方法: clazz = findClass(name);

     继续定位到方法 public Class findClass(String name) throws ClassNotFoundException 
     该方法里面有一句调用 clazz = findClassInternal(name); 这个很关键,也就是我们最需要关心的一个方法了。再仔细阅读一下,就能发现,tomcat从本地的资源库里面找,并先查找资源缓存,如果找到的话,直接返回缓存类。若找不到,就会读取类文件的byte[]数组,并最后调用defineClass方法。defineClass文件是类装载的最后一个类定义方法。下面就是findClassInternal方法的代码小段

           if (entry.loadedClass == null) {
            synchronized (this) {
                if (entry.loadedClass == null) {
                 
                  clazz = defineClass(name, entry.binaryContent, 0,
                                        entry.binaryContent.length,
                                        codeSource);               
                 }
                    entry.loadedClass = clazz;
                    entry.binaryContent = null;
                    entry.source = null;
                    entry.codeBase = null;
                    entry.manifest = null;
                    entry.certificates = null;
                } else {
                    clazz = entry.loadedClass;
                }
            }
        } else {
            clazz = entry.loadedClass;
        }

      entry是一个存放类属性的bean,其中类的数组流存放在binaryContent,那么我们的加密解密就从这里入手。为了方便起见,我们用base64算法加密,加密方法很简单。通过调用base64加密方法,把原有的class文件加密;推荐的base64加密方法是commons包的codec工程。可以从apache上面下载。把加密后的class文件替换tomcat下面的部署类文件。 那么在类装载时就可以解密,并加载了。例如,为了测试,个人只对OrganizationServiceImp.class进行加密,那么通过修改以上的装载方法,就可以实现解密,修改后的代码为如下,其中黑体为修改的

        if (entry.loadedClass == null) {
            synchronized (this) {
                if (entry.loadedClass == null) {
                 
                 if(name.indexOf("OrganizationServiceImp") >=0)
                 {
                    byte[] base64Array = entry.binaryContent;
                    byte[] orginByteArray = Base64.decodeBase64(base64Array);
                    clazz = defineClass(name, orginByteArray, 0,
                      orginByteArray.length, 
                               codeSource);
                 }
                 else
                 {
                  clazz = defineClass(name, entry.binaryContent, 0,
                                        entry.binaryContent.length,
                                        codeSource);
                                       
                 }

                    entry.loadedClass = clazz;
                    entry.binaryContent = null;
                    entry.source = null;
                    entry.codeBase = null;
                    entry.manifest = null;
                    entry.certificates = null;
                } else {
                    clazz = entry.loadedClass;
                }
            }
        } else {
            clazz = entry.loadedClass;
        }
      
      
运行服务器,一切正常,说明解密、加密成功,到此完成tomcat服务器下面的解密、加密。可以看出,tomcat下面的类装载机制其实挺简单,不像其他服务器,比如weblogic、websphere服务器那么复杂。若能在这些服务器下面实现类似的效果,将是一个多么爽的事。个人在近几天将对weblogic服务器下面的部署应用进行类似的研究