一.启动环境
JEB 2.0Demo版本启动后出现这样一个界面
当前环境算出的许可证数据
48000000BDEAE192E4CEFC82B34C2AC67F3A85DF5C0E262E421772CF84F18EC0E4A9F41798FD1648BF2794B4545F6315D6AC21C3921172C29FA004FAE1A8127C585A37F27FC478F9187BD35BBD7BA0DE
根据经验来看,肯定是机器码和注册码经过特定的运算,运算通过就注册成功
二. 分析过程
1. 定位关键点
在main函数我们发现启动时会先回去License相关信息,我们跟进这个函数
在跟进的AbstractClientContext类中我们发现
这里比较像注册码比较的地方
上面的this.uomid 点击不进去, 搜索也搜索不到, 一般情况这个成员的值定义可能在父类
我们父类跟踪该值this.uomid,果然找到相关初始化地方
跟踪最终的初始化,发现其在该函数进行初始化过程
看起来很像算机器码的地方, 我们可以高度怀疑上面的过程就是注册码检查校验的过程了
2. 先还原机器码算法
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
public final class MachineHelper {
private String GetWinSerialNum() {
Process locProcess;
String serial = null;
Runtime locRuntime = Runtime.getRuntime();
try {
locProcess = locRuntime.exec("wmic bios get serialnumber".split(" "));
Scanner scanner = new Scanner(locProcess.getInputStream());
while (scanner.hasNext()) {
if ("SerialNumber".equals(scanner.next())) {
serial = scanner.next().trim();
break;
}
}
scanner.close();
} catch (IOException e) {
}
return serial;
}
@SuppressWarnings("null")
private String GetMacSerialNum() {
Process locProcess;
String serial = null;
Runtime locRuntime = Runtime.getRuntime();
try {
locProcess = locRuntime.exec("/usr/sbin/system_profiler SPHardwareDataType".split(" "));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(locProcess.getInputStream()));
String buffer = null;
while ((buffer = bufferedReader.readLine()) != null) {
if (buffer.indexOf("Serial Number") >= 0) {
String buf1 = buffer.split("Serial Number")[1];
int iPoint = buf1.indexOf(":");
if (iPoint >= 0) {
serial = serial.substring(iPoint + 1).trim();
}
break;
}
}
} catch (IOException e) {
}
return serial;
}
private String GetLinuxSerialNum() {
String serial = null;
try {
BufferedReader midFilebuf = new BufferedReader(new InputStreamReader(new FileInputStream("/var/lib/dbus/machine-id")));
String buffer = midFilebuf.readLine();
midFilebuf.close();
if (buffer != null) {
serial = buffer.trim();
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
return serial;
}
private String GetLinuxSerialNum2() {
String serial = null;
try {
BufferedReader fstabFilebuf = new BufferedReader(new InputStreamReader(new FileInputStream("/etc/fstab")));
String buffer = null;
while ((buffer = fstabFilebuf.readLine()) != null) {
buffer = buffer.trim();
if (buffer.length() == 0) {
continue;
}
if (buffer.startsWith("#")) {
continue;
}
String[] Keyvalue = buffer.split("[ \t]+");
if (Keyvalue.length < 2) {
continue;
}
if (!Keyvalue[1].equals("/")) {
continue;
}
buffer = Keyvalue[0];
if (buffer.startsWith("UUID=")) {
serial = buffer.substring(5);
} else if (buffer.startsWith("LABEL=")) {
serial = buffer.substring(6);
}
if (serial != null) {
serial.toLowerCase();
}
}
fstabFilebuf.close();
} catch (FileNotFoundException e) {
} catch (IOException e) {
e.printStackTrace();
}
return serial;
}
public long GetMachineID() {
String osType = System.getProperty("os.name", "");
String SNKey = null;
long machineId = 0;
if (osType.startsWith("Windows")) {
SNKey = GetWinSerialNum();
} else if (osType.startsWith("Mac")) {
SNKey = GetMacSerialNum();
} else if (osType.startsWith("Linux")) {
SNKey = GetLinuxSerialNum();
if (SNKey == null) {
SNKey = GetLinuxSerialNum2();
}
} else {
SNKey = "LambdaLambda";
}
try {
MessageDigest md = MessageDigest.getInstance("MD5");
ByteBuffer buffer = ByteBuffer.wrap(md.digest(SNKey.getBytes()));
buffer.order(ByteOrder.LITTLE_ENDIAN);
machineId = buffer.getLong() & 0xFFFFFFFF;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return machineId;
}
public static void main(String[] args) {
MachineHelper helper = new MachineHelper();
System.out.println(helper.GetMachineID());
}
}
解密后
3. 注册算法分析
当v2_1 != 0时 校验通过
当v6 == v8时校验通过
向上跟踪发现v6 v8是根据licenseKey和machineKey分别计算出来的
那么还原licenseKey的算法即可
import java.nio.ByteBuffer;
public class Test {
private static int sum(int i)
{
int j = 0;
for(; i > 0; i >>= 4)
j += i & 0xf;
return j % 10;
}
public static String getKey(long machineId,long unixTime) {
int i = (int)(machineId & 0xFFFFFFFF);
int j = (int)(machineId >> 32 & 0xFFFFFFFF);
int i1 = i + 0x45F22A12 + 0x11223344 & 0xFFFFFFFF;
int j1 = j - 0x1B0CB11 + 0x55667788 & 0x7FFFFFFF;
ByteBuffer bb = ByteBuffer.allocateDirect(8);
bb.putInt(j1);
bb.putInt(i1);
bb.rewind();
long l = bb.getLong();
int d = (int)unixTime ^ 0x56739ACD;
return String.format("%dZ%d%d", l, d, sum(d));
}
public static void main(String[] args) {
MachineHelper helper = new MachineHelper();
long machineID = helper.GetMachineID();
long unixTime = System.currentTimeMillis() / 1000L + 94608000L - 1123200L;
String key = getKey(machineID, unixTime);
System.out.println(helper.GetMachineID());
System.out.println(key);
}
}
计算出key
成功通过运算