Java程序反编译
Java程序反编译2010-12-13 19:00 Java程序反编译就是把经过java文
件编译后的可执行的class文件再反编译为java文件,因为经过编译的class
文件是不可阅读的!但是由于java文件一般都不是单独运行的,会有类之间的
相互调用,所以反编译工具反编译后只能大体上还原原来java文件,而不能完全还原,特别是一些变量的取值,定义等.
反编译的工具有好多,在众多的JAVA反编译工具中,有几种非常著名的工具使用了相同的核心引擎--JAD,其中主要包括:Front End Plus、mDeJava、Decafe Pro、Cavaj Java Decompiler、DJ Java Decompiler、NMI's Java Class Viewer和国产的JAVA源代码反编译专家。
SUN公司的JDK(JDK1.1.3)文档,反编译JAVA的JAVAP文件(EXE),这个文件位于\JDK\BIN\下面,可用命令:javap-c-package-public-private
hello.java对hello.java文件经编译后的hello.class文件进行编译。
这就决定JAVA文件编译后不是机器码,而是一个字节码文件,也就是CLASS文件。而这样的文件是存在规律的,经过反编译工具是可以还原回来的。例如Decafe、FrontEnd,YingJAD和Jode等等软件。下面是《Nokia中Short
数组转换算法》
thread.jspa?threadID=872&tstart=0
类中Main函数的ByteCode:
0 ldc#16 2invokestatic#18 5astore_1 6return
其源代码是: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)
那么Ljava/lang/String;就是说需要传入一个String对象,而为什么前面要有一个L呢,这是JAVA虚拟机用来表示这是一个Object。如果是基本类型,这里就不需要有L了。然后返回为short的一维数组,也就是对应的[S。
是不是很有意思,S对应着Short类型,而"["对应一维数组,那有些朋友要问了,两维呢,那就"[[",呵呵,是不是很有意思。
好了,调用了函数,返回的值要保存下来吧。那么就是第三行要做的事情了。
第三行:5 astore_1
呵呵,很简单的。但是却有文章,也是比较容易混乱的地方。
astore_为虚拟机指令,作用为:将当前reference存储到局部变量中去。而必须是对当前框架的局部变量的有效索引。打个比方,可能我们这个函数中
可能还要用到这个局部变量,我们可以通过来到它。例如调用虚拟机指令:
aload_1,就能得到该值。
第四行:6 return
同样的,return也是虚拟机指令了,它的作用为:从方法返回void。
这里也就是退出main函数。
--
ok,终于啰嗦完毕了。有些朋友可能要问,这么复杂,才四行就说这么多,呵呵,可能是我这人废话过多,当然如果你熟悉了,一点就能看懂了。通过肉
眼就可以反编译程序了。目前所有的反编译工具都无法做到完美反编译,在有
问题的地方还需要人去修正。
好了,说了半天如何反编译,我们就来看看如果在你的程序如果防止别人
来反编译。好不容易写好的程序被人反编译了,多郁闷。哈哈。工欲善其事,
必先利其器,这句话用对了吗?
什么混淆等等的方法,我就不说了,我这里主要是要说一种通过添加代码
来在某种程度来避免当前流行的反编译工具对你的代码进行反编译。
方案一。
1,首先要添加一个参数为Exception类型的函数,例如这样。
public static void Fake(Exception e)
{
}
一定要有e.toString();,因为要防止你的混淆器把无用的代码过滤。
2,然后在每个类中调用这个函数,放在try.catch(Exception e).中的catch里面,例如:
try
{
.
}
java源代码加密catch(Exception e)
{
Fake(e);
}
请注意,一定要放在catch才有用,其他地方无用。
方案二。
如果以上方法还不够专业,我们再来一个。呵呵~
1,同样的,我们定义一个类,这个类叫做AntiCrack.。名字好像有点大。代码如下:
public class AntiCrack
{
private AntiCrack()
{
}
public static Throwable Fake(Throwable throwable,Throwable throwable1)
{
try
{
java.lang.Throwable.class
}).invoke(throwable,new Object{
throwable1
});
}
catch(Exception exception){}
return throwable;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论