984724283毕业论文Java程序的保护_第1页
984724283毕业论文Java程序的保护_第2页
984724283毕业论文Java程序的保护_第3页
984724283毕业论文Java程序的保护_第4页
984724283毕业论文Java程序的保护_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、陕西职业技术学院计算机科学系学生毕业论文17 java程序的保护摘要 由于 java 语言面向对象和编译成中间代码执行的特点,其在抗反编译和反盗版方 面显得尤其脆弱。本文针对 java 软件的特点,运用多种方法,综合设计出一个保护 java 类 文件的方法。java是一种跨平台的、解释型语言。java 源代码编译中间“字节码”存储于class文件中。class文件是一种字节码形式的中间代码,该字节码中包括了很多源代码的信息,例如变量名、方法名 等。因此,java中间代码的反编译就变得非常容易。目前市场上有许多免费的、商用的反编译软件,都能够生成高质量的反编译后的源代码。所以,对开发人员 来说,

2、如何保护java程序就变成了一个非常重要的挑战。本文首先讨论了保护java程序的基本方法,然后对代码混淆问题进行深入研究,最后结合一个实际 的应用程序,分析如何在实践中保护java程序。 关 键 词: class;加密;密钥;代码混淆 目前,java 编程语言的应用在全世界范围正流行,它广泛的应用在 internet 的数据库、 多媒体、cgi 及动态网页的制作方面。1999 年在美国对 java 程序员的需求量首次超过 c+。 经调查统计,java 语言应用在软件领域占领着举足轻重的地位,为人类科技文明进步奠定了 重要基础。然而,java 语言却存在着巨大的安全隐患。java 是一种跨平台的

3、、解释型语言。 第一,java 源代码编译中间“字节码”存储于 class 文件中。class 文件是一种字节码形式的中 间代码,该字节码中包括了很多源代码的信息,例如变量名、方法名等;第二,由于跨平台 的需求,java 的指令集比较简单通用,较容易得出程序的语义信息;第三,java 编译器将每 一个类编译成一个单独的文件,这也简化了反编译的工作;第四,java 的 class 文件中,仍 然保留所有的方法和变量的名称,可以通过这些名称来访问变量和方法,这些符号往往带有 许多语义信息。因此,java 程序的这些特点,很容易对不经过处理的 java 程序进行反编译。 目前,市场上有许多优秀的 j

4、ava 反编译工具,能够反编译出非常接近源代码的程序。所以, 对开发人员来说,如何保护 java 程序就变成一个非常重要的任务。第一章 java类文件的安全威胁1.1 java的编译 开发 java 应用程序首先是使用编辑工具编写 java 的源代码,然后使用编译器编译成虚 拟机可执行的 class 类文件。编译后生成的类文件是一种有格式的中间代码字节码文件, 不能在本地机器上独立运行,只能在 java 虚拟机里解释执行。java 编译器不对变量和方法 等符号的引用转换为数值引用,也不确定程序执行过程中的内存布局,而是将这些符号的引 用信息保留在类文件中,由解释器在运行过程中创建内存布局,然后

5、再通过查找表来确定一 个变量或方法所在的地址1。 从 java 类文件的结构及其实际数据可知 java 类文件保留了源代码文件的大部分信息, 如所有的变量和方法等信息。正是由于这个特点,只要在各个平台上实现了各自的 java 虚 拟机,不用修改 java 应用程序的源代码就可以在各个平台上运行,真正做到跨平台的特性, 这也是 java 能够迅速流行起来的重要原因。1.2 java的反编译 反编译是一个将目标代码转换成源代码的过程2。而目标代码是一种用语言表示的代 码,这种语言能通过实机或虚拟机直接执行。从本质上说,他需要根据小规模、低层次的行 为来推断大规模、高层次的行为。因此,反编译目标代码

