开场白就不说了,直接切入正题吧。
本破解的前提是安装了IDEA 5.0并获得了30天的评估序列号,即IDEA可以启动但有30天的时间限制。
首先根据bin目录下idea.bat的内容确定入口类:



 SET CLASS_PATH=%IDEA_HOME%\lib\idea.jar
SET CLASS_PATH=%IDEA_HOME%\lib\idea.jar
 SET CLASS_PATH=%CLASS_PATH%;%IDEA_HOME%\lib\openapi.jar
SET CLASS_PATH=%CLASS_PATH%;%IDEA_HOME%\lib\openapi.jar
 SET CLASS_PATH=%CLASS_PATH%;%IDEA_HOME%\lib\jdom.jar
SET CLASS_PATH=%CLASS_PATH%;%IDEA_HOME%\lib\jdom.jar
 SET CLASS_PATH=%CLASS_PATH%;%IDEA_HOME%\lib\log4j.jar
SET CLASS_PATH=%CLASS_PATH%;%IDEA_HOME%\lib\log4j.jar
 SET CLASS_PATH=%CLASS_PATH%;%IDEA_HOME%\lib\extensions.jar
SET CLASS_PATH=%CLASS_PATH%;%IDEA_HOME%\lib\extensions.jar
 SET CLASS_PATH=%CLASS_PATH%;%IDEA_JDK%\lib\tools.jar
SET CLASS_PATH=%CLASS_PATH%;%IDEA_JDK%\lib\tools.jar



 第一行中的idea.jar即是启动jar包。
用Win RAR打开idea.jar,依次进入com、intellij目录,可发现intellij下包甚多,应该就是IDEA的核心。接下来就是凭运气和“天赋”了,序列号的校验模块就在这些包中,找出来只是时间问题。
最终我把焦点定在com.intellij.licensecommon.license.LicenseDataImpl(LicenseData是个抽象类)。使用DJ Java Decompiler对LicenseDataImpl.class进行反编译,得到的源代码如下:
  1 package com.intellij.licensecommon.license;
package com.intellij.licensecommon.license;
  2
  3 import com.intellij.licensecommon.util.*;
import com.intellij.licensecommon.util.*;
  4 import java.util.*;
import java.util.*;
  5
  6 public class LicenseDataImpl
