防止JAVA代码被反编译的方法
我们都知道JAVA是一种解析型语言 这就决定JAVA文件编译后不是机器码 而是一个字节码文件 也就是CLASS文件 而这样的文件是存在规律的 经过反编译工具是可以还原回来的 例如Decafe FrontEnd YingJAD和Jode等等软件 下面是《Nokia中Short数组转换算法》
类中Main函数的ByteCode
ldc #
invokestatic #
astore_
return
其源代码是 short [] pixels = parseImage( /ef s png );
我们通过反编译工具是可以还原出以上源代码的 而通过简单的分析 我们也能自己写出源代码的
JAVA手机网[]第一行 ldc #
ldc为虚拟机的指令 作用是 压入常量池的项 形式如下
ldc index
这个index就是上面的 也就是在常量池中的有效索引 当我们去看常量池的时候 我们就会找到index为 的值为String_info 里面存了/ef s png
所以这行的意思就是把/ef s pn作为一个String存在常量池中 其有效索引为
第二行 invokestatic #
invokestatic为虚拟机指令 作用是 调用类(static)方法 形式如下
invokestatic indexbyte indexbyte
其中indexbyte 和indexbyte 必须是在常量池中的有效索引 而是指向的类型必须有Methodref标记 对类名 方法名和方法的描述符的引用
所以当我们看常量池中索引为 的地方 我们就会得到以下信息
Class Name : cp_info#
Name Type : cp_info#
和 都是常量池中的有效索引 值就是右边<>中的值 再往下跟踪我就不多说了 有兴趣的朋友可以去JAVA虚拟机规范
这里我简单介绍一下parseImage(Ljava/lang/String;)[S 的意思
JAVA手机网[]这就是parseImage这个函数的运行 我们反过来看看parseImage的原型就明白了
short [] parseImage(String)
那么Ljava/lang/String;就是说需要传入一个String对象 而为什么前面要有一个L呢 这是JAVA虚拟机用来表示这是一个Object 如果是基本类型 这里就不需要有L了 然后返回为short的一维数组 也就是对应的[S 是不是很有意思 S对应着Short类型 而 [ 对应一维数组 那有些朋友要问了 两维呢 那就 [[ 呵呵 是不是很有意思
好了 调用了函数 返回的值要保存下来吧 那么就是第三行要做的事情了
第三行 astore_
呵呵 很简单的 但是却有文章 也是比较容易混乱的地方
astore_为虚拟机指令 作用为 将当前reference存储到局部变量中去 而必须是对当前框架的局部变量的有效索引 打个比方 可能我们这个函数中可能还要用到这个局部变量 我们可以通过来找到它 例如调用虚拟机指令
aload_ 就能得到该值
第四行 return
同样的 return也是虚拟机指令了 它的作用为 从方法返回void
这里也就是退出main函数
ok 终于啰嗦完毕了 有些朋友可能要问 这么复杂 才四行就说这么多 呵呵 可能是我这人废话过多 当然如果你熟悉了 一点就能看懂了 通过肉眼就可以反编译程序了 目前所有的反编译工具都无法做到完美反编译 在有问题的地方还需要人去修正
好了 说了半天如何反编译 我们就来看看如果在你的程序如果防止别人来反编译 好不容易写好的程序被人反编译了 多郁闷 哈哈 工欲善其事 必先利其器 这句话用对了吗?
什么混淆等等的方法 我就不说了 我这里主要是要说一种通过添加代码来在某种程度来避免当前流行的反编译工具对你的代码进行反编译
方案一
首先要添加一个参数为Exception类型的函数 例如这样
public static void Fake(Exception e)
{
JAVA手机网[] e toString();
}
一定要有e toString(); 因为要防止你的混淆器把无用的代码过滤
然后在每个类中调用这个函数 放在try catch(Exception e) 中的catch里面 例如
try
JAVA手机网[] {
}
catch (Exception e)
{
Fake(e);
}
请注意 一定要放在catch才有用 其他地方无用
方案二
如果以上方法还不够专业 我们再来一个 呵呵~
同样的 我们定义一个类 这个类叫做AntiCrack 名字好像有点大 代码如下
public class AntiCrack
{
private AntiCrack()
{
}
public static Throwable Fake(Throwable throwable Throwable throwable )
{
try
{
throwable getClass() getMethod( initCause new Class[] {
JAVA手机网[] java lang Throwable class
}) invoke(throwable new Object[] {
throwable
});
}
catch(Exception exception) { }
return throwable;
}
}
同样的 我们在catch里面调用该函数 例如如下
try
{
//your code here
}
catch(IOException ioexception)
{
IllegalArgumentException illegalargumentexception = new IllegalArgumentException(ioexception toString());
AntiCrack fake(illegalargumentexception ioexception);
throw illegalargumentexception;
}
或者也可以这样
public class AntiException extends Exception
{
public AntiException()
{
}
public AntiException(String s)
{
super(s);
}
public AntiException(String s Throwable throwable)
{
super(s);
AntiCrack fake(this throwable);
}
}
JAVA手机网[]然后在你的程序里面
try
{
}
catch(IoException e)
{
throw new AntiException(ioexception toString() ioexception);
}
当采用以上方式后 任何类只要调用了该函数 生成的class反编译后出错 得不到结果
Decafe FrontEnd和YingJAD 反编译时都有exception 然后无法进行下去 大家可以多测试变得反编译工具 建议推荐用第二个方法
lishixinzhi/Article/program/Java/hx/201311/25765