• 静思
  • 吴言片语
    • 吴言
    • 片语
    • 杂七杂八
  • 死于青春
    • 一路走好
  • 乌合麒麟
  • 纪念
    • 5.12
    • 3.23
  • GitHub
    • A List of Post-mortems
    • The Art of Command Line
  • 关于
    • Privacy Policy

程序员的信仰

金鳞岂是池中物,一遇风云便化龙

HOME » 技术生活 » IDEA破解过程

IDEA破解过程

2005 年 8 月 5 日 @ 下午 7:11 by Jay | 被踩了 2,971 脚

开场白就不说了,直接切入正题吧。

本破解的前提是安装了IDEA 5.0并获得了30天的评估序列号,即IDEA可以启动但有30天的时间限制。

首先根据bin目录下idea.bat的内容确定入口类:

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\jdom.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_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进行反编译,得到的源代码如下:

package com.intellij.licensecommon.license;

import com.intellij.licensecommon.util.*;
import java.util.*;

public class LicenseDataImpl extends AbstractLicenseData{
  static Date makeDate(int i,int j,int k){
    Calendar calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("Europe/Prague"));
    calendar.clear();
    calendar.set(i,j,k);
    return calendar.getTime();
  }

  public LicenseDataImpl(String s,String s1){
    super(s,s1);
    g = null;
  }

  public LicenseDataImpl(String s,String s1,long l){
    super(s,s1,l);
    g = null;
  }

  public String toString(){
    return getUserName() + ":" + getKey();
  }

  public boolean willNeedUpgrade(){
    a();
    if(g.majorVersion >= 5)
      return false;
    if(g.generationDate == null)
      return true;
    else
      return a(g.generationDate,FREE_UPGRADE_DATE);
  }

  private boolean a(Date date,Date date1){
    long l = date.getTime();
    long l1 = date1.getTime();
    return l < l1 - 0xa4cb80L;
  }

  public boolean needsUpgrade(Date date){
    if(date == null)
      return false;
    if(date.before(DEAD_LINE_DATE))
      return false;
    else
      return willNeedUpgrade();
  }

  public boolean isEvaluationExpired(Date date){
    if(date == null)
      return false;
    if(!willExpire())
      return false;
    else
      //return date.after(g.expirationDate);
      return false;
  }

  public boolean isValid(){
    a();
    //return b();

    return true;
  }

  private void a(){
    if(b())
      return;
    try{
      g = LicenseDecoder.decodeLicenseKey(getUserName(),getKey());
    }
    catch(InvalidLicenseKeyException invalidlicensekeyexception){}
  }

  private boolean b(){
    return g != null;
  }

  public boolean willExpire(){
    return getExpirationDate() != null;
  }

  public Date getExpirationDate(){
    a();
    return g.expirationDate;
  }

  public boolean isNonCommercial(){
    a();
    return g.licenseType == 1;
  }

  public boolean isCommercial(){
    a();
    return g.licenseType == 0;
  }

  public boolean isSite(){
    a();
    return g.licenseType == 2;
  }

  public boolean isOpenSource(){
    a();
    return g.licenseType == 3;
  }

  public boolean isYearAcademic(){
    a();
    return g.licenseType == 5;
  }

  public boolean shouldDetectDuplicates(){
    return!isSite() && !willExpire();
  }

  public Date getUpgradeDeadline(){
    return DEAD_LINE_DATE;
  }

  public boolean isPersonal(){
    a();
    return g.licenseType == 4;
  }

  public Date getGenerationDate(){
    a();
    return g.generationDate;
  }

  public int getMajorVersion(){
    a();
    return g.majorVersion;
  }

  public int getMinorVersion(){
    a();
    return g.minorVersion;
  }

  public static LicenseDataImpl create(String s,String s1){
    return new LicenseDataImpl(s,s1);
  }

  public static LicenseDataImpl createFromUser(String s,String s1){
    LicenseDataImpl licensedataimpl = new LicenseDataImpl(s,s1);
    licensedataimpl.setFromUser(true);
    licensedataimpl.setAccepted(false);
    return licensedataimpl;
  }

  public static LicenseDataImpl create(String s,String s1,long l){
    return new LicenseDataImpl(s,s1,l);
  }

  public static final int CURRENT_MAJOR_VERSION = 5;
  public static final int CURRENT_MINOR_VERSION = 0;
  public static final Date DEAD_LINE_DATE = makeDate(2005,8,1);
  public static final Date FREE_UPGRADE_DATE = makeDate(2005,4,1);
  private static final long f = 0xa4cb80L;
  public static final String IDEA_VERSION = "IntelliJ IDEA 5";
  private LicenseInfo g;
}

