JAVA反编译和源代码保护_第1页
JAVA反编译和源代码保护_第2页
JAVA反编译和源代码保护_第3页
JAVA反编译和源代码保护_第4页
JAVA反编译和源代码保护_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

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

文档简介

2.10Java反编译和源代码保护一、反编译反编译是一个将目标代码转换成源代码的过程。目标代码是一种用机器语言表示的代码,这种语言能通过实机或虚拟机直接执行。当C编译器编译生成一个对象的目标代码时,该目标代码是为某一特定硬件平台运行而产生的,在编译过程中,编译程序通过查表将所有符号的引用转换为特定的内存偏移量。目标代码只能在特定的CPU上运行。而Java编译器为了保证目标代码的可移植性,并不将对变量和方法的引用编译为数值引用,也不确定程序执行过程中的内存布局,而是将这些符号引用信息保留在字节码中,由Java虚拟机在运行过程中创立内存布局,然后再通过查表来确定一个方法所在的地址。由于其相对简单的Java虚拟机(与真实的微处理器相比)和规范的字节码格式,由Java字节码(Bytecode)反编译成源代码的过程相对于C语言来说要简单许多,因此,当前反编译Java程序颇为盛行。在介绍Java反编译器之前,要提及JDK自带的一个工具javap,它是一个Java代码反汇编器。反汇编器和反编译器是不同的,使用javap反汇编的Java类文件可得到数据区定义、方法和类的引用等信息。例如,下面是对HelloWorld.class反汇编后的部分信息:C:\JExamples>javap-cHelloWorldCompiledfrom"helloworld.java"publicclassHelloWorldextendsjava.lang.Object{publicHelloWorld();Code:0: aload_01: invokespecial#1;//Methodjava/lang/Object."<init>":()V4: return由此可见在Java字节码中蕴藏了大量的信息。Java反编译器就是利用类文件中的潜在信息和语言规范等猜测出源代码的。没有一个反编译器能够保证准确无误地翻译出源代码,而且每个反编译器自身也存在各种不同的漏洞。但是我们不可轻视反编译器的威力,它还是能比较准确地翻译出部分甚至全部的源代码。下面是一个具体的例子(图1所示),利用Java反编译器Jode(Jode的下载位置:/download.html)成功地反编译了HelloWorld.class:Ill4Jode[c]1993^2901JochenHoenicke<juchen^gnu.oig>FilmOptions□HellcM/oridpnhlicdasEHelloYarlipullicaticvoidniai^.Ill4Jode[c]1993^2901JochenHoenicke<juchen^gnu.oig>FilmOptions□HellcM/oridpnhlicdasEHelloYarlipullicaticvoidniai^.(SttriiiE[-吕t『ings){S^steTi.out.jriiitlrLCMeLloWorld!rt);HelleWorld-DecampiledlyJUDE*Visittittp://jode.sourceforge,net/图1Jode反编译HelloWorld.class反编译对安全构成的威胁是显而易见的,因此源码保护也就必不可少。其实,反编译和代码保护是一场无休止的斗争,双方都在争斗中得以发展。目前保护源码的方法大致可以归为三类:加密、模糊和定制Java的类装载器。所谓加密,就是在Java应用程序分发之前,使用加密工具进行加密。流行的加密工具有PGP(PrettyGoodPrivacy)和GPG(GnuPrivacyGuard)等。但最终用户在运行应用之前必须先进行解密,解密之后最终用户就有了一份不加密的类文件,所以加密只能对软件分发的中间环节进行有效保护,其实际效用大大减弱。二、模糊技术模糊技术(Obfuscator)就是对源代码进行模糊化处理的行为。经过模糊处理后的代码,将失去了一此可读性,程序员很难识别代码的用意。举例来说,有如下的源代码:publicclassHillSort{publicstaticString[]sort(String[]stringArray){Stringtmp;booleanexchange;for(inti=0;i<stringArray.length-1;i++){exchange=false;for(intj=stringArray.length-2;j>=i;j--){if(stringArray[j+1].compareTo(stringArray[j])<0){tmp=stringArray[j+1];stringArray[j+1]=stringArray[j];stringArray[j]=tmp;exchange=true;}}if(!exchange){break;}}returnstringArray;}•••}利用模糊处理器Smokescreen(Smokescreen是一个Java模糊器软件,其下载位置:/smokescreen/licensedownload.html,对HillSort.class进行模糊处理得到A.class,然后,再利用Jode对A.class反编译,得到的源代码如下:publicclassA{publicstaticString[]A(String[]strings){inti=0;GOTOflow_2_32_flow_2_32_:inti;IF(i>=strings.length-1)GOTOflow_72_33_String[]strings_0_=strings;booleanbool=false;inti_1_=strings_0_.length-2;for(;;){IF(i_1_<i)GOTOflow_75_34_if(strings[i_1_+1].compareTo(strings[i_1_])<0){booleanbool_2_=true;Stringstring=strings[i_1_+1];strings[i_1_+1]=strings[i_1_];strings[i_1_]=string;bool=bool_2_;}i_1_--;}flow_70_35_:String[]strings_3_=null;GOTOflow_71_36_static{•••}}模糊处理器把可读的有意义的变量名、方法名,有时甚至是类名、包名转换成没有意义的字符串,让人难以阅读程序,但对于JVM来说,其在本质上和原来的程序是一样的。在上例中类名HillSort变为A,方法名sort变为A,变量名stringArray变为strings,我们已经不可能简单地从这些名称了解这段代码的功能。有的模糊处理器更进一步,甚至采用非法的字符串来替代类文件中的标记,有意地违反了Java的规范。这些古怪的用法也可能造成Java虚拟机不能作出合法的反应(尤其在浏览器中)。例如,一个像“=”这样的变量与Java的规范是相反的;一些虚拟机可以忽略它,而另一些不可以这样。模糊处理器除了对符号名进行转换,还可能修改字节码值指令,以模糊方法中的指令控制流,使得反编译的工作更难。上例中就被加入大量的GOTO语句。模糊处理器还会在字节码中添加一些俗称“炸弹”的代码,反编译器如果不能忽略或告警,常常可能导致自身崩溃。例如一些模糊处理器会在return语句后面插入无意义的代码,确保Java虚拟机不会被执行它,反编译器却可能没有识别这个障碍。模糊处理器也有一些不足之处,main方法不会被模糊处理,这是既定的类入口函数,否则Java虚拟机无法运行该类,本地方法不会被模糊处理。另外,调用Class.forName()时指定的类名字符串,不会被模糊处理,模糊处理会提供模糊转换前后的名称映射表,手工修改此处的类名字符串为转换后的名称,即可解决该问题。反编译和模糊处理的技术都在发展,越来越复杂。这方面的工具也越来越多,大多既支持命令行,也支持图形界面。三、类装载器在介绍如何定制类装载器(ClassLoader)前,先要了解Java的运行机制。Java应用程序启动时,在运行指定类的main方法前,虚拟机首先要装载该类的字节码,然后还要执行链接和初始化的准备工作。例如运行HelloWorld时,Java虚拟机试图执行类HelloWorld的main方法,但发现该类并没有被装载,于是虚拟机使用ClassLoader寻找并装载HelloWorld的字节码。如果这个装载过程失败,则抛出一个异常;如果HelloWorld被成功装载,HelloWorld的main方法才会进一步被调用。Java运行时装入字节码的机制意味着可以对字节码和装载过程进行修改。一个称为ClassLoader的对象负责为JVM装载类的字节码。JVM给ClassLoader一个待装入类的名字(比如HelloWorld),然后由ClassLoader负责找到类文件,装入原始数据,并把它转换成一个Class对象。我们可以对类文件进行加密,当其通过定制ClassLoader装载时再进行解密,解密后的字节码保存在内存中,这样窃密者很难得到解密后的代码。定制ClassLoader既要完成原来所承担的工作,又要完成即时解密的任务。类装载器实现的核心代码如下:importjava.io.*;importjava.security.*;importjava.lang.reflect.*;importjavax.crypto.*;importjavax.crypto.spec.*;publicclassXClassLoaderextendsClassLoader{privatefinalStringCRYPT_ALGORITHM="DES";privateCiphercipher=null;publicXClassLoader(StringkeyFile)throwsIOException,GeneralSecurityException{bytekeyData[]=Util.readFile(keyFile);SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance(CRYPT_ALGORITHM);SecretKeysecretKey=keyFactory.generateSecret(newDESKeySpec(keyData));cipher=Cipher.getInstance(CRYPT_ALGORITHM);cipher.init(Cipher.DECRYPT_MODE,secretKey,newSecureRandom());}publicClassloadClass(Stringname,booleanresolve)throwsClassNotFoundException{Classclasz=null;//检查类是否已被装载if(null!=(clasz=findLoadedClass(name))){returnclasz;}//定制装载处理try{//读取加密的类文件byteencodedClass[]=Util.readFile(name+".class");if(null!=encodedClass&&null!=cipher){//解密bytedecodedClass[]=cipher.doFinal(encodedClass);//创建类实例if(decodedClass!=null){clasz=defineClass(name,decodedClass,0,decodedClass.length);}}}catch(Exceptione){}//如果上面没有成功,用默认的ClassLoader装入它if(clasz==null){clasz=findSystemClass(name);//装入相关的类if(resolve&&clasz!=null){resolveClass(clasz);}if(clasz==null){thrownewClassNotFoundException();}returnclasz;}staticpublicvoidmain(Stringargs[])throwsException{if(args.length<2){System.out.println("Usage:javaXClassLoaderkeyFileApplication[args0][args1]...");return;}StringkeyFile=args[0];//密匙文件StringappName=args[1];//应用实例类名StringappArgs[]=null;//应用实例的命令行参数if(args.length>2){appArgs=newString[args.length-2];System.arraycopy(args,2,appArgs,0,args.length-2);}//创建解密的ClassLoaderXClassLoaderxClassLoader=newXClassLoader(keyFile);//装载应用实例的字节码,并创建一个类实例ClassappClass=xClassLoader.loadClass(appName);//通过ReflectionAPI,获取应用实例的main()方法引用Methodmain=appClass.getMethod("main",newClass[]{(newString[1]).getClass()});//调用main()main.invoke(null,newObject[]{appArgs});}}publicclassUtil{//把文件读入byte数组staticpublicbyte[]readFile(Stringfilename)throwsIOException{Filefile=newFile(filename);bytedata[]=newbyte[(int)file.length()];FileInputStreamfin=newFileInputStream(file);intr=fin.read(data);if(r!=data.length)thrownewIOException("Notcompletereadingfile:"+file);fin.close();returndata;}//把byte数组写出到文件staticpublicvoidwriteFile(Stringfilename,bytedata[])throwsIOException{FileOutputStreamfout=newFileOutputStream(filename);fout.write(data);fout.close();}}类加密器实现的核心代码如下:importjava.io.*;importjava.security.*;importjavax.crypto.*;publicclassXClassEncode{staticprivatefinalStringCRYPT_ALGORITHM="DES";staticpublicStringkeyFile="key.data";//生成密匙,并把密匙保存到文件staticprivateSecretKeygenerateKey()throwsIOException,GeneralSecurityException{KeyGeneratorkg=KeyGenerator.getInstance(CRYPT_ALGORITHM);kg.init(newSecureRandom());SecretKeykey=kg.generateKey();Util.writeFile(keyFile,key.getEncoded());returnkey;}staticpublicvoidmain(Stringargs[])throwsException{if(args.length<1){System.out.println("Usage:javaXClassEncode[class1][clsss2]...");System.out.println("Output:key.data

温馨提示

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

评论

0/150

提交评论