保护Java代码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;

}

 

你可能感兴趣的:(ClassLoader)