前言
论坛有人推荐Smart Input插件,试用了一下还不错,但是发现这个玩意居然需要激活,这能忍?
https://linux.do/t/topic/42158?u=crazer
让我看看怎么个事情
一键重新授权
万年不变的试用
这里就是在线激活,那我没网就没得用咯?
我直接一键断网
离线输入假code,哦豁,激活失败。
复制下授权链接,使用ja进行联网屏蔽
https://xiaolvpuzi.cn/smartinput/authorize?uuid=**********************
配置url
[URL]
PREFIX,https://xiaolvpuzi.cn
万能jadx-gui大法直接开干
关键字搜索
找到验证方法直接跳
验证代码解析
看下激活码
H0H2H3wdknJf4Ns5L47Jv51iIqtk5xsu000098MGs3MVNJZzJJMFBVWGQ1MgCGN4x8ISc0CiVlX6w0kj2d9sUmSaHs3/6dmb0Y6P5BQYxY9f8Cj3iXTwBVt2NQ9fOOJNHrEh5SJBybZ6hFuhQkj2dzeBQmudIXetbqyFJFdPg8cXZlufszypQ73hDcFQ==tmZVJJhpHRXu1KZn5M0iIX29yHid0tzBG8N/KLXxbAQ7bEQ9VQ1jK+8qpMBjH0R236kJxBxtuU618C/fFV4YWlCZ5HVfBulc4gFd9grwYm6DdW3/Ux2NcL/EC1DaajrX998TPdxCZxZtwYqOuh8j4AuRsTD3xWj898fRelti/BpUT8MuXTBYwNGMCBl+9N8H+Vu9Y+e3fJHQfR/Sx/T2+pJn55LG9SSDRHW9bOTZlpbMm5Ne6izELapCuEHGYRo66vzFmUXIGMGuX1dACaIYZShZtXBnXtgWR+UcW/KsmFM2xymy0w1CpccbKZLNPW3Cijzltjhq9wIGTjpg+SsCyg==
分割一下
前面是我们要用到的
H0H2H3wdknJf4Ns5L47Jv51iIqtk5xsu000098MGs3MVNJZzJJMFBVWGQ1MgCGN4x8ISc0CiVlX6w0kj2d9sUmSaHs3/6dmb0Y6P5BQYxY9f8Cj3iXTwBVt2NQ9fOOJNHrEh5SJBybZ6hFuhQkj2dzeBQmudIXetbqyFJFdPg8cXZlufszypQ73hDcFQ==
后面这串,在dll会对整个lincese进行校验,具体看 @YeloChick 大佬提供的 Smart Input插件激活原理【仅支持windows】 - #60,来自 YeloChick
tmZVJJhpHRXu1KZn5M0iIX29yHid0tzBG8N/KLXxbAQ7bEQ9VQ1jK+8qpMBjH0R236kJxBxtuU618C/fFV4YWlCZ5HVfBulc4gFd9grwYm6DdW3/Ux2NcL/EC1DaajrX998TPdxCZxZtwYqOuh8j4AuRsTD3xWj898fRelti/BpUT8MuXTBYwNGMCBl+9N8H+Vu9Y+e3fJHQfR/Sx/T2+pJn55LG9SSDRHW9bOTZlpbMm5Ne6izELapCuEHGYRo66vzFmUXIGMGuX1dACaIYZShZtXBnXtgWR+UcW/KsmFM2xymy0w1CpccbKZLNPW3Cijzltjhq9wIGTjpg+SsCyg==
代码解释
启用许可证
这个方法就是验证解密后的数据是否符合一系列规范,符合就返回true激活成功,否则激活失败
public boolean enableLicense(String str) {
try {
String decrypt = decrypt(str);
// 判断解密后是否为空
if (StringUtil.isNullOrBlank(decrypt)) {
return false;
}
long parseLong = Long.parseLong(decrypt.substring(0, 10)) * 1000;
// 判断激活码里面的激活时间是否到期
if (parseLong < System.currentTimeMillis()) {
return false;
}
//判断激活码里面的IJ/AI是否一致
if (!Objects.equals((O00O0o0.O000000o() + "@@@@@@@@@@@@@@@@@@@@@@@@@@@").substring(0, 5), decrypt.substring(10,15))) {
return false;
}
//判断激活码里面的用户名是否一致
if (!Objects.equals((System.getProperty("user.name") + "@@@@@@@@@@@@@@@@@@@@@@@@@@@").substring(0, 20), decrypt.substring(15, 35))) {
return false;
}
decrypt.substring(35, 55);
// 判断激活码里面的uuid是否一致
if (!Objects.equals(this.uuid, decrypt.substring(55))) {
return false;
}
this.license = str;
this.expireTimestamp = Long.valueOf(parseLong);
return true;
} catch (Throwable th) {
return false;
}
}
解密方法
标准的AES解密方法
密钥:前 32 个字符
bArr
和bArr2
:分别用于存储 IV 和加密数据的字节数组。那么我们只需要找到key和iv这个AES算法我们就可以逆向出来了。
private static String decrypt(String str) throws Exception {
String substring = str.substring(0, 32);// key
byte[] decode = Base64.getDecoder().decode(str.substring(32 + 6, 32 + 6 + Integer.parseInt(str.substring(32, 32 + 6), 16)));
byte[] bArr = new byte[16]; // iv
byte[] bArr2 = new byte[decode.length - 16];//密文
System.arraycopy(decode, 0, bArr, 0, 16);
System.arraycopy(decode, 16, bArr2, 0, decode.length - 16);
SecretKeySpec secretKeySpec = new SecretKeySpec(substring.getBytes(), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(bArr);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secretKeySpec, ivParameterSpec);
return new String(cipher.doFinal(bArr2), StandardCharsets.UTF_8);
}
输出看下具体值
key:H0H2H3wdknJf4Ns5L47Jv51iIqtk5xsu
IV:base64编码:MGs3MVNJZzJJMFBVWGQ1Mg==
IV:base64解码:0k71SIg2I0PUXd52
下一步就是编写注册机咯
激活
在上述的授权链接里面就有uuid和自己的用户名信息,访问一下链接即可
生成license
public static void main(String[] args) throws Exception {
String license = getLicense("2099-12-31 00:00:00", "dell", "4C4C4544-0020-2010-8020-A0C04F202020");
System.out.println("激活码 = " + license);
}
/**
* 获取激活码
*
* @param expireTime 到期时间
* @param userName 用户名
* @param uuid UUID
* @return
*/
public static String getLicense(String expireTime, String userName, String uuid) throws Exception {
long expireTimestamp = DateUtil.parse(expireTime).getTime() / 1000;
// 获取填充
String padding = padUsername(userName);
String licenseStr = String.format("%sIJ@@@%s%s", expireTimestamp, padding, uuid);
// 获取key
String key = "H0H2H3wdknJf4Ns5L47Jv51iIqtk5xsu";
// 获取iv
byte[] bArr = "0k71SIg2I0PUXd52".getBytes();
return encrypt(key, bArr, licenseStr);
}
//公钥
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtx28zsKlYjCPzUMR0lHN
uVCxkSy7oR2P9Zq//yOO8XXLh4dhNDsL4ntS38YGIJBuNcFa5bg9zXcobUZmP+ur
B3ZKgtpyO4CFqJ8RmLWO0XWVSX7fMY0katdqIl0skU3ckF5iNpb6251y1WlXL1bm
Ii4X15ux8Por++lg4JW9jPc9R98QdxmX9GOMoReCogNlpqYTcouwRf/wvIEY9m6Z
D7bouY/JOBpoyNKPMGC5GI4op6OKCNT09W51nlZ59Qvv/IPFaQGoS5UAyL8fVT1a
Sbk1O8y5pWqy1H7H5ufV+f7XR9zu5dZCTfky4RifX6XX4JKCMR2D3JTReXFVr72E
8QIDAQAB
-----END PUBLIC KEY-----
//私钥
-----BEGIN RSA PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC3HbzOwqViMI/N
QxHSUc25ULGRLLuhHY/1mr//I47xdcuHh2E0Owvie1LfxgYgkG41wVrluD3Ndyht
RmY/66sHdkqC2nI7gIWonxGYtY7RdZVJft8xjSRq12oiXSyRTdyQXmI2lvrbnXLV
aVcvVuYiLhfXm7Hw+iv76WDglb2M9z1H3xB3GZf0Y4yhF4KiA2WmphNyi7BF//C8
gRj2bpkPtui5j8k4GmjI0o8wYLkYjiino4oI1PT1bnWeVnn1C+/8g8VpAahLlQDI
vx9VPVpJuTU7zLmlarLUfsfm59X5/tdH3O7l1kJN+TLhGJ9fpdfgkoIxHYPclNF5
cVWvvYTxAgMBAAECggEAFwHZQGgz492in8FiyphlHvjMyqcCbxiaBxuZrnqfAecR
OrbPh4K4uEzS6ZNFn09OTZo867qFp1xmm645+COJ4l7iN0Uvj5rTEE/mI9gB+P7L
UkfqzpzDe9oTd3xZ9mrAQPJe6Cl5nODQNhCtd+D0+svsSnaBObwRDS5yMd2WipCq
bIhc7Yi5vVpUbDd6+y7+fhkpbpJJgfTpth0cKtOQC+jRLkA0+SclLmG0rUI/ctiV
dFWn6O4IU340yHyzOX9UnBkjlAThWvJdqay4DCMdknF/ChBHhES+kbHmxIWBB0UK
QUm+LX3xv8hjxZfhnDC8oNjoXx3qUhYCyivr8r9IPQKBgQDjmY3y1taiM+ZXRHKH
m5AtEYhCQoJkgPfhY9HjcA4Fl0g4hwLRLyDku5OBW2ahpzichlYPMNrGr2DXkaQo
nOplNvWC43n7deXXGiT6/RN23RLhBHFfQSQVgWOtc5z3DUE0qADcuXWKI1fiMD1z
6T3FbDbMTXtTC9CiwslsP2JstQKBgQDN9zKYPTKHQb/8/LRtDJdPhhZstNY0l66S
J8M6190mAyyYvPsY1sjVp0qSKIxaq9IRUhoqozBWuHJS4GbvLiiEtCNEX9HL+fOC
kOxGILXNBcGiTcczW240Wi/9LJAVJPba4PYiCY240fNKBcvMIbMizBuQ1F4NR6yI
7hUKZX2YzQKBgQCH2ALNSkVZErkMpSHmpobrH2fAhInnCsLol/eSVDNKSv0kIBEi
YYq0evCTaMZc/b3gTp3W+0XZCJw4jgj45I9SUfc/ZB5OZBQGyuf/lkWj0FeQTmKM
hAjRfSTNRhANtK+SiiPZmif5hxbRPhGvuSrRRsF+N1DARHEGdFRcc4h/cQKBgAd3
ltX+If7VW2iIoOHzOukfK2D1jW6KsUGLP4C6osHmC4/eChx0bQOR9Ronbi87W3pV
R62UDQSX20015YV2XvGwtjacYrbKcRGiv24rcWvlcYe42if6gJxVSLgdDXw2wtxc
m4/QWNsCgZeFbkYQUrZIQBeYG3DP0GmGeCzQUSVhAoGBAOM4MTBhgfc5Mi+N38Hx
y4XWkifjjH8iyEDVcaXCrHjkinU7mqXhICU23WG+l0hNH99lE4VvAqiLzZjkdc+e
+kllPlvceRR7jHmp/TpHoJN1ta6ezC1zmRxkGviOMrU9q9Xvvz5iYo6awD/uJ3sl
up9NRN9yIsnEf9nm9tnX8Msv
-----END RSA PRIVATE KEY-----
/**
* 使用AES加密
*
* @param key AES的key
* @param iv AES的iv
* @param plaintext 明文
* @return
*/
private static String encrypt(String key, byte[] iv, String plaintext) throws Exception {
String encryptedString = "";
String suffix = "";
// 使用给定的 key 和 IV 初始化 Cipher
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
// 对明文进行加密
byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
// 拼接 IV 和加密后的数据
byte[] ivAndCiphertext = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, ivAndCiphertext, 0, iv.length);
System.arraycopy(ciphertext, 0, ivAndCiphertext, iv.length, ciphertext.length);
// 对拼接后的数据进行 Base64 编码
String encodedData = Base64.getEncoder().encodeToString(ivAndCiphertext);
// 拼接密钥长度和编码后的数据,并用 0 填充到 6 位
String lengthString = String.format("%06X", encodedData.length());
encryptedString = key + lengthString + encodedData;
// 这里读取的就是上述的私钥文件
PrivateKey privateKey = PemUtil.readPemPrivateKey(new FileInputStream("E:\\Work\\privateKey2048.pem"));
// 创建 Signature 对象并初始化为签名模式
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
// 更新要签名的数据
signature.update(encodedData.getBytes());
// 对数据进行签名
byte[] signatureBytes = signature.sign();
// 将签名转换为 Base64 编码的字符串
String signatureBase64 = Base64.getEncoder().encodeToString(signatureBytes);
return encryptedString + signatureBase64;
}
/**
* 填充格式
*
* @param username 用户名
* @return
*/
public static String padUsername(String username) {
int usernameLength = username.length();
int paddingLength = 40 - usernameLength;
if (paddingLength <= 0) {
return username;
} else {
StringBuilder paddedUsername = new StringBuilder(username);
for (int i = 0; i < paddingLength; i++) {
paddedUsername.append("@");
}
return paddedUsername.toString();
}
}
替换dll
因为dll中会进行签名验证,这里这里暂时没有什么好的办法,只支持windows替换dll
我这里使用的winhex进行替换,dll里面密钥对
修改后dll下载链接:wism.zip官方版下载丨最新版下载丨绿色版下载丨APP下载-123云盘 提取码:iH7s
使用方法
-
找到ide的安装目录\bin下面,删除wism.dll文件
-
找到ide安装插件路径替换instrumented-Smart Input-6.0.4.jar里面dll
ps:我这里是改了它的存储路径,默认的 C:\Users\用户名\AppData\Roaming\JetBrains\IntelliJIdea2024.1类似这种
3.重启ide
食用方法
目前只支持windows平台!!!
1、重新获取授权
2、激活插件
3、在打开的网页中,复制请求地址中uuid和用户名
4、调用上述 生成license方法【看上文 激活章节】
5、配置url【看上文 配置url章节】
6、替换dll 【看上文 替换dll章节】
激活看下
切换看下
完工,告辞!
我真不会破解