最近破解上瘾了,昨天干到3点多,今天又花了一中午把deskzilla,一个bugzilla的桌面客户端)破解了。
这次破解花了很长时间,一是因为代码编译后被混淆了,找关键代码的时候着实花了不少时间。另一方面这个软件的license验证不是使用常见的布尔判断,而是用异常。这意味着必须仔细研究方法的调用栈,于是这次用了一个比较偷巧的方法:在代码中抛出并捕捉异常。在Java中,无论在代码何处抛出异常,JVM都会生成一个从程序入口到抛出异常方法的调用栈,这个机制在需要调用关系的场合非常有用,比如log4j,就是使用这种机制记录log的方法、行数、类名等等信息的。但是,这种机制是非常消耗资源的,因为调用栈里的每一个element都记录着方法、类、甚至行数(如果编译时打开“debug”开关)等信息,而这些信息都是通过反射机制从class文件里直接获得的。
通过对一堆类似huv、dww、dtg、gjt的混淆后的类的分析,终于找出了几个关键类:
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类型的类
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);
// ...
}
这个类定义了需要验证哪些内容,最后关键类的关键代码:
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验证通过。所谓打蛇打七寸,选对了切入点,往往有事半功倍的效果。
-- EOF --
除非注明(如“转载”、“[zz]”等),本博文章皆为原创内容,转载时请注明: 「转载自程序员的信仰©」
本文链接地址:Deskzilla Cracked
Today on history:
【2020】家用游戏机的历史:世嘉、任天堂和 PlayStation 的故事 [zz]
【2012】《2012湖南卫视成人礼盛典》韩寒演讲《远行》
【2010】新浪围脖挂了,twitter第一时间响应
【2010】不要问我哭过了没,因为超人不能流眼泪

不知道最新的Deskzilla 3 有没有破解掉呢,感觉跟你说的还是有点差别啊