obfuscator已经是很好的了,我个人觉得。
因为java基本上可以说是解释型的语言,反编译的技术很成熟,如果不能保护好source,那么什么其他的保护都无从说起了。
ai.

解决方案 »

  1.   

    从IBM网站上引用的网页,可以会对你有所帮助,网址不记得了,
    可以自己去找一下
     如何有效的保护JAVA程序   
     
     
       
    内容: 
     
    流行的加密方式简介 
    ClassLoader加密方式改进 
    应用范例 
    应用范围 
    关于作者 
     
     
    Java 专区中还有: 
     
    教学 
    工具与产品 
    代码与组件 
    所有文章 
    实用技巧 
     
     
     
     
    从头到尾保护JAVA 
    胡宪利 ([email protected])
    中兴通讯SoftSwitch产品部
    2002 年 6 月目前关于JAVA程序的加密方式不外乎JAVA模糊处理(Obfuscator)和运用ClassLoader方法进行加密处理这两种方式(其他的方式亦有,但大多是这两种的延伸和变异)。这两种方式不管给JAVA反编译器造成多少困难, 毕竟还是有迹可寻,有机可乘的。本文介绍的方法是对ClassLoader方式加密处理的一种改进,使之达到传统二进制程序代码安全。
    第一章 流行的加密方式简介关于JAVA程序的加密方式,一直以来都是以JAVA模糊处理(Obfuscator)为主。这方面的研究结果也颇多,既有模糊器(如现在大名鼎鼎的JODE),也有针对反编译器的"炸弹"(如针对反编译工具Mocha的 "炸弹" Crema和HoseMocha)。模糊器,从其字面上,我们就可以知道它是通过模糊处理JAVA代码,具体的说,就是更换变量名,函数名,甚至类名等方法使其反编译出来的代码变得不可理解。举个例子来说吧。先将将下面源代码编译成class文件。        public class  test

    int sortway;
    void sort(Vector a)
    {
    ……
    }
    void setSortWay(int way)
    {
    ……
    }
    void sort(Vector a, int way)
    {
    ……
    }
    }后通过JODE进行模糊处理后,反编译过来后, 可能变成下列代码。        public class  OoOoooOo0Oo0O

    int OoOo0oOo0Oo0O;
    void OoO0ooOo0Oo0O (Vector OoOoo0Oo0OoOO)
    {
    ……
    }
    void OoOo00oOoOo0O (int Oo0oooOo0Oo0O)
    {
    ……
    }
    void OoO0ooOo0Oo0O (Vector OoOoo0Oo0OoOO, int Oo0oooOo0Oo0O)
    {
    OoOo00oOoOo0O (Oo0oooOo0Oo0O);
    OoO0ooOo0Oo0O (OoOoo0Oo0OoOO);
    }
    }其实这只是做到了视觉上的处理,其业务逻辑却依然不变,加以耐心,仍是可以攻破的,如果用在用户身份验证等目的上,完全可以找到身份验证算法而加以突破限制。而所谓的"炸弹"是针对反编译工具本身的缺陷,这种方法对于特定的反编译工具是非常有效的,然而到目前为止,还没有一个全能型的,对每一种反编译工具皆有效,其局限性是明显的!另一种方法是采用ClassLoader加密。JAVA虚拟机通过一个称为ClassLoader的对象装来载类文件的字节码,而ClassLoader是可以由JAVA程序自己来定制的。ClassLoader是如何装载类的呢?ClassLoader根据类名在jar包中找到该类的文件,读取文件,并把它转换成一个Class对象。该方法的原理就是,对需加密的类文件我们先行采用一定的方法(可以是PGP, RSA, MD5等方法)进行加密处理,我们可以在读取文件之后,进行解密后,再转换成一个Class对象。关于ClassLoader工作方式的详细介绍就不在此一一述说了,前面已有文章专题讨论了。有没有发现,该方法并未解决ClassLoader本身的安全性? 显然,只要反编译了该ClassLoader类,就可以顺藤摸瓜找到其它的类了。可见ClassLoader本身"明码"方式仍然造成一定的不安全性,然而,如果该方法解决了ClassLoader本身的安全性,其不失为一个比较好安全方案。第二章 ClassLoader加密方式改进JAVA程序是通过java.exe/javaw.exe来启动的,要对ClassLoader进行解密处理,只能从java.exe/javaw.exe身上着手。我们先来考察一下JDK的发布路径, 发现JDK的每一个版本都提供了src.jar,用winzip打开看看, 可以看到一个launcher的路径,里面包含的就是java.exe/javaw.exe的程序代码。哈哈, 这下我们可以随心所欲了。:-)打开java.c看看,里面有一段, 如下: jstring mainClassName = GetMainClassName(env, jarfile);
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->ExceptionDescribe(env);
        goto leave;
    }
    if (mainClassName == NULL) {
        fprintf(stderr, "Failed to load Main-Class manifest attribute "
        "from\n%s\n", jarfile);
        goto leave;
    }
    classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
    if (classname == NULL) {
        (*env)->ExceptionDescribe(env);
        goto leave;
    }
    mainClass = LoadClass(env, classname);
    (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
        } else {
    mainClass = LoadClass(env, classname);
        }
        if (mainClass == NULL) {
            (*env)->ExceptionDescribe(env);
            status = 4;
    goto leave;
        }其中,函数LoadClass见下:static jclass
    LoadClass(JNIEnv *env, char *name)
    {
        char *buf = MemAlloc(strlen(name) + 1);
        char *s = buf, *t = name, c;
        jclass cls;
        jlong start, end;    if (debug)
    start = CounterGet();    do {
            c = *t++;
    *s++ = (c == '.') ? '/' : c;
        } while (c != '\0');
        cls = (*env)->FindClass(env, buf);
        free(buf);    if (debug) {
    end   = CounterGet();
    printf("%ld micro seconds to load main class\n",
           (jint)Counter2Micros(end-start));
    printf("----_JAVA_LAUNCHER_DEBUG----\n");
        }    return cls;
    }分析上面的程序,我们可以看到env中的函数FindClass根据类名直接得到mainClass对象的。如果我们要装载已加密过的JAVA程序, 显然直接调用FindClass函数是不行的,那么,我们有没有办法自己读取文件,然后将之转换成一个mainClass对象呢?我们来看看JNIEnv里面还有什么?打开JDK路径\include\jni.h, 在里面我们查到下列定义:#ifdef __cplusplus
    typedef JNIEnv_ JNIEnv;
    #else
    typedef const struct JNINativeInterface_ *JNIEnv;
    #endif而在JNINativeInterface_的定义中:struct JNINativeInterface_ {
        ……
        jclass (JNICALL *DefineClass)
          (JNIEnv *env, const char *name, jobject loader, const jbyte *buf,
           jsize len);
    ……
    }对了,DefineClass就是我们要找的,它可以将一个缓冲区(class字节码)转换成一个类实例!下面就是一个实现如何装载加密Class: static jclass
    LoadClass(JNIEnv *env, char *name)
    {
    FILE *in;
        long length, i;
    char *cc;
    int  x;
         char javaloader [MAXPATHLEN], javapath[MAXPATHLEN];    char *buf = MemAlloc(strlen(name) + 1);
         char *s = buf, *t = name, c;
        jclass cls;
         jlong start, end;    if (debug)
    start = CounterGet();    do {
             c = *t++;
    *s++ = (c == '.') ? '/' : c;
         } while (c != '\0'); /*如果装载的类是MyLoader*/
    if(strcmp(buf,"MyLoader")==0) {
    if (GetApplicationHome(javapath, sizeof(javapath)))
    {
    sprintf(javaloader, "%s\\MyLoader.class", javapath);
    } if ((in = fopen(javaloader, "rb")) == NULL)
    {
    fprintf(stderr, "Cannot open input file.\n");
    return (jclass)0x0f;
    } /*读出加密的class文件*/
    fseek(in, 0L, SEEK_END);
    length = ftell(in);
    fseek(in, 0, SEEK_SET);

    cc = MemAlloc(length);
    fread((void*)cc,length,1,in);
    fclose(in); /*解密算法*/
    …… /*将解密后的class字节码转换成class*/
    cls = (*env)->DefineClass(env, buf, 0, cc, length-1);
        free(cc);
    }
    else
    cls = (*env)->FindClass(env, buf);
        
    free(buf);     if (debug) {
    end   = CounterGet();
    printf("%ld micro seconds to load main class\n",
           (jint)Counter2Micros(end-start));
    printf("----_JAVA_LAUNCHER_DEBUG----\n");
        }     return cls;
    }第三章 应用范例在实际应用中,建议新的启动程序继续采用java.exe的参数调用格式, 即java [-options] class [args...],这样的话,一方面程序在开发版本(非加密)和发布版本(加密)时的调用方式就保持一致了,便于别人的理解,另一方面启动程序的制作也简单多了,只需改动java.c中的LoadClass方法了。下面是一般应用的示意图:
     如果调用的方式是这样的:class1调用class2,而由class2调用class3,其中class2有自己定制的ClassLoader(非class3所用的ClassLoader),则这时应该在class2和class3之间加一层interface,由interface调用class3相应的ClassLoader来装载class3, 而interface本身则不能加密。这种形式的典型应用是Tomcat上的web应用,Tomcat装载servlet类时,是采用自己的ClassLoader来装载的, 如果对servlet加密,Tomcat则在装载servlet时不会装载成功,必须采用interface的方式!下面则是其应用示意图:
     第四章 应用范围由于解密需要一定的时间,如果不加区分的全部进行加密处理,势必会影响到程序的速度和响应。所以应该在需要加密的地方才加密,比方说,用户密码验证,专利算法,或者是数据库密码等等,这样的才不会导致系统的性能下降。要达到以上目的, ClassLoader必须对class加以判断,非加密的class调用JVM系统ClassLoader的LoadClass函数, 而对加密的才加以解密处理。建议:ClassLoader最好可配置! 
      

  2.   

    把最重要的业务逻辑做成DLL,通过JNI去调用。
    你的代码有多少值得别人窥视的秘密呢?
      

  3.   

    sun公司的jade加密效果不错,可以试用一下,是使用classLoader加密的