JProfiler 4.2 注册分析
作者:舵手
申明:如转载请保证文章的完整性以及出处
摘要:JProfiler是一款Java剖析器。JProfiler直观的用户界面能够帮助你找到性能瓶颈,并指明你的内存漏洞和解决线程问题。
JProfiler是通过EXE来执行,用十六进制编辑器很容易找到程序的入口类:com.jprofiler.frontend.FrontendApplication 如果你要通过命令行运行,得看看这个类的main方法,它需要两个参数才能运行。简单分析了一下该类,发现方法H完成了注册码的验证,让我们顺藤摸瓜找到计算注册码的位置。
public boolean H()
{
E e1 = com.jprofiler.frontend.E.H.A3().A2();
//由于代码经过了混淆,以E命名的类有n多,所以千万要找正确,否则会浪费你的保宝贵时间
//com.jprofiler.frontend.E.D.E——E的完整类路径
int i1 = e1.A(null, this);
switch(i1)
{
case -2:
if(l())
{
System.err.println("Your license key has expired.");
return false;
}
int j1 = A(p, "Your license key has expired.\nIf you were not able to evaluate JProfiler,
please\nrequest a new key at " + L(), new String[] {
"Enter new key", "Send mail"
}, 0);
if(j1 == 1)
{
O();
return false;
}
if(!A(((String) (null)), true))
return false;
break;
case -1:
break;
case -3:
if(!A("Your license key is invalid. Please check your key.", true))
return false;
break;
case -5:
if(!A("There was an error communicating with the license server.\n
Please check your license key.", true))
return false;
break;
case -4:
if(!A("The license server is invalid. \nPlease check your license key.", true))
return false;
break;
case -6:
A(com.jprofiler.frontend.E.D.C.B(), false);
return false;
default:
if(i1 < 0)
throw new RuntimeException("Unknown license status " + i1);
e1.A(i1);
break;
}
e1.AA();
return true;
}
如果让e1.A(null, this)返回-1,那问题就解决了。如果想暴破可以从这个方法入手,我们这里的任务是追出注册算法:)
首先我们跟进com.jprofiler.frontend.E.H.A3().A2();这两个方法,发现只是对类做一些初始化,我们略过。
跟进e1.A(null, this),它又调用了重载方法A
public int A(String s, C._A _pa)
{
return A(s, _pa, true);
}
public int A(String s, C._A _pa, boolean flag)
{
if(s == null)
s = F4; //在该类初始化时已经给F4给了值,如果注册文件存在,该值为注册码
if(flag && !s.startsWith("FLOAT:") && !s.startsWith("S-"))
com.A.A.E.C.A(s, _pa);//跟进这里,发现是网络验证,由于我访问不了IP 228.7.6.9 所以没有详细分析,
//有时间了再补上。如果你那里通不过网络验证,把com.A.A.E.C$_B(C的内部类)里的IP改一下应该就没问题
//可别问我怎么改,十六进制编辑器就可以了:)
return S(s); //我们再看这个方法
}
public int S(String s)
{
if(s == null)
s = F4;//在该类初始化时已经给F4给了值,如果注册文件存在,该值为注册码
if(s.startsWith("FLOAT:")) //不知道这代表什么,直觉上不是好东西,先不进入,直接到else
{
String s1 = s.substring("FLOAT:".length());
int i = -1;
int j = s1.lastIndexOf(':');
if(j > -1)
{
try
{
i = Integer.parseInt(s1.substring(j + 1));
}
catch(NumberFormatException numberformatexception) { }
s1 = s1.substring(0, j);
}
int k = C3();
int l = com.A.A.E.E.A(s1, i, k, C7());
FD = E.C();
D(l > 0 || l == -1);
return l;
} else
{
return Q(s);
}
}
Q(s)直接调用下面方法
public static int G(String s)
{//s为注册码
if(s == null)
return -3;
s = s.trim();
if(s.length() < 3 || s.charAt(1) != '-' || s.indexOf('#') == -1)//长度大于3,第二位字符必须为-,必段有#
return -3;
switch(s.charAt(0))//取注册码中的第一个字符
{
case 69: // 'E' 试用版
int i = A(s);//查检当前日期是否过了试用期
if(!F(s))
return -3;
else
return i;
case 65: // 'A'
case 76: // 'L'//这三个有什么区别还没有搞清
case 83: // 'S'
return H(s); //让这里返回-1
}
return -3;
}
private static int H(String s)
{
if(B(s) != 2)//license串中的"-"必须等于两个,B函数的作用是计算串中的"-"字符的个数
return -3;
return F(s) ? -1 : -3;//这里F必须反回true
}
private static boolean F(String s)
{
A a = new A(s);//传入注册码,进行截取处理
if(!a.E())
return false;
String s1 = a.A();//返回注册码中第二个“-”后的所有字符
String s2 = E(s1);//把上面得到的字符串以“#”为界分开,“#”前的给s2
String s3 = D(s1);//“#”后的给s3
if(s3 == null || s2 == null)
return false;
else
return A(s3, s2, 11, 7, 29);//重点所在
}
protected static boolean A(String s, String s1, int i, int j, int k)
{
char ac[] = s1.toCharArray();“#”前的串转换为char
int l = 0;
char ac1[] = ac;
int i1 = ac1.length;
for(int j1 = 0; j1 < i1; j1++)
{
char c = ac1[j1];
l += c; //累加
}
String s2 = String.valueOf(l % i) + String.valueOf(l % j) + String.valueOf(l % k);
//分别模11、7、29,结果相加,结果要和“#”后的那部分相等
return s.equals(s2);
}
到这里我们已经知道注册的算法了,其实很简单:注册码必须以A、S、L其中一个字母开头,第二个字符必须为“-”,“-”字符必须为两个,至少一个“#”字符,从目前的分析可以看出注册码长度已以大于等于四了,程序代码中<3时完蛋。接下来载取注册码中从第二个“-”字符位置加1开始到“#”前一个字符的子串,转换为char后累加,再分别模11、7、29,把三次模运算的结果相加,这个值等于注册码中“#”后面的所有字符。
下面给写出它的注册机
import java.util.*;
/**
* <p>Title: JProfiler4.2 注册机</p>
* <p>Description: 每执行一次得到一个注册码</p>
* <p>Copyright: Copyright () 2006</p>
* @author 舵手
* @version 1.0
*/
public class jprofiler4_keygen
{
public static void main(String[] args)
{
String s1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
String s2 = "ALS";
String license = "";
String key = "";
Random rd = new Random();
int j = rd.nextInt(3);
license += s2.substring(j,j+1)+"--";
for (int i =0 ; i < 12 ; i++ )
{
j = rd.nextInt(62);
license += s1.substring(j,j+1);
key += s1.substring(j,j+1);
}
license += "#";
char ac[] = key.toCharArray();
int l = 0;
char ac1[] = ac;
int i1 = ac1.length;
for(int j1 = 0; j1 < i1; j1++)
{
char c = ac1[j1];
l += c;
}
String s3 = String.valueOf(l % 11) + String.valueOf(l % 7) + String.valueOf(l % 29);
license += s3;
System.out.println(license);
}
}
通过上面的分析,我们可以用正则表达式表示出注册码[A|L|S]-.-[a-zA-Z0-9]#[0-9],第二个“-”后的字符到“#”字符前的字符串的长度并没有限制,当然,不能为0,我只测试了长度为1和12,计算的注册码都没有问题,有兴趣的可以多试几个:)“.”这个位置可以插入任意长度的任意字符。
从注册算法上说,这个程序的保护很简单,但如果加上混淆和错综复杂的方法调用,会让你头痛好一阵子。这里我只列出了和计算注册码有关的一些方法,而在实际跟踪中,牵扯到的类和方法数量是很大的,这就需要耐心。我一直以来都认为这样的文章对那些想要从这里学到东西的人没有什么用处,因为这种文章充其量只能算是授人以鱼而不是授人以渔。对那些正在分析这个软件的注册算法的人来说,也许有那么一点点用处:)
分析这个软件的注册只是个人爱好,由于水平有限,错误疏漏在所难免,欢迎大家提出宝贵意见!