| 最近对Java程序的破解比较感兴趣,拿几个行业软件练了一下手,略有心得,拿出来与菜鸟分享!注意只是一点心得,本文并不涉及具体软件的破解。初学破解,失误之处在所难免,敬请高手赐教!
直接进入正题,对Java的破可从下面几方面入手: 一、反编译 工具很多,建意用GUI工具,命令行下的JAD很容易因为不能反编译某一个方法或某一行代码而终止整个文件的反编译,但GUI的工具却能搞定,虽然反编译后部分代码较难看懂,但总比看jvm指命要好得多。而且,GUI的工具多数有批量反编译功能,且能让反编译的文件直接以.Java为后缀保存,也是方便之处。 二、方法调用 安全意识强的开发者会把他的程序进行高质量的混淆,下面就是一个例子 throws NamingException OoO0o0o0O0oo0oO00oOO0 = OoOOoOOO0Oo0OO0OooO0o(); { F33A8299A4F6B0E7500275A27EFF3B6D2E4983F14A9EA38A1 三、为class添加代码 反编译多数情况下也只能让我们看看作者的思路,如果想把反编译出来的代码经过修改后再编译成class,通常是行不通了。而且有时候必须让程序运行在它本身的环境才能行,否则一些类无法得到正确的初始化,“方法调用”也就起不了什么作用。搞过Java的人一定知道Javassist,这个库提供了足够多的方法让你直接修改class文件,而不需要你了解字节码的相关知识,我们可以利用这个库解决上述的问题。下面是我写的一个修改字节码的类,目前还不完善,真正要用时可能需要根据情况做一些修改。 import Java.lang.reflect.*; { { { { { { { CtMethod oldMethod = cc.getDeclaredMethod(_oldmethod); { CtMethod newMethod = CtNewMethod.make(clas[3], cc); { { |
|
| println(cc.getName()+" 类的所有属性:"); for (int i=0 ; i<cfs.length ; i++ ) { continue; { continue; { continue; { { { continue; { { { modifyMethod方法用来在类的指定方法中插入一行或多行代码,参数为a时表示插在方法现有代码的最后面,为b时表示插在方法现有代码的最前面,为i时表时插在代码的指定行的前面,这个行和原代码中的行没有关系,插入位置要插入一次才能确定,为i时返回的值代表实际插入位置,由这个实际插入位置你可以计算i的值。在实际破解中发现,用该方法插入一些代码后,会使原来反编译的不可读的代码变的容易读懂,当然,也有可能使本来可读性很强的代码,因为你插入了一些语句而变得不可读。我常常在关键方法的代码中插入一些 System.out.println();这样的代码来跟踪程序,还有一点限制,你不能直接用打印输出的方法来输出方法体内的局部变量,但你可以对全局变量进行引用操作。 如果要操作局部变量,目前我所知的方法只能在该类里重建该方法,如果那位有其它的好办法,也请指点我一下。 addMethod方法在是类中增加一个新的方法,增加的方式有两种,这里就不做具体介绍。 其它方法也就不一一解释了,有兴趣的朋友可以研究一下Javassist,相信你会写出功能更强大的修改class文件的类库。 四、class的修改 在破解过程中经常会看到rsa非对称加密算法,公钥往往以十六进制存放在class文件中,(当然,也有对公钥加密后存放在配置文件中的程序)以便解密已经加密过的信息。前不久破解的一个J2EE的开发平台就是这样的,license用RSA加密,在搞懂了它的算法后,自己构件license明文,自己再生成一对rsa的公私密钥,用自己的私钥对license文明进行RSA加密,再用十六进制编辑器替换程序中所有的公钥,(当然是用你的公钥替换他的公钥,不然也没法解密)一切就搞定。当然,我所说的只是一个方面,有时暴破时可能还得用到一些JVM的指命,比如你想让一个 return false 的方法 return ture 五、读JVM指令 没有什么可以多说的,如果要从jvm指令看懂成程,必须像熟汇编一样熟悉jvm指令集,还得有一个工具把class翻译成jvm指令代码,总不能用十六进制编辑器读代码吗?如果真是,那你就太牛了。我这里介绍 bcel 这个工具,它可以把class解释为jvm指令集并存为html文件,结果就像下面: 0 getstatic System.out LJava/io/PrintStream; 3 ldc "is one" 5 invokevirtual Java.io.PrintStream.println (LJava/lang/String;)V(String):void 8 getstatic System.out LJava/io/PrintStream; 11 ldc "is two" 13 invokevirtual Java.io.PrintStream.println (LJava/lang/String;)V(String):void 16 getstatic System. out LJava/io/PrintStream; 19 ldc "is three" 21 invokevirtual Java.io.PrintStream.println (LJava/lang/String;)V(String):void 24 getstatic System.out LJava/io/PrintStream; 27 ldc "is four" 29 invokevirtual Java.io.PrintStream.println (LJava/lang/String;)V(String):void 32 return 这是一个方法的全部指令,熟悉jvm指令集的话就已经能读懂它在做什么了 |