6、并不容易。 在 jdk 中,有一个反编译器 javap3,利用该工具可以对 java 类文件进行反编译。经过 该工具反汇编后得到的结果并不是源代码,但是使用javap进行反编译的 java 类文件可以得 到成员变量、方法、行号以及局部变量名等信息4。在 javap 工具的基础上,一些反编译工 具如 mocha,windis,djdecompiler 等工具可反编译出和源代码几乎一摸一样的代码。第二章 java语言 java语言的优点主要表现在:简单、面向对象、多线程、分布性、体系结构中立、安全性等方面2.1简单性 java与c+语言非常相近,但java比c+简单,它抛弃了c+中的一些不是绝对必

7、要的功能,如头文件、预处理文件、指针、结构、运算符重载、多重继承以及自动强迫同型。 java实现了自动的垃圾收集,简化了内存管理的工作。这使程序设计更加简便,同时减少了出错的可能。2.2面向对象java提供了简单的类机制和动态的构架模型。对象中封装了它的状态变量和方法,很好地实现了模块化和信息隐藏;而类则提供了一类对象的原型,通过继承和重载机制,子类可以使用或重新定义父类或超类所提供的方法,从而既实现了代码的复用,又提供了一种动态的解决方案。 java是一种完全面向对象的程序设计语言,它除了数组、布尔和字符三个基本数据类型外的其它类都是对象,它不再支持全局变量。在java中,如果不创建新类就无

8、法创建程序,java程序在运行时必须先创建一个类的实例,然后才能提交运行。java同样支持继承特性,java的类可以从其它类中继承行为,但java只支持类的单重继承,即每个类只能从一个类中继承。 java支持界面,界面允许程序员定义方法但又不立即实现,一个类可以实现多个界面,利用界面可以得到多重继承的许多优点而又没有多重继承的。2.3多线程 多线程使应用程序可以同时进行不同的操作,处理不同的事件。在多线程机制中,不同的线程处理不同的任务,他们之间互不干涉,不会由于一处等待其他部分,这样容易实现网络上的实时交互操作。java程序可以有多个执行线程,如可以让一个线程进行复杂的,而让另一个线程与用户

9、进行交互,这样用户可以在不中断计算线程的前提下与系统进行交互。多线程保证了较高的执行效率。2.4分布性java是面向网络的语言。通过它提供的类库可以处理tcp/ip协议,用户可以通过url地址在网络上很方便的访问其他对象。2.5体系结构中立java是一种网络语言,为使java程序能在网络的任何地方运行,java解释器生成与体系结构无关的字节码结构的文件格式。java为了做到结构中立,除生成机器无关的字节码外,还制定了完全统一的语言文本,如java的基本数据类型不会随目标机的变化而变化,一个整型总是32位,一个长整型总是64位。为了使java的应用程序能不依赖于具体的系统,java语言环境还提供

10、了用于访问底层操作系统功能的类组成的包,当程序使用这些包时,可以确保它能运行在各种支持java的平台上。java.lang: 一般的语言包。其中包括用于字符串处理、多线程、异常处理和数字函数等的类,该包是实现java程序运行平台的基本包java.util: 实用工具包。其中包括哈希表、堆栈、时间和日期等java.io: 基于流模型的输入/输出包。该包用统一的流模型实现了各种格式的输入/输出,包括文件系统、网络和设备的输入/输出等: 网络包。该包支持tcp/ip协议,其中提供了socket、url和www的编程接口java.awt: 抽象窗口工具集。其中实现了可以跨平台的图形用户界面组件,包括窗

11、口、菜单、滚动条和对话框等java.applet: 支持applet程序设计的基本包2.6安全性用于网络、分布环境下的java必须要防止病毒的入侵,java不支持指针,一切对内存的访问都必须通过对象的实例变量来实现,这样就防止了程序员使用欺骗手段访问对象的私有成员,同时也避免了指针操作中容易产生的错误。第三章 常用java类文件的保护方法3.1 java类文件的保护方法由于 java 字节码的抽象级别较高,容易被反编译,所以就有了多种防止 java 字节码被 反编译的方法。 隔离 java 程序:最简单的方法就是让用户不能够访问到 java class 程序,这种方法是最 根本的方法,具体实现

