上周在springside上看到jira这个团队软件,下载下来试用了一番,觉得挺好用得,正好前一段看到了jad这个反编译软件,就想试手一下自己破解这个jira。下面详细叙述了破解的过程,因为不太熟悉这个破解,只是以前大概知道,几乎没有用过所以想试手一下。整个过程花费了昨天晚上一晚上,从6点多到11点,总算破解好了。
先说一下我用得工具吧
eclipse3.2,这个就不用说了吧,主要是试一下3.2的新特性,用3.1也可以的
winrar 解压*.jar文件
然后就是我关键的工具了, Jad 1.5.8e for Windows 9x/NT/2000 on Intel platform
其实我最开始使用的不是这个版本,而是1.5.7然后再破解的过程中,反编译java文件总是有问题,说
JavaClassFileParseException: Class file version mismatch
Parsing atlassian-extras-0.7.19/com/atlassian/license/applications/perforceplugi
n/PeforcePluginLicenseTypeStore.class...The class file version is 47.0 (only 45.
3 and 46.0 are supported)
然后就去google了一下,发现原来是jad的版本问题,所以到http://www.kpdus.com/jad.html#download 下载了最新的JAD,就是1.5.8e这个版本。
下面说一下我破解的过程吧,首先,我们可以使用评估版本的license搭建并且跑起来jira,那么可以看到在每一个具体页面底部,都可以看到一个license信息。既然这个页面可以看到license信息,那么,这个文件肯定最终是去读取了license文件信息的,那么具体逻辑是在哪里呢,我就看了一下web.xml,可以知道,jira是使用sitemath来做页面布局的,具体查看 sitemath.xml以及相应的 decorator.xml,可以知道每个页面底部几乎都是使用 footer.jsp来显示的
打开footer.jsp,可以看到最初几句
1
7
看到其中com.atlassian.license. *,那么我们可以猜测,具体的license就应该与这个相关了
在 footer.jsp 中可以发现下面这句
License curLicense
=
null
;
if
(JiraLicenseUtils.isLicenseSetup())
curLicense
=
LicenseManager.getInstance().getLicense(JiraLicenseUtils.JIRA_LICENSE_KEY);
使用如下命令行,反编译atlassian-extras-0.7.19.jar包(注:这个包JIRA 3.6破解
http://www.blogjava.net/martinx/archive/2006/05/07/44914.html 这篇文章也提到了,但是没有给出如何确定这个包的,其实可以通过eclipse的工程,把整个工程加载,包括类库,然后就可以看到类层次结构了,然后就可以知道具体在那个包了)
jad -o -r -sjava -dsrc atlassian-extras-0.7.19/**/*.class
这样可以把整个atlassian-extras-0.7.19.jar包下的文件都反编译,然后我把反编译的结果java文件导入到了eclipse,新建了一个工程,这样方便后续的处理和查找以及编译等等。
接着,从反编译出来的
JiraLicenseUtils.java 可以发现如下定义
public
static
final
String JIRA_LICENSE_KEY
=
"
JIRA
"
;
分析这一句
curLicense
=
LicenseManager.getInstance().getLicense(JiraLicenseUtils.JIRA_LICENSE_KEY);
主要是 LicenseManager 的 getLicense 方法
License license
=
LicenseDecoder.getLicense(pair, applicationName);
licenseList.put(applicationName, license);
可以看出,是通过 LicenseDecoder 类得到 License 方法的,后面一句是作缓存。
在继续跟踪 LicenseDecoder
可以发现是通过
License loadLicense(LicensePair pair, PublicKey publicKey, String applicationName)
方法来初始化 License 的
继续看下去,可以发现只有这一句具体实例化了一个 Lisence
return
new
DefaultLicense(dateCreated, datePurchased, organisation, licenseType, users, partnerName, licenseId);
到现在,就已经定位到具体的License类了,但是具体是不是这个类呢,这时候就是使用eclipse强大的功能的时候了
使用classic search,如下,可以发现声明中有License的,大约有7、8个类,具体看一下,可以发现仅有刚才的DefaultLIcense是继承了License接口的,那么可以基本确定就是这个类了。
![](https://i-blog.csdnimg.cn/blog_migrate/5f22d85dbafc63f8e380c85463df3159.jpeg)
但是,又不是很放心,所以又在License接口上如下查看了一下
![](https://i-blog.csdnimg.cn/blog_migrate/0949af2699d3aa32d1b869f90af28773.jpeg)
这个两个综合,可以印证一个思想,就是所有的License只有一个实现,就是DefaultLicense,那么,问题就好办了,只要修改DefaultLicense类文件就可以了
看看反编译的文件,知道License接口如下,在具体看一下License接口:
1
public
interface
License
2
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
2
{
3
3
4
4 public abstract Date getDateCreated();
5
5
6
6 public abstract Date getDatePurchased();
7
7
8
8 public abstract String getOrganisation();
9
9
10
10 public abstract LicenseType getLicenseType();
11
11
12
12 public abstract boolean isExpired();
13
13
14
14 public abstract Date getExpiryDate();
15
15
16
16 public abstract String toString();
17
17
18
18 public abstract boolean isLicenseLevel(Collection collection);
19
19
20
20 public abstract int getUsers();
21
21
22
22 public abstract String getPartnerName();
23
23
24
24 public abstract String getLicenseId();
25
25}
26
可以猜想,修改这个接口的实现,使其返回我们需要的值,那么就可以绕过License验证了。另外,我们注意到
public abstract LicenseType getLicenseType();
这个方法,返回值是LicenseType,大概就是我们不同的License类型的一个区别吧,突然想到,其实把这些LicenseType都改成JIRA_ENTERPRISE_FULL_LICENSE几乎类似的,那么也可以绕过这个,不过这个没有具体试过,有兴趣的可以一试。
public
class
JiraLicenseTypeStore
extends
LicenseTypeStore
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
2
{
3
4 public JiraLicenseTypeStore()
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
5
{
6 applicationLicenseTypes.add(JIRA_STANDARD_ACADEMIC);
7 applicationLicenseTypes.add(JIRA_STANDARD_EVALUATION);
8 applicationLicenseTypes.add(JIRA_STANDARD_NON_PROFIT);
9 applicationLicenseTypes.add(JIRA_STANDARD_FULL_LICENSE);
10 applicationLicenseTypes.add(JIRA_PROFESSIONAL_ACADEMIC);
11 applicationLicenseTypes.add(JIRA_PROFESSIONAL_EVALUATION);
12 applicationLicenseTypes.add(JIRA_PROFESSIONAL_NON_PROFIT);
13 applicationLicenseTypes.add(JIRA_PROFESSIONAL_FULL_LICENSE);
14 applicationLicenseTypes.add(JIRA_ENTERPRISE_ACADEMIC);
15 applicationLicenseTypes.add(JIRA_ENTERPRISE_EVALUATION);
16 applicationLicenseTypes.add(JIRA_ENTERPRISE_NON_PROFIT);
17 applicationLicenseTypes.add(JIRA_ENTERPRISE_FULL_LICENSE);
18 }
19
20 public Collection getAllLicenses()
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
21
{
22 return applicationLicenseTypes;
23 }
24
25 public String getPublicKeyFileName()
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
26
{
27 return publicKeyFileName;
28 }
29
30 public String getPrivateKeyFileName()
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
31
{
32 return privateKeyFileName;
33 }
34
35 public static LicenseType JIRA_STANDARD_ACADEMIC = new DefaultLicenseType( 197 , " JIRA Standard: Academic " , false , false );
36 public static LicenseType JIRA_STANDARD_EVALUATION = new DefaultLicenseType( 109 , " JIRA Standard: Evaluation " , true , false );
37 public static LicenseType JIRA_STANDARD_NON_PROFIT = new DefaultLicenseType( 157 , " JIRA Standard: Non-Profit / Open Source " , false , false );
38 public static LicenseType JIRA_STANDARD_FULL_LICENSE = new DefaultLicenseType( 179 , " JIRA Standard: Commercial Server " , false , false );
39 public static LicenseType JIRA_PROFESSIONAL_ACADEMIC = new DefaultLicenseType( 91 , " JIRA Professional: Academic " , false , false );
40 public static LicenseType JIRA_PROFESSIONAL_EVALUATION = new DefaultLicenseType( 47 , " JIRA Professional: Evaluation " , true , false );
41 public static LicenseType JIRA_PROFESSIONAL_NON_PROFIT = new DefaultLicenseType( 76 , " JIRA Professional: Non-Profit / Open Source " , false , false );
42 public static LicenseType JIRA_PROFESSIONAL_FULL_LICENSE = new DefaultLicenseType( 87 , " JIRA Professional: Commercial Server " , false , false );
43 public static LicenseType JIRA_ENTERPRISE_ACADEMIC = new DefaultLicenseType( 269 , " JIRA Enterprise: Academic " , false , false );
44 public static LicenseType JIRA_ENTERPRISE_EVALUATION = new DefaultLicenseType( 201 , " JIRA Enterprise: Evaluation " , true , false );
45 public static LicenseType JIRA_ENTERPRISE_NON_PROFIT = new DefaultLicenseType( 213 , " JIRA Enterprise: Non-Profit / Open Source " , false , false );
46 public static LicenseType JIRA_ENTERPRISE_FULL_LICENSE = new DefaultLicenseType( 267 , " JIRA Enterprise: Commercial Server " , false , false );
47 public static String publicKeyFileName = " com/atlassian/jira/issue/Bug.class " ;
48 public static String privateKeyFileName = " jira/jira.byte " ;
49
50 }
那么,分析了上述的类,那么,就来修改一下DefaultLicense了,首先把初始化修改一下,如下:
1
public
DefaultLicense(Date dateCreated, Date datePurchased, String organisation, LicenseType licenseType,
int
users, String partnerName, String licenseId)
2
2
{
3
3 Calendar calendar = Calendar.getInstance();
4
4 calendar.set( 1982 , 4 , 21 );
5
5 this .dateCreated = calendar.getTime();
6
6 this .datePurchased = calendar.getTime();
7
7 this .organisation = " escout@sjtu " ;
8
8 this .licenseType = JiraLicenseTypeStore.JIRA_ENTERPRISE_ACADEMIC;
9
9 this .users = 10000 ;
10
10 this .partnerName = partnerName;
11
11 this .licenseId = licenseId;
12
12 }
接着,把修改的DefaultLicense文件,覆盖到atlassian-extras-0.7.19.jar解压开的同名文件处覆盖,同时使用下面的命令重新打包
D:/develope/jadnt157/atlassian-extras-0.7.19>jar cvf atlassianextras-0.7.19.jar
./
然后把修改后的jar放到web-inf/lib目录下覆盖同名文件。重启tomcat,这时候,我本来想应该就可以了,谁知打开浏览器,白屏!没有任何页面显示,ft。
想了想,打开tomcat的log文件,发现如下几行。
2006-05-12 21:26:08,421 ERROR [web.action.util.JiraLicenseUtils] The current license is too old (Mon Jun 14 21:26:05 CST 1982) to run this version (3.6 - Tue Apr 11 00:00:00 CST 2006) of JIRA.
埃,本来想用一个比较有纪念意义的日期呢,看来不能随心所欲啊。
后来又改了一下,最终如下:
1
public
class
DefaultLicense
2
implements
License
3
{
4
5
public DefaultLicense(Date dateCreated, Date datePurchased, String organisation, LicenseType licenseType, int users, String partnerName)
6
{
7
Calendar calendar = Calendar.getInstance();
8
calendar.add(Calendar.DAY_OF_MONTH, - 5 );
9
this .dateCreated = calendar.getTime();
10
this .datePurchased = calendar.getTime();
11
this .organisation = " escout@sjtu " ;
12
this .licenseType = JiraLicenseTypeStore.JIRA_ENTERPRISE_ACADEMIC;
13
this .users = 10000 ;
14
this .partnerName = partnerName;
15
this .licenseId = "" ;
16
}
17
18
public DefaultLicense(Date dateCreated, Date datePurchased, String organisation, LicenseType licenseType, int users, String partnerName, String licenseId)
19
{
20
Calendar calendar = Calendar.getInstance();
21
calendar.add(Calendar.DAY_OF_MONTH, - 1 );
22
this .dateCreated = calendar.getTime();
23
this .datePurchased = calendar.getTime();
24
this .organisation = " escout@sjtu " ;
25
this .licenseType = JiraLicenseTypeStore.JIRA_ENTERPRISE_ACADEMIC;
26
this .users = 10000 ;
27
this .partnerName = partnerName;
28
this .licenseId = licenseId;
29
}
30
31
public Date getDateCreated()
32
{
33
return dateCreated;
34
}
35
36
public Date getDatePurchased()
37
{
38
return datePurchased;
39
}
40
41
public String getOrganisation()
42
{
43
return organisation;
44
}
45
46
public LicenseType getLicenseType()
47
{
48
return licenseType;
49
}
50
51
public String toString()
52
{
53
return licenseType.getNiceName() + " licensed to " + organisation;
54
}
55
56
public boolean isExpired()
57
{
58
return false ;
59
}
60
61
public Date getExpiryDate()
62
{
63
return null ;
64
}
65
66
public String getPartnerName()
67
{
68
return partnerName;
69
}
70
71
public boolean isLicenseLevel(Collection levels)
72
{
73
for (Iterator iterator = levels.iterator(); iterator.hasNext();)
74
{
75
String level = (String)iterator.next();
76
if (getLicenseType().getDescription().toLowerCase().indexOf(level.toLowerCase()) != - 1 )
77
return true ;
78
}
79
80
return false ;
81
}
82
83
public int getUsers()
84
{
85
return - 1 ;
86
}
87
88
public String getLicenseId()
89
{
90
return licenseId;
91
}
92
93
public static long EVALUATION_PERIOD = 0x9fa52400L ;
94
protected Date dateCreated;
95
protected Date datePurchased;
96
protected String organisation;
97
protected LicenseType licenseType;
98
private int users;
99
private String partnerName;
100
private String licenseId;
101
102
}
再次打包放到jira/web-inf/lib/目录下,重启,这下好了,jira license detail显示:
escout@sjtu |
08/五月/06 |
JIRA Enterprise: Commercial Server |
R5AM<<8X9R |
Your commercial JIRA support and updates are available until 09/五月/07. |
哈哈,初次破解成功!!
附记:初次破解,没有多少经验,所以更多记录了一下实际的步骤。后来我测试了一下,当把系统时间更改了之后,Support Period在重启tomcat之后才会更新,所以大概这个状态在运行时是保存在Application对象中的吧