升级完idea 之后 发现插件不对劲了 .
重新下载mybatis类插件 就下载了 MybatisCodeHelperPro
免费功能够用 但是每次提示激活
于是 tg中搜了下 发现居然没有..
简单的试下破解
插件位置
由于我是mac 电脑 在jetbrains toolbox的帮助下找到了idea的日志
根据日志拿到了插件的目录.
激活方式
插件界面如下
简单分析了插件激活页面之后 目标离线激活
寻找机会
在此之前 利用 jadx 和 recaf-gui 进行反编译和编译工作
输入任意编码提示错误信息.
在jadx中查到定位类
第一次 找到了公钥 解密的地方 经过一顿研究 发现私钥加密了原始数据 base64编码了密文 .
第二次 找到了解密后的数据格式 (感谢52破解的一个帖子 构建了成功的载荷格式)
{ "paidKey": "88888888-8888-8888-8888-888888888888", "valid": true, "userMac": "唯一码", "validTo": 4100688000000 }
破解逻辑绕过解密动作
这个时候用jadx 定位到类 在recaf-gui 中 用Smali 编辑class .
.inner public static {
name: Decoder,
inner: java/util/Base64$Decoder,
outer: java/util/Base64
}
.inner public static final {
name: Lookup,
inner: java/lang/invoke/MethodHandles$Lookup,
outer: java/lang/invoke/MethodHandles
}
.sourcefile "SourceFile"
.super java/lang/Object
.class public super com/ccnode/codegenerator/ag/f/e {
.field private static a Lcom/google/gson/Gson;
.method public <init> ()V {
parameters: { this },
code: {
A:
line 11
aload this
invokespecial java/lang/Object.<init> ()V
return
B:
}
}
.method public static a (Ljava/lang/String;)Lcom/ccnode/codegenerator/ag/d/f; {
parameters: { v0 },
exceptions: {
{ B, C, D, Lcom/ccnode/codegenerator/ag/f/b; },
{ G, H, I, Ljava/io/UnsupportedEncodingException; },
{ K, L, M, Ljava/lang/Exception; }
},
code: {
A:
line 15
aconst_null
astore v1
B:
// try-start: range=[B-C] handler=D:com/ccnode/codegenerator/ag/f/b
line 17
new java/lang/String
dup
invokestatic java/util/Base64.getDecoder ()Ljava/util/Base64$Decoder;
ldc "TUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDZzUyUjExV0h1MysvNUV2WnhkS0l2a3ovekpnS2VNUUhNLytMVkxSZS9zWUpFQlUxbUUrODc3MmJJckk4UThscldqSHc5cmVjQ1RWVVhXUnhWYXBndk1HYTZ3KzU4STZwYXdSaFhwZDBrRkhUY2xxeUZGWFpoS3ZiQUtoblphRGNuZkJtSkhObTQwR0JFTGpCTmx5MXpha2FIblFmUzF0QlhaSGQwOUV0c2VRSURBUUFC"
invokevirtual java/util/Base64$Decoder.decode (Ljava/lang/String;)[B
getstatic kotlin/text/Charsets.UTF_8 Ljava/nio/charset/Charset;
invokespecial java/lang/String.<init> ([BLjava/nio/charset/Charset;)V
invokestatic com/ccnode/codegenerator/ag/f/d.a (Ljava/lang/String;)Ljava/security/interfaces/RSAPublicKey;
invokestatic java/util/Base64.getDecoder ()Ljava/util/Base64$Decoder;
aload v0
invokevirtual java/util/Base64$Decoder.decode (Ljava/lang/String;)[B
invokestatic com/ccnode/codegenerator/ag/f/d.b (Ljava/security/interfaces/RSAPublicKey;[B)[B
astore v1
C:
// try-end: range=[B-C] handler=D:com/ccnode/codegenerator/ag/f/b
line 20
goto F
D:
// try-handler: range=[B-C] handler=D:com/ccnode/codegenerator/ag/f/b
line 18
astore v2
E:
line 19
new com/ccnode/codegenerator/ag/f/c
dup
invokespecial com/ccnode/codegenerator/ag/f/c.<init> ()V
invokestatic java/util/Base64.getDecoder ()Ljava/util/Base64$Decoder;
aload v0
invokevirtual java/util/Base64$Decoder.decode (Ljava/lang/String;)[B
invokestatic com/ccnode/codegenerator/ag/f/d.b (Ljava/security/interfaces/RSAPublicKey;[B)[B
astore v1
F:
line 21
aconst_null
astore v2
G:
// try-start: range=[G-H] handler=I:java/io/UnsupportedEncodingException
line 24
new java/lang/String
dup
aload v1
ldc "UTF-8"
invokespecial java/lang/String.<init> ([BLjava/lang/String;)V
astore v3
H:
// try-end: range=[G-H] handler=I:java/io/UnsupportedEncodingException
line 27
goto K
I:
// try-handler: range=[G-H] handler=I:java/io/UnsupportedEncodingException
line 25
astore v4
J:
line 26
new java/lang/RuntimeException
dup
aload v4
invokespecial java/lang/RuntimeException.<init> (Ljava/lang/Throwable;)V
athrow
K:
// try-start: range=[K-L] handler=M:java/lang/Exception
line 29
getstatic com/ccnode/codegenerator/ag/f/e.a Lcom/google/gson/Gson;
aload v3
ldc Lcom/ccnode/codegenerator/ag/d/f;
invokevirtual com/google/gson/Gson.fromJson (Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
checkcast com/ccnode/codegenerator/ag/d/f
astore v2
L:
// try-end: range=[K-L] handler=M:java/lang/Exception
line 32
goto O
M:
// try-handler: range=[K-L] handler=M:java/lang/Exception
line 30
astore v4
N:
line 31
new java/lang/RuntimeException
dup
aload v3
invokedynamic makeConcatWithConstants (Ljava/lang/String;)Ljava/lang/String; { invokestatic, java/lang/invoke/StringConcatFactory.makeConcatWithConstants, (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; } { "gson catch exception, the json string is\u0001" }
aload v4
invokespecial java/lang/RuntimeException.<init> (Ljava/lang/String;Ljava/lang/Throwable;)V
athrow
O:
line 33
aload v2
areturn
P:
}
}
.method static <clinit> ()V {
code: {
A:
line 12
new com/google/gson/Gson
dup
invokespecial com/google/gson/Gson.<init> ()V
putstatic com/ccnode/codegenerator/ag/f/e.a Lcom/google/gson/Gson;
return
B:
}
}
}
直接将输入的字符串作为json传递给gson 反序列化
.inner public static {
name: Decoder,
inner: java/util/Base64$Decoder,
outer: java/util/Base64
}
.inner public static final {
name: Lookup,
inner: java/lang/invoke/MethodHandles$Lookup,
outer: java/lang/invoke/MethodHandles
}
.sourcefile "SourceFile"
.super java/lang/Object
.class public super com/ccnode/codegenerator/ag/f/e {
.field private static a Lcom/google/gson/Gson;
.method public <init> ()V {
parameters: { this },
code: {
A:
line 11
aload this
invokespecial java/lang/Object.<init> ()V
return
B:
}
}
.method public static a (Ljava/lang/String;)Lcom/ccnode/codegenerator/ag/d/f; {
parameters: { v0 },
exceptions: {
{ A, B, C, Ljava/lang/Exception; }
},
code: {
A:
// try-start: range=[A-B] handler=C:java/lang/Exception
line 29
getstatic com/ccnode/codegenerator/ag/f/e.a Lcom/google/gson/Gson;
aload v0
ldc Lcom/ccnode/codegenerator/ag/d/f;
invokevirtual com/google/gson/Gson.fromJson (Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
checkcast com/ccnode/codegenerator/ag/d/f
astore v2
B:
// try-end: range=[A-B] handler=C:java/lang/Exception
line 32
goto E
C:
// try-handler: range=[A-B] handler=C:java/lang/Exception
line 30
astore v4
D:
line 31
new java/lang/RuntimeException
dup
aload v0
invokedynamic makeConcatWithConstants (Ljava/lang/String;)Ljava/lang/String; { invokestatic, java/lang/invoke/StringConcatFactory.makeConcatWithConstants, (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; } { "gson catch exception, the json string is\u0001" }
aload v4
invokespecial java/lang/RuntimeException.<init> (Ljava/lang/String;Ljava/lang/Throwable;)V
athrow
E:
line 33
aload v2
areturn
F:
}
}
.method static <clinit> ()V {
code: {
A:
line 12
new com/google/gson/Gson
dup
invokespecial com/google/gson/Gson.<init> ()V
putstatic com/ccnode/codegenerator/ag/f/e.a Lcom/google/gson/Gson;
return
B:
}
}
}
重复N+1次询问ai 语法
编译成功 导出工程
替换之后 重启idea 显示激活成功
唯一码计算代码
package com.free.api.oshitest;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
public class Mac {
private static final byte[][] VIRTUAL_MAC_PREFIXES = {{0, 5, 105}, {0, 28, 20}, {0, 12, 41}, {0, 80, 86}, {8, 0, 39}, {10, 0, 39}, {0, 3, -1}, {0, 21, 93}};
public static void main(String[] args) {
final String mac = getNetworkInfo("mac").getFirst();
System.out.println(mac);
}
public static String mac() {
return getNetworkInfo("mac").getFirst();
}
public static List<String> getNetworkInfo(String type) {
List<String> result = new ArrayList<>();
try {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
if (!isValidNetworkInterface(networkInterface)) {
continue;
}
Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
while (inetAddresses.hasMoreElements()) {
InetAddress inetAddress = inetAddresses.nextElement();
if (isLocalIPv4Address(inetAddress)) {
processNetworkAddress(inetAddress, type, result);
}
}
}
} catch (SocketException e) {
System.err.println("Error getting network interfaces: " + e.getMessage());
} catch (UnknownHostException e) {
System.err.println("Error resolving host: " + e.getMessage());
}
return result;
}
private static boolean isValidNetworkInterface(NetworkInterface networkInterface) throws SocketException {
byte[] hardwareAddress = networkInterface.getHardwareAddress();
return hardwareAddress != null && hardwareAddress.length > 0 && !isVirtualMacAddress(hardwareAddress);
}
private static boolean isLocalIPv4Address(InetAddress inetAddress) {
return inetAddress instanceof Inet4Address && inetAddress.isSiteLocalAddress();
}
private static void processNetworkAddress(InetAddress inetAddress, String type, List<String> result) throws UnknownHostException {
InetAddress address = InetAddress.getByName(inetAddress.getHostAddress());
if (address == null) {
return;
}
if ("ip".equals(type)) {
String ip = address.toString().replaceAll("^/+", "");
result.add(ip);
} else if ("mac".equals(type)) {
String mac = formatMacAddress(address);
if (mac != null) {
result.add(mac);
}
}
}
private static String formatMacAddress(InetAddress inetAddress) {
try {
byte[] hardwareAddress = NetworkInterface.getByInetAddress(inetAddress).getHardwareAddress();
if (hardwareAddress == null) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hardwareAddress.length; i++) {
sb.append(String.format("%02X", hardwareAddress[i]));
if (i < hardwareAddress.length - 1) {
sb.append("-");
}
}
return sb.toString();
} catch (SocketException e) {
System.err.println("Error getting MAC address: " + e.getMessage());
return null;
}
}
private static boolean isVirtualMacAddress(byte[] macAddress) {
if (macAddress == null || macAddress.length < 3) {
return false;
}
for (byte[] prefix : VIRTUAL_MAC_PREFIXES) {
if (macAddress[0] == prefix[0] && macAddress[1] == prefix[1] && macAddress[2] == prefix[2]) {
return true;
}
}
return false;
}
}
激活码构建程序
package com.free.api.oshitest;
import com.google.gson.annotations.SerializedName;
public class f {
@SerializedName(value = "paidKey")
private String a;
@SerializedName(value = "valid")
private Boolean a2;
@SerializedName(value = "userMac")
private String b3;
@SerializedName(value = "validTo")
private Long a4;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public Boolean getA2() {
return a2;
}
public void setA2(Boolean a2) {
this.a2 = a2;
}
public String getB3() {
return b3;
}
public void setB3(String b3) {
this.b3 = b3;
}
public Long getA4() {
return a4;
}
public void setA4(Long a4) {
this.a4 = a4;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("f{");
sb.append("a='").append(a).append('\'');
sb.append(", a2=").append(a2);
sb.append(", b3='").append(b3).append('\'');
sb.append(", a4=").append(a4);
sb.append('}');
return sb.toString();
}
}
package com.free.api.oshitest;
import com.google.gson.Gson;
import java.util.Base64;
/**
* @author: Yh
* @date: 2025-10月-30 17:35:00 17:35
*/
public class GetKey {
public static void main(String[] args) {
f f = new f();
f.setA("88888888-8888-8888-8888-888888888888");
f.setA2(true);
f.setA4(4100688000000L);
f.setB3(Mac.mac());
Gson gson = new Gson();
final String json = gson.toJson(f);
System.out.println(json);
final String s = Base64.getEncoder().encodeToString(json.getBytes());
System.out.println(s);
}
}