public class LicenseDataImpl
  7
 extends AbstractLicenseData
    extends AbstractLicenseData {
{
  8
 static Date makeDate(int i,int j,int k)
  static Date makeDate(int i,int j,int k) {
{
  9 Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("Europe/Prague"));
    Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("Europe/Prague"));
 10 calendar.clear();
    calendar.clear();
 11 calendar.set(i,j,k);
    calendar.set(i,j,k);
 12 return calendar.getTime();
    return calendar.getTime();
 13 }
  }
 14
 15
 public LicenseDataImpl(String s,String s1)
  public LicenseDataImpl(String s,String s1) {
{
 16 super(s,s1);
    super(s,s1);
 17 g = null;
    g = null;
 18 }
  }
 19
 20
 public LicenseDataImpl(String s,String s1,long l)
  public LicenseDataImpl(String s,String s1,long l) {
{
 21 super(s,s1,l);
    super(s,s1,l);
 22 g = null;
    g = null;
 23 }
  }
 24
 25
 public String toString()
  public String toString() {
{
 26 return getUserName() + ":" + getKey();
    return getUserName() + ":" + getKey();
 27 }
  }
 28
 29
 public boolean willNeedUpgrade()
  public boolean willNeedUpgrade() {
{
 30 a();
    a();
 31 if(g.majorVersion >= 5)
    if(g.majorVersion >= 5)
 32 return false;
      return false;
 33 if(g.generationDate == null)
    if(g.generationDate == null)
 34 return true;
      return true;
 35 else
    else
 36 return a(g.generationDate,FREE_UPGRADE_DATE);
      return a(g.generationDate,FREE_UPGRADE_DATE);
 37 }
  }
 38
 39
 private boolean a(Date date,Date date1)
  private boolean a(Date date,Date date1) {
{
 40 long l = date.getTime();
    long l = date.getTime();
 41 long l1 = date1.getTime();
    long l1 = date1.getTime();
 42 return l < l1 - 0xa4cb80L;
    return l < l1 - 0xa4cb80L;
 43 }
  }
 44
 45
 public boolean needsUpgrade(Date date)
  public boolean needsUpgrade(Date date) {
{
 46 if(date == null)
    if(date == null)
 47 return false;
      return false;
 48 if(date.before(DEAD_LINE_DATE))
    if(date.before(DEAD_LINE_DATE))
 49 return false;
      return false;
 50 else
    else
 51 return willNeedUpgrade();
      return willNeedUpgrade();
 52 }
  }
 53
 54
 public boolean isEvaluationExpired(Date date)
  public boolean isEvaluationExpired(Date date) {
{
 55 if(date == null)
    if(date == null)
 56 return false;
      return false;
 57 if(!willExpire())
    if(!willExpire())
 58 return false;
      return false;
 59 else
    else
 60 //return date.after(g.expirationDate);
      //return date.after(g.expirationDate);
 61 return false;
      return false;
 62 }
  }
 63
 64
 public boolean isValid()
  public boolean isValid() {
{
 65 a();
    a();
 66 //return b();
    //return b();
 67
 68 return true;
    return true;
 69 }
  }
 70
 71
 private void a()
  private void a() {
{
 72 if(b())
    if(b())
 73 return;
      return;
 74
 try
    try {
{
 75 g = LicenseDecoder.decodeLicenseKey(getUserName(),getKey());
      g = LicenseDecoder.decodeLicenseKey(getUserName(),getKey());
 76 }
    }
 77
 catch(InvalidLicenseKeyException invalidlicensekeyexception)
    catch(InvalidLicenseKeyException invalidlicensekeyexception) {}
{}
 78 }
  }
 79
 80
 private boolean b()
  private boolean b() {
{
 81 return g != null;
    return g != null;
 82 }
  }
 83
 84
 public boolean willExpire()
  public boolean willExpire() {
{
 85 return getExpirationDate() != null;
    return getExpirationDate() != null;
 86 }
  }
 87
 88
 public Date getExpirationDate()
  public Date getExpirationDate() {
{
 89 a();
    a();
 90 return g.expirationDate;
    return g.expirationDate;
 91 }
  }
 92
 93
 public boolean isNonCommercial()
  public boolean isNonCommercial() {
{
 94 a();
    a();
 95 return g.licenseType == 1;
    return g.licenseType == 1;
 96 }
  }
 97
 98
 public boolean isCommercial()
  public boolean isCommercial() {
{
 99 a();
    a();
100 return g.licenseType == 0;
    return g.licenseType == 0;
101 }
  }
102
103
 public boolean isSite()
  public boolean isSite() {
{
104 a();
    a();
105 return g.licenseType == 2;
    return g.licenseType == 2;
106 }
  }
107
108
 public boolean isOpenSource()
  public boolean isOpenSource() {
{
109 a();
    a();
110 return g.licenseType == 3;
    return g.licenseType == 3;
111 }
  }
112
113
 public boolean isYearAcademic()
  public boolean isYearAcademic() {
{
114 a();
    a();
115 return g.licenseType == 5;
    return g.licenseType == 5;
116 }
  }
117
118
 public boolean shouldDetectDuplicates()
  public boolean shouldDetectDuplicates() {
{
119 return!isSite() && !willExpire();
    return!isSite() && !willExpire();
120 }
  }
121
122
 public Date getUpgradeDeadline()
  public Date getUpgradeDeadline() {
{
123 return DEAD_LINE_DATE;
    return DEAD_LINE_DATE;
124 }
  }
