我们都知道JAVA是一种解析型语言这就决定JAVA文件编译后不是机器码而是一个字节码文件也就是CLASS文件而这样的文件是存在规律的经过反编译工具是可以还原回来的例如DecafeFrontEndYingJAD和Jode等等软件下面是《Nokia中Short数组转换算法》
类中Main函数的ByteCode
ldc #
invokestatic #
astore_
return
其源代码是short [] pixels = parseImage(/efspng);
我们通过反编译工具是可以还原出以上源代码的而通过简单的分析我们也能自己写出源代码的
第一行ldc #
ldc为虚拟机的指令作用是压入常量池的项形式如下
ldc index
这个index就是上面的也就是在常量池中的有效索引当我们去看常量池的时候我们就会找到index为的值为String_info里面存了/efspng
所以这行的意思就是把/efspn作为一个String存在常量池中其有效索引为
第二行 invokestatic #
invokestatic为虚拟机指令作用是调用类(static)方法形式如下
invokestatic indexbyte indexbyte
其中indexbyte和indexbyte必须是在常量池中的有效索引而是指向的类型必须有Methodref标记对类名方法名和方法的描述符的引用
所以当我们看常量池中索引为的地方我们就会得到以下信息
Class Name : cp_info#
Name Type : cp_info#
和都是常量池中的有效索引值就是右边<>中的值再往下跟蹤我就不多说了有兴趣的朋友可以去JAVA虚拟机规范
这里我简单介绍一下parseImage(Ljava/lang/String;)[S 的意思
这就是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)
{
etoString();
}
一定要有etoString();因为要防止你的混淆器把无用的代码过滤
然后在每个类中调用这个函数放在trycatch(Exception e)中的catch里面例如
try
{
}
catch (Exception e)
{
Fake(e);
}
请注意 一定要放在catch才有用其他地方无用
方案二
如果以上方法还不够专业我们再来一个呵呵~
同样的我们定义一个类这个类叫做AntiCrack名字好像有点大代码如下
public class AntiCrack
{
private AntiCrack()
{
}
public static Throwable Fake(Throwable throwable Throwable throwable)
{
try
{
throwablegetClass()getMethod(initCause new Class[] {
javalangThrowableclass
})invoke(throwable new Object[] {
throwable
});
}
catch(Exception exception) { }
return throwable;
}
}
同样的我们在catch里面调用该函数例如如下
try
{
//your code here
}
catch(IOException ioexception)
{
IllegalArgumentException illegalargumentexception = new IllegalArgumentException(ioexceptiontoString());
AntiCrackfake(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);
AntiCrackfake(this throwable);
}
}
然后在你的程序里面
try
{
}
catch(IoException e)
{
throw new AntiException(ioexceptiontoString() ioexception);
}
当采用以上方式后任何类只要调用了该函数生成的class反编译后出错得不到结果
DecafeFrontEnd和YingJAD反编译时都有exception然后无法进行下去大家可以多测试变得反编译工具建议推荐用第二个方法