服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

如何有效的保护java程序


目前关于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 %s ", 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 != ′

扫描关注微信公众号