12、有多种方式。 代码混淆:这种方法对 class 文件进行重新组织和处理,使得处理前后的代码具有相同的语义,被混淆后的代码很难被反编译。 转换成本地代码:本地代码难以被反编译,开发人员可以选择将整个应用程序或关键模块转换成本地代码。如果仅仅转换关键模块,在使用这些模块时,需调用 jni 技术,这将牺牲 java 的跨平台特性 加密 class 文件:为了防止 class 文件被直接反编译,可以将一些关键的 class 文件加密 例如对密钥、加密算法、注册码、序列号管理相关的类等。在使用这些被加密的类之前 先解密,然后再将其装载到 jvm 中。 对比上述几种方法,都存在其自身的优缺点。隔离 jav

13、a 程序只能适合网络环境的客户 机/服务器结构或者分布式的环境,对单机运行的程序就无法隔离,而且 java 程序需要使用 安全机制保护服务器开放接口的使用,服务器的安全成了整个系统安全的焦点。代码本地化, 对于不同的平台,需要维护不同版本的本地代码,这将加重软件支持和维护的工作。对 class 文件进行加密,在使用时再进行解密,同时将关键加密代码部分进行代码混淆,这样经过双 重处理后,代码的安全性6提高了很多,该方法也是本文研究的重点。第四章 class文件加密技术java 生成的 class 文件大量暴露在客户端,利用现在的反编译工具可轻易的获取源代码, 下面将讲叙如何有效的保护 class

14、 文件。4.1读取本工程的所有待加密 class 文件,并保存到 byte 型数组中;public static byte symmetricencrypt(byte key, byte classdata) ;方法对读取到的所 有 class 文件进行加密, key 为用来加密的密钥,classdata 为所读到的待加密 class 文件, 返回结果为加密后的 class 文件,然后将其写回原来的 class 中,保证结构的完整性。4.2加密过的 cl行解密,最后将解密后的类装载到 jvm 这里我的虚拟机有默认的类加载器,但是若要它根据用户提供的密码解密代码就难以做到, 此时需要通过自定义