125
126
 public boolean isPersonal()
  public boolean isPersonal() {
{
127 a();
    a();
128 return g.licenseType == 4;
    return g.licenseType == 4;
129 }
  }
130
131
 public Date getGenerationDate()
  public Date getGenerationDate() {
{
132 a();
    a();
133 return g.generationDate;
    return g.generationDate;
134 }
  }
135
136
 public int getMajorVersion()
  public int getMajorVersion() {
{
137 a();
    a();
138 return g.majorVersion;
    return g.majorVersion;
139 }
  }
140
141
 public int getMinorVersion()
  public int getMinorVersion() {
{
142 a();
    a();
143 return g.minorVersion;
    return g.minorVersion;
144 }
  }
145
146
 public static LicenseDataImpl create(String s,String s1)
  public static LicenseDataImpl create(String s,String s1) {
{
147 return new LicenseDataImpl(s,s1);
    return new LicenseDataImpl(s,s1);
148 }
  }
149
150
 public static LicenseDataImpl createFromUser(String s,String s1)
  public static LicenseDataImpl createFromUser(String s,String s1) {
{
151 LicenseDataImpl licensedataimpl = new LicenseDataImpl(s,s1);
    LicenseDataImpl licensedataimpl = new LicenseDataImpl(s,s1);
152 licensedataimpl.setFromUser(true);
    licensedataimpl.setFromUser(true);
153 licensedataimpl.setAccepted(false);
    licensedataimpl.setAccepted(false);
154 return licensedataimpl;
    return licensedataimpl;
155 }
  }
156 a
a
157
 public static LicenseDataImpl create(String s,String s1,long l)
  public static LicenseDataImpl create(String s,String s1,long l) {
{
158 return new LicenseDataImpl(s,s1,l);
    return new LicenseDataImpl(s,s1,l);
159 }
  }
160
161 public static final int CURRENT_MAJOR_VERSION = 5;
  public static final int CURRENT_MAJOR_VERSION = 5;
162 public static final int CURRENT_MINOR_VERSION = 0;
  public static final int CURRENT_MINOR_VERSION = 0;
163 public static final Date DEAD_LINE_DATE = makeDate(2005,8,1);
  public static final Date DEAD_LINE_DATE = makeDate(2005,8,1);
164 public static final Date FREE_UPGRADE_DATE = makeDate(2005,4,1);
  public static final Date FREE_UPGRADE_DATE = makeDate(2005,4,1);
165 private static final long f = 0xa4cb80L;
  private static final long f = 0xa4cb80L;
166 public static final String IDEA_VERSION = "IntelliJ IDEA 5";
  public static final String IDEA_VERSION = "IntelliJ IDEA 5";
167 private LicenseInfo g;
  private LicenseInfo g;
168 }
}
169
  
顺便说一句,对于Alloy来说,IDEA基本没有做混淆(可能是公共方法太多的原因),因此反编译后源代码的可读性很好,而且反编译后的源代码基本可以正确编译。
见第60行和66行,原先是调用了两个方法进行验证。根据方法名推测isEvaluationExpired()应该是校验评估序列号是否到期,isValid()则是验证授权的合法性,这样只要直接使用boolean常量绕开检查就行了(第61行和68行)。这样修改后重新编译生成新的LicenseDataImpl.class,放回jar包覆盖原先的class文件就行了。
最后是验证。我在我的机器上将时间调到2006年8月,启动IDEA,虽然界面仍显示“Expiration date: September, 1, 2005”,但是IDE依然正常工作,破解成功
补充一句,在验证时需要了解操作系统中的其它软件是否对系统时间更改有保护性措施。像在我的机器上将时间调后1年后,卡巴斯基就过期了,将时间调回来后卡巴斯基被锁死,保持过期状态,最后只能重装。所以大家在调系统时间的时候可要考虑周到啊。
	posted on 2005-08-05 19:11 
^ Mustang ^ 阅读(6185) 
评论(13)  编辑  收藏  所属分类: 
破解