Crack IntelliJ IDEA 5.0 这是一个Java IDE,含有非常好的功能,因此来进行分析。作者:vhly[FR]日期:2006/10/04 - 2006/10/05目标:IntelliJ IDEA 5.0工具:DJ Java Decompiler 3.7.7方法:静态分析、爆破(修改类功能重新编译)简述:当程序执行时,首先检测是否已注册, 如果未注册(如下文件未找到)将执行注册对话框,否则无法使用,没有试用设置 ConfigPath + File.separatorChar + "idea50.key"; ConfigPath + File.separatorChar + "idea40.key"; SystemPath + File.separatorChar + "idea.license"; BinPath + File.separatorChar + "idea.license"; 可以找到注册验证方法,但是由于使用了大数运算的 modPow 方法,进行逆向运算时需要大量时间,因此只进行爆破。操作步骤: 请将Patch_TNT目录下的 LicenseDataImpl_TNT_by_vhly[FR].class重命名为 LicenseDataImpl.class 将改名后的类添加到 idea.jar 文件的 com/intellij/licensecommon/license/ 目录下 运行:完成注册:注意序列号应该是这种个是 XXXXX-XXXXX-XXXXX-XXXXX-XXXXX步骤1:分析注册验证方法1) 寻找程序执行流程 分析bin目录中的idea.bat文件,找出如下语句(用于执行软件) "%JAVA_EXE%" %JVM_ARGS% -cp "%CLASS_PATH%" %IDEA_MAIN_CLASS_NAME% %* 其中JAVA_EXE 指向 java.exe; IDEA_MAIN_CLASS_NAME 指向 com.intellij.idea.Main 因此要分析 com.intellij.idea.Main类的执行过程(IDEA采用了插件的方式,即使是Main类也是用插件管理的方式来运行) Main的执行流程: public static void main(String ... args) 执行软件入口点,该方法调用了插件管理器 PluginManager.main(args, (com.intellij.idea.Main.class).getName(), "start"); 此处执行插件管理器的调用 指定类的指定方法 即:调用 com.intellij.idea.Main类的方法 start() 参数为 args 由此可知 实际上执行了 Main.start(args); protected static void start(String as[]) 可以将这个方法看作类的入口之一 if(!checkStartupPossible()) // 检查版本以及只可以有一个实例 支持 1.4以上 System.exit(-1); ...... // 日志设置 mainImpl(as); // 执行入口点 真正的main的实现 protected static void mainImpl(String as[]) .... // 界面设置 装载本地库 if("Compuware".equals(ApplicationInfoImpl.getShadowInstance().getPackageCode())) // 返回空 LicenseManager.setInstance(new CompuwareLicense()); if("Fabrique".equals(ApplicationInfoImpl.getShadowInstance().getPackageCode())) // 返回空 LicenseManager.setInstance(new FabriqueLicense()); 由于上面的语句不会执行因此 LicenseManager.getInstance() 实际上会返回 IdeaLicense对象 LicenseManager.getInstance().startUp(new com.intellij.ide.license.LicenseManager.StartupAction(as) { // 指定调用 方法 a(String args[]) // 调用验证的方法在此处调用 public void proceed() { Main.a(args); } public void cancel() { System.exit(-1); } }); // 调用startUp方法实际上执行了 proceed()方法 程序流程为 调用 Main类的 a(String args[])方法 private static void a(String as[]) //执行程序 IdeaApplication app = new IdeaApplication(as); // 此处为软件的执行过程 已经没有License验证le SwingUtilities.invokeLater(new Runnable(app) { public void run() { app.run(); } }); LicenseManager实例 对应 LicenseManager.getInstance(); 同时该类是个不完全抽象类 private static LicenseManager a; public abstract boolean supportsRegistration(); // 是否可以注册 public abstract void register(); // 调用注册 public abstract void startUp(StartupAction startupaction); // 执行相应的命令 public abstract String licensedToMessage(); // 显示 License To: public abstract String licensedRestrictionsMessage(); public abstract LicenseFactory createLicenseFactory(); // 设置 LicenseFactory 用于或去注册数据 LicenseData public abstract boolean shouldCheckForUpdates(); // 检测升级 public LicenseManager() { } public static LicenseManager getInstance() { if(a == null) a = new IdeaLicense(); // 默认为 IdeaLicense (包路径com/intellij/ide/license/impl) return a; } public boolean isEap() // what meen the "isEap"? HAHAHAHAAAA { return false; } 通过startUp方法调用 Main.a(args); a(String args[])方法的步骤 IdeaApplication app = new IdeaApplication(as); // 设定IdeaApplication 同时由于 app又是一个 Runnable new Thread(app).start(); // 调用 IdeaApplication类的 run方法 IdeaApplication类的执行流程 protected IdeaApplication(String as[]) // 首先为构造方法 由 Main.a调用 { c = true; // a.assertTrue(d == null); // a 使用了 log4J 的 Logger d = this; b = as; boolean flag = "true".equals(System.getProperty("idea.is.internal")); ApplicationManagerEx.createApplication("componentSets/IdeaComponents", flag, false, "idea"); e = a(); // 返回 属性 com.intellij.appStarter 指定的类 e.premain(as); // 内部类 IdeaApplication$IdeaStarter premain(String args[]) // 方法预处理 final Splash splash = new Splash(ApplicationInfoImpl.getShadowInstance().getLogoUrl()); SwingUtilities.invokeLater(new Runnable() {splash.show();}); 装载开始画面 IdeaApplication.b(); // 调用 IdeaApplication方法 b() // 设置Alloy外观 注意以下为 Alloy 的注册信息 哈哈 AlloyLookAndFeel.setProperty("alloy.licenseCode", "4#JetBrains#1ou2uex#6920nk"); AlloyLookAndFeel.setProperty("alloy.isToolbarEffectsEnabled", "false"); ............... } 调用 IdeaApplication类的 run()方法 public void run() { ApplicationEx applicationex = ApplicationManagerEx.getApplicationEx(); // 装载附加类库 e.main(b); 调用 IdeaStarter 的 main方法 main(String ... args) e = null; } 调用 IdeaStarter类的main方法 public void main(String args[]) ... // 应用程序扩展 ((WindowManagerImpl)WindowManager.getInstance()).showFrame(); // 显示界面 // 此时的程序如果可以执行到这里那么程序就可以使用了但是 LicenseManager 和 IdeaLicense不会让程序执行到上述代码。 2) 分析 LicenseManager、IdeaLicense重点分析 IdeaLicense构造方法public IdeaLicense() { Log.FACTORY = new IdeaLoggerFactory(); d = LicenseFile.create(); // LicenseFile d; 创建授权文件类 便于 存储、读取 MessagePolicy.setMessages(new LicenseMessagesImpl()); // LicenseMessageImpl 包含了全部的授权信息提示 包括出错、过期等信息 g = createLicenseClient(); // ClientImplementation g; // 可以从这个类分析,但是现在没用 NetworkLicenseSource networklicensesource = new NetworkLicenseSource(g); // 网络认证 尚不考虑 a(networklicensesource); a(); // 此处重要 } private void a() { e = new LicenseAuthorizorImpl(); // LicenseAuthorizor 用于授权验证 GetFromUser getfromuser = new GetFromUser(e, createLicenseFactory()); // GetFromUser 包含了通过用户获得的 Name & Key createLicensePolicyBuilder().createRegister(e, getfromuser, this, d, g); // 重要 通过分析这个方法,可以找到验证 // createLicensePolicyBuilder() 返回 PolicyBuild 类 调用 PolicyBuild的如下方法流程: public void createRegister(LicenseAuthorizor licenseauthorizor, GetFromUser getfromuser, LicenseTarget licensetarget, LicenseTarget licensetarget1, LicenseClient licenseclient) { addValidation(licenseauthorizor, getfromuser, licensetarget, licensetarget1, licenseclient); } // 创建注册属性 // addValidation 添加 CheckValid命令类 protected void addValidation(LicenseAuthorizor licenseauthorizor, GetFromUser getfromuser, LicenseTarget licensetarget, LicenseTarget licensetarget1, LicenseClient licenseclient) { licenseauthorizor.addPolicy(new NotNull(getfromuser)); // 注册信息不能为空 LicenseData addPoliciesForValidity(licenseauthorizor, getfromuser); // 检测注册信息是否正确 licenseauthorizor.addPolicy(new CheckNeedUpgrade(getfromuser)); // 检测升级 licenseauthorizor.addPolicy(new CheckEvaluationExpired(getfromuser)); // 检测是否过期 licenseauthorizor.addPolicy(new UserAcceptsLicense(new Cancel())); // 当注册显示正确之后 显示授权内容 用户必须 accept licenseauthorizor.addPolicy(new SaveToTarget(licensetarget)); // 保存授权 licenseauthorizor.addPolicy(new SaveFromUser(licensetarget1)); // 保存授权 licenseauthorizor.addPolicy(new BroadcastUsing(licenseclient)); // 网络认证广播 licenseauthorizor.addPolicy(new CheckWillNeedUpgrade(licensetarget1)); // 检查是否需要升级 licenseauthorizor.addPolicy(new CheckWillExpire()); // 检查是否要过期 licenseauthorizor.addPolicy(new Proceed()); // 执行正常的程序 } // 其中 addPolicy方法就是添加执行的命令 protected void addPoliciesForValidity(LicenseAuthorizor licenseauthorizor, GetFromUser getfromuser) { licenseauthorizor.addPolicy(new CheckCancelled(getfromuser)); // 检查是否被取消 即尚未注册 licenseauthorizor.addPolicy(new CheckValid(getfromuser)); // 检查是否正确 } public class CheckCancelled extends MessagePolicy // 可以暂时不考虑 public class CheckValid extends MessagePolicy { public LicenseData check(AuthorizationAction auth, LicenseData licensedata) throws TerminateCheckException { if(licensedata.isValid()) // 处理 isValid即可 return licensedata; // 着重分析 LicenseData if(licensedata.isFromUser()) getMessages().showLicenseInvalidMessage(); // 显示 出错信息 else getMessages().showLicenseCorruptMessage(); // 显示 推出 return myFail.check(auth, licensedata); } } } public void register() { MessagePolicy.getMessages().setShowLicenseEntryAsDialog(true); // 显示用户注册对话框 MessagePolicy.getMessages().setRegistering(true); e.checkPolicy(new AuthorizationAction() {}); }3) 分析 LicenseDataLicenseData被定义为一个接口public interface LicenseData // 由 LicenseDataImpl 实现 也就是要修改的地方{ public abstract boolean willNeedUpgrade(); public abstract boolean isAccepted(); // 是否接受 public abstract void setAccepted(boolean flag); public abstract boolean needsUpgrade(Date date); public abstract String getKey(); // 获得序列号 public abstract boolean isEvaluationExpired(Date date); // 是否过期 public abstract boolean isValid(); // 重点分析 爆破点 public abstract boolean isFromUser(); public abstract boolean willExpire(); public abstract long getTimeStamp(); public abstract Date getExpirationDate(); // 获得过期时间 如果为 null 则永不过期 public abstract String getUserName(); // 获得注册用户名 public abstract boolean isNonCommercial(); // 注册类型 public abstract boolean shouldDetectDuplicates(); public abstract Date getUpgradeDeadline(); public abstract boolean isPersonal(); // 注册类型 public abstract boolean isYearAcademic(); // 注册类型 public abstract boolean isOpenSource(); // 注册类型 public abstract int getMajorVersion(); // 版本号 public abstract int getProductId(); // 产品id}类 LicenseDataImplpublic class LicenseDataImpl extends AbstractLicenseData{ public static final int CURRENT_MAJOR_VERSION = 5; 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; protected 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() { if(getMajorVersion() >= getCurrentMajorVersion()) return false; if(g.generationDate == null) return true; else return a(g.generationDate, FREE_UPGRADE_DATE); } protected int getCurrentMajorVersion() { return 5; } 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(getUpgradeDeadline())) 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); } public boolean isValid() { a(); return true; // 注意 ******************* 修改之前为 return g != null; } private void a() { if(b()) return; g = new LicenseInfo(); // 修改之前为 g = LicenseDecoder.decodeLicenseKey(s,s1); 用于验证 用户名序列号 g.userName = "vhly[FR]"; // 由于 LicenseInfo 实际为数据类(可以直接修改变量)那么就用这种方法 可以修改为 g.userName = getUserName(); g.customerId = 830213; // My BirthDay is Good Luck! g.licenseType = 0; // isCommercial() => true g.majorVersion = 2; g.minorVersion = 5; g.generationDate = new Date(2006,10,4); // 生成时间 g.expirationDate = null; // 完成爆破 修改 LicenseDataImpl 类之后添加到 idea.jar文件中即可 // 但是第一次的注册还是必须的 } 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 getProductId() { return g.productId; } 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); }}4) 分析注册认证LicenseDecoder 类的验证方法需要使用的常量 private static final BigInteger a = new BigInteger("86f71688cdd2612ca117d1f54bdae029", 16); private static final BigInteger b = new BigInteger("10001", 16); private static final BigInteger c = new BigInteger("846d7cf2385dddd654629dd2ba94ca87", 16); private static final BigInteger d = new BigInteger("10001", 16); private static final BigInteger e = new BigInteger("1030230a52c274c376605b2c1", 16); private static final BigInteger f = new BigInteger("10001", 16); public static LicenseInfo decodeLicenseKey(String name, String key) throws InvalidLicenseKeyException { if(key.length() < 25) return a(name, key); LicenseInfo licenseinfo = new LicenseInfo(); licenseinfo.userName = name; int i = 0; for(int j = 0; j < key.length(); j++) { char c1 = key.charAt(j); if(c1 == '-') i++; } // 寻找 分隔符 - 的个数 if(i != 5 && i != 4) // 必须是4个或者5个 throw new InvalidLicenseKeyException(); if(i == 5) // 当为5个的情况 { int k = s1.indexOf('-'); try { licenseinfo.customerId = Integer.parseInt(s1.substring(0, k)); // 开始的为用户ID 格式 XXXX- s1 = s1.substring(k + 1); // 真正的序列号为后面的4个 - 即格式为 XXXXX-XXXXX-XXXXX-XXXXX-XXXXX } catch(NumberFormatException numberformatexception) { throw new InvalidLicenseKeyException(); } } else //包含4个-的用户Id为-1 { licenseinfo.customerId = -1; } BigInteger biginteger = LicenseUtil.decodeGroups(s1); 将序列号计算成 BigInteger /*调用 public static BigInteger decodeGroups(String s) throws InvalidLicenseKeyException 对于 s1的生成 可以使用 LicenseUtil.encodeGroups(BigInteger big) 使用任意 big */ BigInteger biginteger1 = biginteger.modPow(b, a); // big **(b) mod a 序列号的大数 big 的 b次方 模 a byte abyte0[] = biginteger1.toByteArray(); // 长度必须为12 // 取结果的字节数组 if(abyte0.length != 12) // 在此处目前无法找出长度为 12 的数值 只能到 16 或者 17 if(abyte0.length == 13) { if(abyte0[0] == 0) { byte abyte1[] = new byte[12]; System.arraycopy(abyte0, 1, abyte1, 0, 12); abyte0 = abyte1; } else { throw new InvalidLicenseKeyException(); } } else if(abyte0.length < 12) { byte abyte2[] = new byte[12]; System.arraycopy(abyte0, 0, abyte2, 12 - abyte0.length, abyte0.length); abyte0 = abyte2; } else { throw new InvalidLicenseKeyException(); } // 由于 使用了 modPow方法 对于逆向求解我还未找到相应的解法!!!!!!!!!! need Help!!!!!!!!!!!!!!!!1 if(name != null) { short word0 = LicenseUtil.calculateCheckSum(name, licenseinfo.customerId, abyte0); // 计算校验和 //对于生成的数组 最后两位不会参与 CRC32计算 // 也就时说 计算完 word0之后再设置 if(abyte0[10] != (byte)(word0 & 0xff)) // [10] = word0 & 0xff throw new InvalidLicenseKeyException(); if(abyte0[11] != (byte)(word0 >> 8 & 0xff)) // [11] = word0 >> 8 & 0xff throw new InvalidLicenseKeyException(); } licenseinfo.licenseType = abyte0[0] >> 4; // 0 - 5 licenseinfo.productId = abyte0[0] & 0xf; // 5 licenseinfo.minorVersion = abyte0[1] >> 4; // 2 licenseinfo.majorVersion = abyte0[1] & 0xf; // 5 long l = ((long)abyte0[2] & 255L) + (((long)abyte0[3] & 255L) << 8) + (((long)abyte0[4] & 255L) << 16) + (((long)abyte0[5] & 255L) << 24) << 16; licenseinfo.generationDate = new Date(l); // 4个字节 的long 作为创建时的时间数 int i1 = (abyte0[6] & 0xff) + ((abyte0[7] & 0xff) << 8); // 0 为0 则证明 永不过期 if(i1 != 0) licenseinfo.expirationDate = new Date(l + (long)i1 * 24L * 60L * 60L * 1000L); return licenseinfo; // 返回生成的 LicenseInfo 对象 如果执行成功 证明 验证正确 }完整的注册流程String name,key;if(key has 5 '-') getCustomerId(the first XXXXX) key = substring(4 -)end iflong sum = 0long temp = 0x39aa400Lfor x each - splite key // BigInteger LicenseUtil.decodeGroups(String key) // 每一个 XXXXX 从最后一格 XXXXX开始向前循环 int k = decodeGroup(XXXXX) sum *= temp sum += kend forsum**b mod a => sum.modPow(b,a) -> resultresult -> toByteArray -> bufbuf .length must 12short crcsum (name, id, buf) buf的最后2位不参与运算 用于保存计算出的 crc校验和 0 1 2 3 4 5 6 7 8 9 10 11T I MI MA D D D D E E X X S S生成的字节数组格式T 4bit 授权类型 0 - 5I 4bit 产品ID 5MI 4bit min Version 5MA 4bit maj Version 2D D D D 4Bytes 创建时间E E 2Bytes 过期时间 0 永不过期X X 2Bytes unknown 未知S S 2Bytes CRC32 校验和function decodeGroup(XXXXX) : return intint k =0 for each X in XXXXX // 逆序运算 X = X to number // if '0' -> 0; '9' -> 9; 'A' -> 'A' -65 +10 k *= 36 k += X end for取 一个数的 三十六进制数值end function6) 猜测的注册机方法public String genKey(String name, int cid){ byte buf[] = new byte[12]; buf[0] = 5; buf[1] = 0x52; long l = System.currentTimeMills(); l >>= 16; buf[2] = l & 0xff; buf[3] = l >> 8 & 0xff; buf[4] = l >> 16 & 0xff; buf[5] = l >> 24 & 0xff; buf[6] = 0; buf[7] = 0; buf[8] = 1; buf[9] = 1; short word = LicenseUtil.calculateCheckSum(name, id, buf); buf[10] = word & 0xff; buf[11] = word >> 8 & 0xff; BigInteger bt = new BigInteger(buf); // 计算出了 结果 x**b mod a = bt (bt = x.modPow(b,a)); x = ? // 尚未找出正确的序列号 BigInteger bigKey = ? String key = LicenseUtil.encodeGroups(bigKey); if(cid == -1) return key; else key = Integer.toString(cid).toUpperCase()+key; return key;}10月10日,经过这几天的分析。我终于发现实际上序列号,是使用RSA的方法计算的主要是用户序列号 S (BigInteger)授权信息 I (BigInteger) toByteArray()-〉授权数据其中 LicenseDecoder中的 BigInteger a 为RSA公钥的指数部分 LicenseDecoder中的 BigInteger b 为RSA公钥的指数部分由于 IntelliJ 公司有 RSA 的私钥,所以只有 该公司才可以生成符合格式的序列号。对于这种方式,我们需要将 a,b替换为我们的公钥参数,并且使用我们的私钥参数(e, b)执行序列号生成byte [] buf = .... // 根据格式生成授权数据BigInteger I = new BigInteger(buf);BigInteger S = I.modPow(b, e); // 生成我们的 S序列号数值String serial = LicenseUtil.encodeGroups(S);完成
转载请注明原文地址: https://ibbs.8miu.com/read-11787.html