顺便说一句,对于Alloy来说,IDEA基本没有做混淆(可能是公共方法太多的原因),因此反编译后源代码的可读性很好,而且反编译后的源代码基本可以正确编译。

见第59行和65行,原先是调用了两个方法进行验证。根据方法名推测isEvaluationExpired()应该是校验评估序列号是否到期,isValid()则是验证授权的合法性,这样只要直接使用boolean常量绕开检查就行了(第60行和67行)。这样修改后重新编译生成新的LicenseDataImpl.class,放回jar包覆盖原先的class文件就行了。

最后是验证。我在我的机器上将时间调到2006年8月,启动IDEA,虽然界面仍显示“Expiration date: September, 1, 2005”,但是IDE依然正常工作,破解成功

补充一句,在验证时需要了解操作系统中的其它软件是否对系统时间更改有保护性措施。像在我的机器上将时间调后1年后,卡巴斯基就过期了,将时间调回来后卡巴斯基被锁死,保持过期状态,最后只能重装。所以大家在调系统时间的时候可要考虑周到啊。


-- EOF --

除非注明(如“转载”、“[zz]”等),本博文章皆为原创内容,转载时请注明: 「转载自程序员的信仰©」
本文链接地址:IDEA破解过程

分享

  • 点击分享到 Facebook (在新窗口中打开) Facebook
  • 点击以分享到 X(在新窗口中打开) X
  • 更多
  • 点击分享到Reddit(在新窗口中打开) Reddit
  • 点击分享到Telegram(在新窗口中打开) Telegram
  • 点击以在 Mastodon 上共享(在新窗口中打开) Mastodon

赞过:

赞 正在加载……

相关

Today on history:

【2011】About "IBM Rational XML ODBC Driver could not be loaded due to system error 126" when Integrating ClearQuest with Insight
【2009】终于找到一个可看的FF皮肤
Posted in: 技术生活 Tagged: alloy, java, 破解
← 腾讯七宗罪 [zz]
适配器模式(Adapter) →

android (9) apple (20) augmentum (9) Beijing (21) bt (8) career (28) coding (38) firefox (10) google (36) hibernate (11) ibm (11) iphone (10) java (93) linux (16) m$ (26) mac (58) macos (27) nazca (9) olympics (8) oo (8) playstation (10) rip (8) Shanghai (39) spring (9) tips (45) tommy emmanuel (8) ubuntu (12) usa (23) windows (9) 北航 (17) 博客 (29) 吐槽 (8) 周末 (9) 和谐社会 (26) 小资 (11) 愤青 (40) 方言 (10) 朋友 (77) 歌词 (8) 烟酒不分家 (18) 爱国 (19) 爱情 (8) 犯二 (15) 破解 (8) 足球 (11)

烫手山芋

  • 再谈苹果的输入法:这一次是靠OS X自带的输入法来翻身的~ - 被踩了 27,459 脚
  • 生活,就是一个期待跟着一个期待 - 被踩了 21,360 脚
  • 星巴克饮品缩写大全(Starbucks Drink ID Codes)[zz] - 被踩了 18,420 脚
  • 从一个全角冒号说一下我为什么不感冒iOS - 被踩了 14,336 脚
  • 有关Character.isLetter()和Character.isLetterOrDigit() - 被踩了 13,592 脚

刚拍的砖

  • leo 发表在《再谈苹果的输入法:这一次是靠OS X自带的输入法来翻身的~》
  • 花 发表在《再谈苹果的输入法:这一次是靠OS X自带的输入法来翻身的~》
  • 无名氏 发表在《从一个全角冒号说一下我为什么不感冒iOS》
  • Jay 发表在《Mac OS geek级问题》
  • Wei Wang 发表在《再谈苹果的输入法:这一次是靠OS X自带的输入法来翻身的~》

随便看看

  • Adium 消息样式 – Mochastyle5 年 ago
  • 欢迎各位来上海20 年 ago
  • Mac OS geek级问题5 年 ago
  • 优秀的程序员20 年 ago
  • Sun 卖了……9 年 ago

文以类聚

光阴似箭

其他操作

  • 登录
  • 条目 feed
  • 评论 feed
  • WordPress.org

Copyright © 2025 程序员的信仰.

Jay's Omega WordPress Theme by Jay

 

正在加载评论...
 

    %d