java代码防止反编译 java反编译是啥意思

如何防止class被反编译,の颐堑闹恫可以使用代码混淆是对Class文件进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能(语义) 。但是混淆后的代码很难被反编译,即反编译后得出的代码是非常难懂、晦涩的,因此反编译人员很难得出程序的真正语义 。
从理论上来说,如果有足够的时间,被混淆的代码仍然可能被破解,甚至目前有些人正在研制反混淆的工具 。但是从实际情况来看,由于混淆技术的多元化发展,混淆理论的成熟 , 经过混淆的Java代码还是能够很好地防止反编译 。
app开发完后,最好做一下扫描和加固 , 应用扫描可以通过静态代码分析、动态数据跟踪,定位出风险代码,同时监控敏感数据的异常行为 。
加固可以在一定程度上保护自己核心代码算法,提高破解/盗版/二次打包的难度,缓解代码注入/动态调试/内存注入攻击等 。
目前市面上有很多第三方加固的平台,如果新应用发布前需要扫描或者加固的话,可以先试试免费的,例如腾讯御安全,建议自己先去扫描测试下 。
如何防止JAVA程序源代码被反编译我们都知道JAVA是一种解析型语言 , 这就决定JAVA文件编译后不是机器码,而是一个字节码文件,也就是CLASS文件 。而这样的文件是存在规律的,经过反编译工具是可以还原回来的 。例如Decafe、FrontEnd,YingJAD和Jode等等软件 。下面是《Nokia中Short数组转换算法》
类中Main函数的ByteCode:0 ldc #162 invokestatic #185 astore_16 return其源代码是:short [] pixels = parseImage("/ef1s.png");
我们通过反编译工具是可以还原出以上源代码的 。而通过简单的分析 , 我们也能自己写出源代码的 。
第一行:ldc #16
ldc为虚拟机的指令,作用是:压入常量池的项,形式如下ldc index这个index就是上面的16,也就是在常量池中的有效索引,当我们去看常量池的时候,我们就会找到index为16的值为String_info , 里面存了/ef1s.png.
所以这行的意思就是把/ef1s.pn作为一个String存在常量池中,其有效索引为16 。
第二行:2 invokestatic #18
invokestatic为虚拟机指令 , 作用是:调用类(static)方法 , 形式如下
invokestatic indexbyte1 indexbyte2
其中indexbyte1和indexbyte2必须是在常量池中的有效索引,而是指向的类型必须有Methodref标记,对类名,方法名和方法的描述符的引用 。
所以当我们看常量池中索引为18的地方,我们就会得到以下信息:
Class Name : cp_info#1
Name Type : cp_info#19
1 和19都是常量池中的有效索引,值就是右边中的值 , 再往下跟踪我就不多说了,有兴趣的朋友可以去JAVA虚拟机规范 。
这里我简单介绍一下parseImage(Ljava/lang/String;)[S 的意思 。
这就是parseImage这个函数的运行,我们反过来看看parseImage的原型就明白了
short [] parseImage(String)
【java代码防止反编译 java反编译是啥意思】那么Ljava/lang/String;就是说需要传入一个String对象,而为什么前面要有一个L呢,这是JAVA虚拟机用来表示这是一个Object 。如果是基本类型,这里就不需要有L了 。然后返回为short的一维数组,也就是对应的[S 。是不是很有意思 , S对应着Short类型,而“[”对应一维数组,那有些朋友要问了,两维呢,那就“[[” , 呵呵,是不是很有意思 。
好了,调用了函数,返回的值要保存下来吧 。那么就是第三行要做的事情了 。
如何防止java文件被反编译无法防止 。.class文件的标准是公开的 , 无法防止别人反编译你的代码 。
你顶多可以用代码扰乱工具扰乱你的代码,这样反编译的代码就难以阅读 。比如可以试试用proguard来扰乱(“加密”)和反扰乱(“解密”)你的代码 。
但是java有那么多很不错的代码阅读分析工具 , 即使你用了扰乱器,也不能保证代码的安全 。
如何防止程序员反编译?Java从诞生以来,其基因就是开放精神 , 也正因此,其可以得到广泛爱好者java代码防止反编译的支持和奉献,最终很快发展壮大,以至于有今天之风光!但随着java的应用领域越来越广,特别是一些功能要发布到终端用户手中(如Android开发的app) , 有时候,公司为了商业技术的保密考虑,不希望这里面的一些核心代码能够被人破解(破解之后,甚至可以被简单改改就发布出去 , 说严重点,就可能会扰乱公司的正常软件的市场行为),这时候就要求这些java代码不能够被反编译 。
这里要先说一下反编译的现象 。因为java一直秉持着开放共享的理念,所以大家也都知道,我们一般共享一个自己写的jar包时,同时会共享一个对应的source包 。但这些依然与反编译没有什么关系,但java的共享理念,不只是建议我们这样做,而且它自己也在底层上“强迫”我们这么做!在java写的.java文件后,使用javac编译成class文件 , 在编译的过程,不像C/C或C#那样编译时进行加密或混淆,它是直接对其进行符号化、标记化的编译处理,于是 , 也产生了一个逆向工程的问题:可以根据class文件反向解析成原来的java文件!这就是反编译的由来 。
但很多时候,有些公司出于如上述的原因考虑时,真的不希望自己写的代码被别人反编译,尤其是那些收费的app或桌面软件(甚至还有一些j2ee的wen项目)!这时候,防止反编译就成了必然!但前面也说过了,因为开放理念的原因 , class是可以被反编译的 , 那现在有这样的需求之后,有哪些方式可以做到防止反编译呢?经过研究java源代码并进行了一些技术实现(结果发现,以前都有人想到过,所以在对应章节的时候,我会贴出一些写得比较细的文章,而我就简单阐述一下,也算偷个懒吧),我总共整理出以下这几种方式:
代码混淆
这种方式的做法正如其名,是把代码打乱,并掺入一些随机或特殊的字符,让代码的可读性大大降低,“曲线救国”似的达到所谓的加密 。其实,其本质就是打乱代码的顺序、将各类符号(如类名、方法名、属性名)进行随机或乱命名,使其无意义,让人读代码时很累 , 进而让人乍一看,以为这些代码是加过密的!
由其实现方式上可知,其实现原理只是扰乱正常的代码可读性,并不是真正的加密,如果一个人的耐心很好,依然可以理出整个程序在做什么 , 更何况,一个应用中,其核心代码才是人们想去了解的,所以大大缩小了代码阅读的范围!
当然,这种方式的存在,而且还比较流行 , 其原因在于,基本能防范一些技术人员进行反编译(比如说我,让我破解一个混淆的代码,我宁愿自己重写一个了)!而且其实现较为简单,对项目的代码又无开发上的侵入性 。目前业界也有较多这类工具,有商用的,也有免费的 , 目前比较流行的免费的是:proguard(我现象临时用的就是这个) 。
上面说了,这种方式其实并不是真正加密代码 , 其实代码还是能够被人反编译(有人可能说,使用proguard中的optimize选项,可以从字节流层面更改代码 , 甚至可以让JD这些反编译软件可以无法得到内容 。说得有点道理,但有两个问题:1、使用optimize对JDK及环境要求较高,容易造成混淆后的代码无法正常运行;2、这种方式其实还是混淆,JD反编译有点问题 , 可以有更强悍的工具,矛盾哲学在哪儿都是存在的^_^) 。那如何能做到我的class代码无法被人反编译呢?那就需要我们下面的“加密class”!
加密class
在说加密class之前,我们要先了解一些java的基本概念,如:ClassLoader 。做java的人已经或者以后会知道,java程序的运行 , 是类中的逻辑在JVM中运行,而类又是怎么加载到JVM中的呢(JVM内幕之类的,不在本文中阐述,所以点到为止)?答案是:ClassLoader 。JVM在启动时是如何初始化整个环境的,有哪些ClassLoader及作用是什么,大家可以自己问度娘,也不在本文中讨论 。
让我们从最常见的代码开始,揭开一下ClassLoader的一点点面纱!看下面的代码:
Java代码
public class Demo{
public static void main(String[] args){
System.out.println(“hello world!”);
}
}
上面这段代码,大家都认识 。但我要问的是:如果我们使用javac对其进行编译,然后使用java使其运行(为什么不在Eclipse中使用Run as功能呢?因为Eclipse帮我们封闭,从而简化了太多东西 , 使我们忽略了太多的底层细节 , 只有从原始的操作上,我们才能看到本质),那么,它是怎么加载到JVM中的?答案是:通过AppClassLoader加载的(相关知识点可以参考:)!如果不相信的话 , 可以输出一下System.out.println(Thread.currentThrea().getContextLoader());看看 。
那又有一个新的问题产生了:ClassLoader又是怎样加载class的呢?其实,AppClassLoader继承自java.lang.ClassLoader类 , 所以,基本操作都在这个类里面,让我们直接看下面这段核心代码吧:
看看这个方法中的逻辑,非常简单 , 先从内存中找 , 如果没有 , 则从父级或根先找 , 如果没找到,则再从自己的方法里面找!那findClass里面是什么样的呢?很不幸,这个方法是个抽象(abstract)的,也就是使用什么方式加载,由程序使用ClassLoader自己决定!这就给我们留下了巨大的“”!让我们看一下非常常见的一个ClassLoader的实现,那就是URLClassLoader(几乎所有的j2ee的web项目的容器使用的ClassLoader都是继承自它),让我们看一下它的findClass的实现:
这个方法里面的逻辑也很简单,从定义的ucp(就是各个jar包或class文件的具体路径)中读取指定的class文件的信息(如字节流之类),然后交给defineClass定义到JVM中,让我们继续看一下这个方法的核心部分:
看到这里,已经没有必要再往下面看了(再往下就是native方法了,这是一个重大伏笔哦),我们要做的手脚就在这里!
手脚怎么做呢?很简单,上面的代码逻辑告诉我们 , ClassLoader只是拿到class文件中的内容byte[],然后交给JVM初始化!于是我们的逻辑就简单了:只要在交给JVM时是正确的class文件就行了,在这之前是什么样子无所谓!所以,我们的加密的整个逻辑就是:
在编译代码时(如使用ant或maven),使用插件将代码进行加密(加密方式自己?。玞lass文件里面的内容读取成byte[],然后进行加密后再写回到class文件(这时候class文件里面的内容不是标准的class , 无法被反编译了)
在启动项目代码时,指定使用我们自定义的ClassLoader就行了,而自定义的部分,主要就是在这里做解密工作!
如此,搞定!以上的做法比较完整的阐述,可以仔细阅读一下这篇文章:文章中的介绍 。
通过这个方法貌似可以解决代码反编译的问题了!错!这里有一个巨大的坑!因为我们自定义的ClassLoader是不能加密的,要不然JVM不认识 , 就全歇菜了!如果我来反编译,呵呵,我只要反编译一下这个自定义的ClassLoader , 然后把里面解密后的内容写到指定的文件中保存下来,再把这个加了逻辑的自定义ClassLoader放回去运行,java代码防止反编译你猜结果会怎样?没错,java代码防止反编译你会想死!因为你好不容易想出来的加密算法 , 结果人家根本不需要破解,直接就绕过去了!
现在,让我们总结一下这个方法的优缺点:实现方式简单有效,同时对代码几乎没有侵入性,不影响正常开发与发布 。缺点也很明显,就是很容易被人破解!
当然啦,关于缺点问题,你也可以这么干:先对所有代码进行混淆、再进行加密 , 保证:1、不容易找到我们自定义的那个ClassLoader;2、就算找到了,破解了,代码可读性还是很差,让你看得吐血?。ㄓ幸黄恼拢揖醯眯吹貌淮?,大家可以看一看:)
嗯,我觉得这个方法很好,我自己也差点被这个想法感动了 , 但是,作为一个严谨的程序员,我真的不愿意留下一个隐患在这里!所以,我继续思索!
高级加密class
前面我们说过有个伏笔来着,还记得吧?没错,就是那个native!native定义的方法是什么方法?就是我们传说中的JNI调用!前面介绍过的有一篇文章中提到过,其实jvm的真实身份并不是java , 而是c写的jvm.dll(windows版本下),java与dll文件的调用就是通过JNI实现的!于是,我们就可以这样想:JNI可以调用第三方语言的类库 , 那么,我们可不可以把解密与装载使用第三方语言写(如C,因为它们生成的库是不好反编译的),这样它可以把解密出来的class内容直接调jvm.dll的加载接口进行初始化成class , 再返回给我们的ClassLoader?这样,我们自定义的ClassLoader只要使用JNI调用这个第三方语言写的组件,整个解密过程,都在黑盒中进行,别人就无从破解了!
嗯 , 这个方法真的很不错的!但也有两个小问题:1.使用第三方语言写,得会第三方语言,我说的会,是指很溜!2.对于不同的操作系统,甚至同一操作系统不同的版本,都可能要有差异化的代码生成对应环境下的组件(如window下是exe,linux是so等)!如果你不在乎这两个问题,我觉得,这个方式真的挺不错的 。但对于我来说,我的信条是,越复杂的方式越容易出错!我个人比较崇尚简洁的美,所以 , 这个方法我不会轻易使用!
对了,如果大家觉得这个方法还算可行的话 , 可以推荐一个我无意中看到的东西给大家看看(我都没有用过的):jinstall,
更改JVM
看到这个标题,我想你可能会震惊 。是的,你没看错,做为一个程序员,是应该要具有怀疑一切、敢想敢做的信念 。如果你有意留心的话,你会发现JVM版本在业界其实也有好几个版本的,如:Sun公司的、IBM的、Apache的、Google的……
所以,不要阻碍自己的想象力,现在没有这个能力 , 并不代表不可能 。所以,我想到,如果我把jvm改了,在里面对加载的类进行解密,那不就可以了吗?我在设计构思过程中,突然发现:人老了就是容易糊涂!前面使用第三方语言实现解密的两个问题,正好也是更改JVM要面对的两个问题,而且还有一个更大的问题:这个JVM就得跟着这个项目到处走?。?
java代码防止反编译的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java反编译是啥意思、java代码防止反编译的信息别忘了在本站进行查找喔 。

    推荐阅读