对于Zelix KlassMaster(简称ZKM)有一个时间限制,有固定的过期时间。为了对ZKM进行破解,可以通过反编译的方式进行。一般的软件首先要找到入口点,然后分析软件的流程。1、软件ZKM的入口点。 通过分析,ZKM的入口点为com.zelix.ZKM,反编译com.zelix.ZKM,分析 public static void main(String... args)主方法,发现调用了 Class.forName(z[6]); 通过字符串信息搜集,发现调用的是 com.zelix.zopublic static void main(String args[]) {label0: { int i = rb.a; try { Class.forName(z[6]); // com.zelix.zo } catch(ClassNotFoundException _ex) { System.err.println(a + z[12] + a); System.exit(1); } try { Class aclass[] = new Class[1]; aclass[0] = c == null ? (c = a(z[24])) : c; Constructor constructor = (d == null ? (d = a(z[2])) : d).getConstructor(aclass); Object aobj[] = new Object[1]; aobj[0] = args; constructor.newInstance(aobj); // 调用 new com.zelix.zo(String... args) break label0; } .....}
2、分析com.zelix.zo的运行过程 public zo(String as1[]) { boolean flag3 = tb.b; super(); if(as1.length == 0) // 无参调用 f(); { f(); return; } .....//处理参数 }
f()方法非常重要,主要处理软件启动
private void f() { String s1 = ""; System.out.println(z[8] + q + " " + z[4] + s1 + z[9] + "?" + z[7]);// 以上现实软件信息 String s2 = a(3); boolean flag = s2.indexOf(p) != -1; String s3 = null; if(r.k()) s3 = UIManager.getCrossPlatformLookAndFeelClassName(); else s3 = UIManager.getSystemLookAndFeelClassName(); if(s3 != null) try { UIManager.setLookAndFeel(s3); } catch(Exception exception) { } wu wu1 = new wu(); wu wu2 = a(); it it1 = new it(wu1, wu2, false, flag, oc.h); fv fv1 = new fv(false);
String s4 = a(fv1, it1.q(), wu2, true); ds ds1 = new ds(); gv gv1 = gv.b(); PrintWriter printwriter = null; try { printwriter = new PrintWriter(new FileWriter(z[3]), true); } catch(IOException ioexception) { ds1.b(z[11], z[6] + ioexception.getClass().getName()); } PrintWriter printwriter1 = printwriter; Properties properties = System.getProperties(); px.a(properties, printwriter1); printwriter1.println(); long l1 = px.a(); if(l1 > -1L) { printwriter1.println(z[5] + l1 + z[10]); printwriter1.println(); } String s5 = z[8] + q + " " + z[4]; String s6 = vh.e() + " " + s5 + s1; printwriter1.println(s6); ap ap1 = new ap(gv1, it1, ds1, printwriter1); (new Thread(ap1)).start(); z2 z2_1 = new z2(z[8] + q, it1, wu1, wu2, printwriter1, r); it1.a(z2_1); Dimension dimension = z2_1.getSize(); dimension.width--; z2_1.setSize(dimension); hv hv1 = new hv(this); new g1(z2_1, fv1, s4, hv1); // 此处为NAG("I agree")窗口 }
软件运行时显示过期,通过分析ZKM类,发现ZKM类中包含了异常处理代码。通过重写ZKM类的main方法如下public static void main(String... args)throws Exception{ zo zo1 = new zo(args);}运行后软件抛出com.zelix.a1异常,同时提示过期。
因此在com.zelix.zo类中搜索抛出com.zelix.a1异常的方法。找到方法:static String a(String s1, String s2, String s3, Object obj) { boolean flag = tb.b; String s4; long l2; String s5; long l4; long l5; cy cy1; Object aobj[]; int i1; s4 = obj.getClass().getName(); SimpleDateFormat simpledateformat = new SimpleDateFormat(z[16]); TimeZone timezone = TimeZone.getDefault(); simpledateformat.setTimeZone(timezone); long l1 = sc.a(s1); l2 = sc.a(s2); long l3 = sc.a(s3); Date date = new Date(l1); s5 = simpledateformat.format(date); l4 = System.currentTimeMillis(); Date date1 = new Date(l4); if(l3 * 4L * 4L != l2) // 过期 throw new a1(s5 + z[20]); if(l4 > l1) //过期 throw new a1(s5 + z[22]); if(l4 < l1 - l2) // 使用时间为12天 throw new a1(s5 + z[17]); l5 = l4 + l3; cy1 = new cy(System.getProperty(z[1]), oc.h); aobj = cy1.a(); i1 = 0; if(!flag) goto _L2; else goto _L1_L1: if(aobj[i1] instanceof File) { long l6 = ((File)aobj[i1]).lastModified(); // 通过文件判断是否修改 if(l6 > l5) throw new a1(s5 + z[19]); } else { File file = new File(((ZipFile)aobj[i1]).getName()); if(file.exists()) { long l7 = file.lastModified(); if(l7 > l5) // 过期 throw new a1(s5 + z[24]); if(file.getName().endsWith(z[25])) try { w6 w6_1 = new w6(file); ZipEntry zipentry = w6_1.getEntry(s4.replace('.', '/') + z[12]); if(zipentry != null) { long l8 = zipentry.getTime(); if(l8 > l5) throw new a1(s5 + z[21]); if(l8 != -1L && l4 > l8 + l2) throw new a1(s5 + z[23]); w6_1.close(); } } catch(IOException ioexception) { } } } i1++;_L2: if(i1 >= aobj.length) { cy1.a(); return s5; // 返回过期时间 } if(true) goto _L1; else goto _L3_L3: JVM INSTR pop ; throw new a1(z[18]); }
方法 a() 由于整个类无法通过反编译后再次编译因此需要使用字节代码操作类库来进行修改
简单的设定为ldc #string // ldc "This is cracked by vhly[FR] AT 2006/12/10"areturn
实际上的代码相对于
static a(String s1, String s2, String s3, Object obj){ return "This is cracked by vhly[FR] AT 2006/12/10";}