15、classloader 类来完成加密类的装载。自定义的 classloader 首先找到被 加密过的类,然后进行解密,最后将解密后的类装载到 jvm 中。这里我的自定义 classloader 如下: classloader apploader=new encryptedclassloader(encryptedclassloader.class.getclassloader(), new file(args1); thread.currentthread().setcontextclassloader(apploader); final class app = apploader.loadc

16、lass(args2); 其中参数 args1传入的是方法所在的工程名,args2为主函数所在的类名。 在加载类后,系统的默认 findclass()并未对加载的类作任何处理,由于 class 文件已被加密过,此时若运用系统方法 findclass()则会抛出 classnotfoundexception()的异常,所以这里需要重构我自己的 findclass()方法:protected class findclass(final string name) throws classnotfoundexception final string classresource = name.repla

17、ce(., /) + .class; final url classurl = getresource(classresource); inputstream in = null;file file = new file(classurl.getpath();byte classbytes = new byte(int)file.length(); fileinputstream fin = new fileinputstream(file); fin.read(classbytes);classbytes = decrypt(classbytes);/解密return defineclass

18、(name, classbytes, 0, classbytes.length);在这个函数中,我运用 decrypt(classbytes);方法对所有的加密 class 文件进行解密,并 在其中调用方法 public static byte symmetricencrypto(byte key, byte bytesource)将解密 后的 class 文件保存直原文件处,保持文件目录级别不变, key 为解密密钥,bytesource 为待解密的 byte 型文件。至此,已完成对类文件的加密和解密,经过测试,功能已实现,class文件无法被反编译。但为进一步加强程序的安全性,我做了如下的

19、处理。对包 含有关键信 息的方法进 行代码混淆 处理 。在 上述内容中 ,方 法 symmetricencrypt(byte key, byte classdata) 包含有加密 所用到的 算法,自 定义的classloader 包含有关键信息,findclass(final string name)以及 decrypt(classbytes);中包含有解 密信息,由于它们本身不是被加密的,因此它可能成为黑客最先攻击的目标。如果相关的解密密钥和算法被攻克,那么被加密的类也很容易被解密。所以这里我对这些关键代码进行代 码混淆。代码混淆是对代码进行重新组织和处理,使得处理后的代码与处理前的代码完成

20、相 同的功能,但是混淆后的代码很难被反编译。代码混淆有符号混淆、数据混淆、控制混淆和 预防性混淆。这里我采用数据混淆对关键代码进行处理。public static byte symmetricencrypt(byte key, byte classdata) ;处理如下:/rawkey,bytesource 为 symmetricencrypt(byte, byte)的待传入参数byte tempkey = null;tempkey 0 = 0x00;for (int i = 0; i key.length; i+)tempkey i+1 = keyi;tempkey key.length +

21、 1 = 0x11;byte source = null;source0 = 0x00;for(int i = 0; i classdata.length; i+) sourcei+1 = classdatai; sourceclassdata.length + 1 = 0x11;public static byte symmetricencrypt(bytetempkey, bytesource) /取 tempkey 和 source 的除第一个和最后一个 byte 的值.对 public class loadclass(final string tempname, final boole

22、an resolve)方法进行处理:string tempname = abcdefg + name ; /name:loadclass 的第一个待传入参数public class loadclass(final string tempname, final boolean resolve) string name = tempname.substring(11,tempname.length();.对 findclass(string name)方法进行处理:/name 为 findclass(string name)待传入参数,先做如下处理addname = name + 01357924

23、680;protected class findclass(final string addname)name = addname.substring(0,addname.length()-11);./fingclass 其他工作int len; /len = 待传文件 file 的长度:file.length()byte classbytes = new byte(int) len; classbyteslen + 1 = 0x00; classbyteslen + 2 = 0x11;/classbytes 作为 decrypt(byte classbytes)的传入参数private st

24、atic byte decrypt(final byte classbytes)byte data = new byte(int)classbyte.lengt - 2;for(int i = 0; i exceptionoccurred(env) (*env)-exceptiondescribe(env); goto leave;if (mainclassname = null) fprintf(stderr, failed to load main-class manifest attribute fromn%sn, jarfile); goto leave;classname = (ch

25、ar *)(*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)-exceptionde

26、scribe(env); status = 4;goto leave; 其中,函数loadclass见下:static jclassloadclass(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)-findc

27、lass(env, buf); free(buf); if (debug) end = counterget();printf(%ld micro seconds to load main classn, (jint)counter2micros(end-start);printf(-_java_launcher_debug-n); return cls;分析上面的程序,我们可以看到env中的函数findclass根据类名直接得到mainclass对象的。如果我们要装载已加密过的java程序, 显然直接调用findclass函数是不行的,那么,我们有没有办法自己读取文件,然后将之转换成一个ma

28、inclass对象呢?我们来看看jnienv里面还有什么?打开jdk路径includejni.h, 在里面我们查到下列定义:#ifdef _cplusplustypedef jnienv_ jnienv;#elsetypedef const struct jninativeinterface_ *jnienv;#endif而在jninativeinterface_的定义中:struct jninativeinterface_ jclass (jnicall *defineclass) (jnienv *env, const char *name, jobject loader, const j

29、byte *buf, jsize len);对了,defineclass就是我们要找的,它可以将一个缓冲区(class字节码)转换成一个类实例!下面就是一个实现如何装载加密class:static jclassloadclass(jnienv *env, char *name)file *in; long length, i;char *cc;int x; char javaloader maxpathlen, javapathmaxpathlen; char *buf = memalloc(strlen(name) + 1); char *s = buf, *t = name, c; jcl

30、ass 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, %smyloader.class, javapath);if (in = fopen(javaloader, rb) = null)fprintf(std

31、err, 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);elsecls = (*env)-findclass(env, buf); free(buf); if (debug) end = counterget();printf(%ld micro seconds to load main cl

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论