`
conkeyn
  • 浏览: 1507297 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

JRebel 2.x 破解

    博客分类:
  • Java
阅读更多

最近几天开发公司的项目,发现重启成了一个很大的问题,服务器端JS、Freemarker脚本、Java类,随便修改点东西就需要重启服务,在公司一般2分钟能起一次,在家里起一次得20分钟(连得公司数据库)
突然想起很久以前看的Java Rebel这个获了Jolt大奖的东东,遂去官网下载了最新版,果然不错
可惜只有30天的Trial,毛爷爷说的自己动手、丰衣足食,那么就破吧。。。

虽然标题写的是2.x,但不表示真的是所有的2.x版本都能破解,至少到我这里2.1.1-nightly还是可以的
因为我这个人总是喜欢用最新版的,而网上大家提供的都是之前的老版本
加之觉得授人以鱼不如授人以渔,干脆把破解过程写下来,这样大家以后总是可以用到破解的最新版,不是很爽?
废话少说,下面就开始吧

首先,自然是去官网上下载最新的JRebel的代码

然后自然是在本机的服务上试试看效果,比如用的是否舒服啦之类的,使用方法这里就不介绍了,网上大把的文章

第三步是找个反编译工具把整个jar包都反编译过来,我用的是http://java.decompiler.free.fr/ ,图形化界面,还算方便。
不过这里需要注意一点,反编译的产物由于被混淆过,所以会有类似a.java和A.java的产物,如果在Windows下面,由于不区分大小写,这两个文件会互相覆盖,因此最好是找台Linux的机器来做这个事情会比较方便点

第四步就要用到第二步的东东了,如果我们平时使用下载的evaluation版本启动项目时,会出现一行字“You are running JRebel evaluation license”,拿着这段字在所有的源码包里查找,虽然是混淆,但是字符串是不会变的
我找到了一个叫jZ.java的类,你找到的可能与我的名字不同,这是混淆器弄的

第五步自然就是看懂这个类及其周边类了,如果你比较懒不想看,可以跳过这步,直接按照我下面的办法来做就行
这个类的代码我就不贴了,最终结果就是,根据这个类及其周边类的代码,我总结出了第六步代码

第六步,将下面这段充满try/catch的恶心的代码复制到本地执行,执行时保证jrebel.jar在CLASSPATH中

package com.baidu.jrebel.crack;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Map;

import com.zeroturnaround.licensing.UserLicense;

/**
 *
 * LicenseParser
 *
 * @author GuoLin
 *
 */
public class LicenseParser {

    private UserLicense userLicense;

    private Map<String, Object> licenseMap;

    /**
     * 从一个classpath中的license文件中加载数据.
     * @param filename 在classpath中的文件名
     */
    public LicenseParser(String filename) {
        userLicense = getLicense(filename);
        licenseMap = buildMap(userLicense.getLicense());
    }
   
    /**
     * 修改licenseMap的值.
     * @param key 键
     * @param value 值
     */
    public void set(String key, Object value) {
        licenseMap.put(key, value);
    }
   
    /**
     * 移除licenseMap的键值对.
     * @param key 键
     */
    public void remove(String key) {
        licenseMap.remove(key);
    }

    /**
     * 将License存储到新的文件中.
     * @param newFilename 新文件名
     */
    public void store(String newFilename) {
        // 将Map中的值写入UserLicense对象
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = null;
            try {
                objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
                objectOutputStream.writeObject(licenseMap);
                userLicense.setLicense(byteArrayOutputStream.toByteArray());
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            } finally {
                try {
                    objectOutputStream.close();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        } finally {
            if (byteArrayOutputStream != null) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }

        // 保存UserLicense的值到文件
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(new BufferedOutputStream(
                    new FileOutputStream(newFilename)));
            objectOutputStream.writeObject(userLicense);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        } finally {
            if (objectOutputStream != null) {
                try {
                    objectOutputStream.close();
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
    }

    public String toString() {
        return licenseMap.toString();
    }

    /**
     * 从文件中进行反序列化到UserLicense类.
     * @param filename 文件名,CLASSPATH下
     * @return 反序列化完成的UserLicense对象
     * @throws Exception
     */
    private static UserLicense getLicense(String filename) {
        ObjectInputStream licenseFileObjectInputStream = null;
        try {
            licenseFileObjectInputStream = new ObjectInputStream(ClassLoader
                    .getSystemClassLoader().getResourceAsStream(filename));
            return (UserLicense) licenseFileObjectInputStream.readObject();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        } finally {
            if (licenseFileObjectInputStream != null) {
                try {
                    licenseFileObjectInputStream.close();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
    }

    /**
     * 根据license的字节码获取最终的Map.
     * @param licenseBytes 字节码流
     * @return 由字节码流反序列化后的Map
     */
    @SuppressWarnings("unchecked")
    private static Map<String, Object> buildMap(byte[] licenseBytes) {
        ObjectInputStream localObjectInputStream = null;
        try {
            localObjectInputStream = new ObjectInputStream(
                    new ByteArrayInputStream(licenseBytes));
            return (Map<String, Object>) localObjectInputStream.readObject();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        } finally {
            if (localObjectInputStream != null) {
                try {
                    localObjectInputStream.close();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        LicenseParser parser = new LicenseParser("jrebel.lic");
       
        // 显示内容
        System.out.println(parser.toString());
       
        // 修改各类属性,参考反编译后的代码中搜索"Seats"结果所在文件的逻辑
        Calendar cal = new GregorianCalendar(2020, 01, 01);
        parser.set("validUntil", cal.getTime());  // 过期时间
        parser.set("Seats", "Unlimited");
        parser.set("Organization", "IIT Xiaoheiwu");
        parser.set("Comment", "Congratulations! I have bean cracked!");
        parser.set("commercial", "true");
        parser.remove("limited");
       
        // 显示内容
        System.out.println(parser.toString());
       
        parser.store("D:/jrebel.lic");
    }

}
 

以上代码主要是有了一个将license文件加载->修改->保存的过程,如果想知道为什么要修改那些参数,请回到第五步,这里就不多说了
如果执行正常,那么最终会在D:/上生成一个jrebel.lic文件,这个就是我们新的License文件 

到这里还没完,因为虽然我们生成了一个新的License文件,但是代码中会对这个文件做签名验证,那么我们下一步需要去掉这个签名

在第四步所指的类中,找到类似这样的代码(可以根据"Product"字符串进行查找):

if (AClass.aMethod(localUserLicense)) {
  x = 1;
}
...
if ((!("JavaRebel".equals(localMap.get("Product")))) && (!("JRebel".equals(localMap.get("Product"))))) {
  x = 0;
}
 

注意这段中的几个有黄底的地方,x表示一个变量,这个变量用于标识License的种类,AClass.aMethod是调用AClass这个类上 的一个静态方法(类名和方法名由于被混淆会不同,例如我的是eY.a(localUserLicense)),这个if语句实际是表示签名是否通过,如果 通过就x=1否则x默认为0,0表示非法License

明白了以上这些,现在很简单了,在同包下找到AClass类(对于我来说是eY,对于你来说可能是任何值,这也是上面一段之所以要说明一下的原因),找到aMethod方法(可能有很多同名方法,找到参数、返回值都匹配的方法),方法描述大致如下

public static boolean aMethod(UserLicense paramUserLicense) throws Exception

本来是只需要简单的将这个方法中的所有代码删除并大方的写上return true;就万事大吉的,但我反编译出来的类中有两个同名的aMethod方法(参数相同),编译不过去了,只好再深一步

在这个方法中主要是调用了另一个类(暂时称为BClass),遂找到BClass类,发现这个类太适合伪造了——没有同名public方法,所有public方法只有一个需要返回boolean值,其他均无需返回值
大方的将其所有private方法删除,将其所有private成员变量删除,将所有的public方法的内容全部删除,需要返回boolean的方法直接return true;

于是代码改造完成,接下来编译BClass类:

javac com/zeroturnaround/javarebel/BClass.java -cp ../jrebel.jar

 再用WinRAR之类的东东将我们本次产物BClass.class文件和第六步生成的jrebel.lic文件复制到jar包中对应的位置中覆盖原有的文件

大功告成!重启Tomcat试试吧,哈哈哈

 

分享到:
评论
1 楼 gkbusy 2010-06-27  
google搜索看到了另外一篇更早的文章:
http://fallenlord.blogbus.com/logs/51703120.html

如果是转载,还是注明一下出处吧

另外破解版的东西用在商业用途上,这是不可取的,在JE这样严肃的技术论坛里是不应该宣扬的做法

真的听毛爷爷的话,就应该自己动手解决开发效率问题,有兴趣,可以关注我七月份的文章,将就这一块适当地进行展开探讨(之所以说“适当”是因为热加载在JVM上是不给予实现的,JAVA官方的规范和论坛里已经明确回应过,所以我们得另想办法)

相关推荐

    myeclipse热部署jrebel6.5.0

    Tomcat 7.x --&gt;JDK 配置jvm参数: -noverify -javaagent:D:\myeclipse\jar\jrebel6.5.0\jrebel.jar -Drebel.dirs=${project_loc}\WEB-INF\classes -Drebel.spring_plugin=true -Drebel.struts2-plugin=true -...

    JRebel 7.0.14离线安装包及7.X破解

    亲测可用 时间到2017 Oct.31. 将破解包解压后放在C:\Users\Administrator下即可,原先的.jrebel文件夹注意备份。 如果是离线PC,到期了可以调整系统日期继续使用。 如果是联网PC,建议使用其他联网方式验证。

    JRebel 7.x + SpringBoot 1.5.2.RELEASE BUG 启动报错解决方案-附件资源

    JRebel 7.x + SpringBoot 1.5.2.RELEASE BUG 启动报错解决方案-附件资源

    myeclipse 插件热部署 jrebel6.5

    Tomcat 7.x --&gt;JDK 配置jvm参数: -noverify -javaagent:D:\myeclipse\jar\jrebel6.5.0\jrebel.jar -Drebel.dirs=${project_loc}\WEB-INF\classes -Drebel.spring_plugin=true -Drebel.struts2-plugin=true -...

    jrebel最新eclipse插件离线包update-site.zip(2020.1.1),支持springboot2

    jrebel官网下载update-site.zip包时超级慢,还可能下载不下来,经过多次努力终于成功了,分享给大家,希望能有帮助。本包安装完后,Jrebel agent是2020.1.1,算是最新版了,支持springboot2.X

    jrebel6.4.3破解版

    jrebel6.4.3破解版 解压后将jarbel 以及jrebel6下的jar分别覆盖替换eclipse\plugins\org.zeroturnaround.eclipse.embedder_6.X.X.RELEASE下的jrebel和jrebel6的jar ,将lic也复制放在这两个文件夹下,与jar一起

    修改java 不重启tomcat

    修改java 不重启tomcat jrebel 4.x

    maven-jrebel-plugin:为Maven项目生成rebel.xml配置文件

    需要Maven 3.0或更高版本(对于Maven 2.x项目,请使用JRebel Maven插件版本1.1.5)。 有关更多信息,请参阅以下JRebel文档: ://manuals.zeroturnaround.com/jrebel/standalone/maven.html 用法 将以下代码段添加...

    Marven + Jetty + Myeclipse实现java修改实时生效

    2、在myeclipse中配置 输入jetty:run -X 输入-noverify -javaagent:D:/java/spring/jrebel.jar 3、在pom.xml中加入下面信息 &lt;plugin&gt; &lt;groupId&gt;org.zeroturnaround&lt;/groupId&gt; &lt;artifactId&gt;javarebel-...

    springboot-tutorials:codehome出品SpringBoot2.x基础教程

    SpringBoot2.x基础教程 已完成系列

    topfox快速开发平台例子 topfox-sample.zip

    在 srpingboot2.x.x 和MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 编程规范参考《阿里巴巴Java开发手册》 借鉴mybaties plus部分思想 特性: - **无侵入**:只做增强不做改变,引入它不会对...

    topfox快速开发框架

    在 srpingboot2.x.x 和MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 编程规范参考《阿里巴巴Java开发手册》 借鉴 mybaties plus 部分思想 特性: 无侵入:只做增强不做改变,引入它不会对现有...

    myhippoproject:河马CMS示例项目

    日志位于 target/tomcat7x/logs 楼宇分布 要构建仅包含可部署工件的 Tomcat 发行版 tarball: mvn clean verify mvn -P dist 如果您需要自定义分发,另请参阅 src/main/assembly/distribution.xml。 使用 JRebel ...

    常用的 IntelliJ IDEA 插件

    3. Key Promoter X:当您使用IDEA时,它将显示快捷键操作后面的悬停层,以帮助您加快工作效率并建立记忆功效。 4. Markdown Navigator:提供对 Markdown 文件的全面支持,在编辑器内提供渲染预览和文件系统导航等...

    JavaEE开发的颠覆者SpringBoot实战[完整版].part2

    在当今Java EE 开发中,Spring 框架是当之无愧的王者。而Spring Boot 是Spring 主推的基于“习惯优于配置”的原则,让你能够快速搭建应用的框架,从而使得Java EE 开发变得异常简单。...A.2 常用应用属性配置列表 488

    spring-x-ssm:SSMShiroESAMQLog4j2DruidquartzSwagger2MyBatis-plus等

    spring-x-ssm SSM/Shiro/ES/AMQ/Log4j2/Druid/quartz/Swagger2/MyBatis-plus等 1.使用方法: 一:导入eclipse/idea. 二:导入sql. 三:更改数据库连接,运行.(初始账号:admin密码:123) 2.所用技术. SSM Shiro ES 验证码...

    jr-ide-idea-6.3.1-idea-13-15附带破解账户

    实测IntelliJ IDEA 2017.2 x64可用,离线安装插件后,可实现IntelliJ热部署

    JavaEE开发的颠覆者SpringBoot实战[完整版].part3

    在当今Java EE 开发中,Spring 框架是当之无愧的王者。而Spring Boot 是Spring 主推的基于“习惯优于配置”的原则,让你能够快速搭建应用的框架,从而使得Java EE 开发变得异常简单。...A.2 常用应用属性配置列表 488

    JavaEE开发的颠覆者SpringBoot实战[完整版].part1

    在当今Java EE 开发中,Spring 框架是当之无愧的王者。而Spring Boot 是Spring 主推的基于“习惯优于配置”的原则,让你能够快速搭建应用的框架,从而使得Java EE 开发变得异常简单。...A.2 常用应用属性配置列表 488

Global site tag (gtag.js) - Google Analytics