金麟岂是池中物,一遇风云便化龙
Posts tagged 破解
Deskzilla Cracked
May 7th
最近破解上瘾了,昨天干到3点多,今天又花了一中午把deskzilla,一个bugzilla的桌面客户端)破解了。
这次破解花了很长时间,一是因为代码编译后被混淆了,找关键代码的时候着实花了不少时间。另一方面这个软件的license验证不是使用常见的布尔判断,而是用异常。这意味着必须仔细研究方法的调用栈,于是这次用了一个比较偷巧的方法:在代码中抛出并捕捉异常。在Java中,无论在代码何处抛出异常,JVM都会生成一个从程序入口到抛出异常方法的调用栈,这个机制在需要调用关系的场合非常有用,比如log4j,就是使用这种机制记录log的方法、行数、类名等等信息的。但是,这种机制是非常消耗资源的,因为调用栈里的每一个element都记录着方法、类、甚至行数(如果编译时打开“debug”开关)等信息,而这些信息都是通过反射机制从class文件里直接获得的。
通过对一堆类似huv、dww、dtg、gjt的混淆后的类的分析,终于找出了几个关键类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package z; public class dza extends hwn { // ... static { l = epv.a("Application.License.FULL", "Single-user license"); m = epv.a("Application.License.EVAL", "Evaluation license"); n = epv.a("Application.License.EAP", "EAP license"); o = epv.a("Application.License.OS", "License for open-source projects"); p = epv.a("Application.License.INVALID", "License is INVALID"); r = epv.a("Application.License.FLOATING", "Floating license"); s = epv.a("Application.License.PERSONAL", "Personal license"); t = epv.a("Application.License.ACADEMIC", "Academic license"); u = epv.a("Application.License.SITE", "Site license"); a = new dza("FULL", l); b = new dza("PERSONAL", s); c = new dza("FLOATING", r); d = new dza("ACADEMIC", t); e = new dza("SITE", u); f = new dza("OS", o); g = new dza("EAP", n); h = new dza("KLEVAL", m); i = new dza("EVAL", m); j = new dza("INVALID", p); } // ... } |
可以看出这是定义license类型的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package z; public class aef extends hwn { // ... public static final aef a = new gdo("UserName"); public static final aef b = new gdo("UserCompany"); public static final aef c = new fsf("CustomerID"); public static final aef d = new fir("ExpirationDate"); public static final aef e = new aef("LicenseType", dza.class); public static final aef f = new gdo("AdditionalInfo"); public static final aef g = new fsf("MinBuild"); public static final aef h = new fsf("MaxBuild"); public static final aef i = new fsf("MaxLeaseCount"); public static final aef m = new fsf("R"); public static final Date j = new Date(0L); public static final Date k = new Date(1L); // ... } |
这个类定义了需要验证哪些内容,最后关键类的关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package z; public class huv implements cud { // ... public String a(aef aef1) { String s; if (aef1 == aef.d) { Date time = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000); Calendar cal = Calendar.getInstance(); cal.setTime(time); int year = cal.get(Calendar.YEAR); int month = cal.get(Calendar.MONTH) + 1; int day = cal.get(Calendar.DAY_OF_MONTH); s = "" + year; if (month < 10) { s += ("0" + month); } if (day < 10) { s += ("0" + day); } } else if (aef1 == aef.b) { s = "Nazca"; } else if (aef1 == aef.f) { s = "to memorize my Macbook..."; } else if (aef1 == aef.e) { return dza.a.h(); } else if (aef1 == aef.a) { return "Cracked by Jay"; } else if (aef1 == aef.i) { return "20"; } else if (aef1 == aef.c) { return "1"; } else { s = ""; } return s; } // ... } |
可以看出过期时间定为当前时间的后一天,这样就永远不会过期了。最后编译,打包,替换原先的jar包,就行了。
最后提一句,破解时选择切入点非常重要。比如这次,我选择的切入点是相当靠后的,仅仅在字符串被送入验证方法之前。如果切入点再往前的话会很麻烦,因为看了一下代码,deskzilla的license是一个经3DES加密的XML文件,XML还需要用MD5校验,如果切入点是生成XML文件,那我还得搞到3DES的密钥,以及保证MD5验证通过。所谓打蛇打七寸,选对了切入点,往往有事半功倍的效果。
Synthetica破解
Mar 17th
话说前段时间提到把Synthetica给破了,而网上关于破解的文章很少,所以今天就详细说说我是怎么破的。
准备知识
Synthetica是一套很漂亮的Java的look & feel,大家可以去主页上跑一下demo(JWS的,需要安装JRE) 。可惜是commercial的,虽然有评估版下载,但是恶心的是,在评估版界面的最下方会有一块多余的区域(下图)
那这次破解的目的就是把这块区域给去了。
就我这几次破解来看,破解主要分以下几个步骤:
1. 反编译
2. 找关键代码(比如序列号校验算法)
3. 修改源代码
4. 编译打包
其中第1步是前提,在这点上Java的byte code的反编译是比较容易的了,因为毕竟是中间码,而且编译期采取的优化手段不多,反编译过来的基本就是源码。这里推荐DJ Compiler,一个相当老牌的Java反编译器。值得注意的是并不是所有的byte code都能顺利反编译,有些Java程序会使用所谓的“混淆”技术对编译后的代码就行破坏,混淆器一般采用以下方法破坏代码:
1. 不可反编译。这点其实基本不可能
2. 反编译后代码不可读。这点相当恶心,混淆器会把类名、方法名、字段名替换成没有意义的名字,当你打开编辑器放眼望去全是“class A”,“int _fld00043”,“void _mhd2314”的时候你就知道该有多痛苦了
3. 插入不可编译代码。这一点也比较恶心,说穿了就是直接修改byte code中的指令,使用合法的,但不可能从源代码编译到的指令替代原有的指令(比较拗口),比如使用“goto”替代循环。这样你的代码即使可以反编译成源代码但只能看不能改,除非你把goto再替换回去
这次Syn并没有使用混淆,所以用DJ很轻易地就反编了,接下来的活就是怎么找关键代码。一开始我以为评估版输入序列号校验成功后就升级成商业版,于是在那儿找了半天序列号的校验方法,没找到。后来凯子提供一条线索,Syn的商业版是要重新下的,于是猜测评估版和商业版不是一个版本(有时候破解也是要点推理的:-)),估计不会校验注册码。于是改变方向找加那一行字的代码,最后找到了:
public void paintBorder(Component component, Graphics g, int j, int k, int l, int i1){ ... g.setColor(UIManager.getColor("Panel.background")); g.fillRect(j, i1, l, i1 + 16); g.setColor(new Color(0xcc0000)); g.setFont(g.getFont().deriveFont(10F)); g.drawString("Synthetica - Unregistered Evaluation Copy!", 0, k + i1 + g.getFontMetrics().getAscent()); ... }
可以看出来它是通过Java 2D直接绘上去的,所以把这几句 注了,编译,打包,就ok了,最终结果:
iPhone破解:1.0.2 -> 1.1.3
Mar 8th
今天在公司玩iPhone,1.0.2的版本,心血来潮,决定升级。
上网搜了N久,有不少升级的方法, 尝试了一种先升到1.1.1的,结果不能识别SIM卡。于是抱着iBrick的决心,直接升到1.1.3,结果成了,方法如下:
1. 下载1.1.3的更新问件,网上一搜一堆,以ipsw 为后缀,162兆
2. 下载安装最新的iTunes,直接上苹果的官网下
3. 连上iPhone,双击1中下载的ipsw,这时应打开iTunes进行更新,更新完后会重启,但处于锁定状态
4. 更新完后,上网搜一个叫ZiPhone的东西,有带GUI的版本,当前好像是3.1
5. 打开ZiPhone(我用的GUI版本,会安装一下),连上iPhone,单击ZiPhone里的“Free My iPhone”,这时iPhone会重启,不行的话重启iPhone,再试一次。成功的话会看到iPhone在刷屏,2分钟左右以后iPhone自动重启,破解完成!
6. 在iphone桌面按installer图标进入install按次序安装Community Sources、BSD system 2.0 Termfix、BSD system 2.1和open SSH
7. 在 iphone里点击setting -> general -> network -> wifi里看到你的iPhone的IP地址
8. 下载安装Winscp,打开Winscp,在Winscp里输入
ip:192.168.1.100
用户名:root
密码:alpine
按LOGIN,一次连接大约需要30-45秒。别急,连不上的话多试几次。
9. 下载iphone 1.1.3汉化包,然后解压。用Winscp 将解压出的2个文件夹Applications和System传到 iphone的根目录下,覆盖原文件
10. 在iPhone 里点击setting -> general -> international -> language -> 简体中文
11. 在iPhone里点击 设置 -> 通用 -> 自动锁定 -> 永不
12. 在iPhone里点击打开installer,选择source -> edit -> add,填入http://app.weiphone.com/installer
13. 在installer里找到weiphone -> WeFit安装
14. 完成后重启iPhone,大功告成!
刷屏中……
刷完后,中文版,可输入中文









