Idea Agent

Idea Agent

Idea Agent 是一个用于增强对于IDEA做一些不可描述功能的Agent,基础理论来在IDEA激活原理

破解原理

从大佬文章可知,IDEA提供了一份付费插件激活的示例代码,源码如下:CheckLicense.java

从而可以知道IDEA使用了CA体系来进行授权激活。

现在我们来看一下IDEA的激活码

1
FV8EM46DQYC5AW9-eyJsaWNlbnNlSWQiOiJGVjhFTTQ2RFFZQzVBVzkiLCJsaWNlbnNlZU5hbWUiOiJtZW5vcmFoIHBhcmFwZXQiLCJsaWNlbnNlZVR5cGUiOiJQRVJTT05BTCIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN1cnJlbnRVc2UiOmZhbHNlLCJwcm9kdWN0cyI6W3siY29kZSI6IlBDV01QIiwiZmFsbGJhY2tEYXRlIjoiMjAyNi0wOS0xNCIsInBhaWRVcFRvIjoiMjAyNi0wOS0xNCIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQUlIiLCJmYWxsYmFja0RhdGUiOiIyMDI2LTA5LTE0IiwicGFpZFVwVG8iOiIyMDI2LTA5LTE0IiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBEQiIsImZhbGxiYWNrRGF0ZSI6IjIwMjYtMDktMTQiLCJwYWlkVXBUbyI6IjIwMjYtMDktMTQiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUFNJIiwiZmFsbGJhY2tEYXRlIjoiMjAyNi0wOS0xNCIsInBhaWRVcFRvIjoiMjAyNi0wOS0xNCIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJJSSIsImZhbGxiYWNrRGF0ZSI6IjIwMjYtMDktMTQiLCJwYWlkVXBUbyI6IjIwMjYtMDktMTQiLCJleHRlbmRlZCI6ZmFsc2V9XSwibWV0YWRhdGEiOiIwMjIwMjQwNzAyUFNBWDAwMDAwNVgiLCJoYXNoIjoiMTIzNDU2NzgvMC01NDE4MTY2MjkiLCJncmFjZVBlcmlvZERheXMiOjcsImF1dG9Qcm9sb25nYXRlZCI6ZmFsc2UsImlzQXV0b1Byb2xvbmdhdGVkIjpmYWxzZSwidHJpYWwiOmZhbHNlLCJhaUFsbG93ZWQiOnRydWV9-cH8qBniG31nF8954hthJJuzF6Fk4RQ9T03IfNxsFkuxUcwaAGHKOcRudvBZIAbLwDDFw63q2QZsnpwthBb/6IqBYnJrjRC83a8wkYKGN8HqAyDtbqdLOxLjcaiAiSKzektfAXn6nGNfDeygcFr/WzMfI0on/43ByuwxmSrjwYc4M8SCR0nkDAi0XwXNnFp3vSp0gJQd+lJtkSHO2KR7gUyNDZOPVduljJGbdLJUK6UcUjrlAd6NrTNqpu5P7hcYRaNzjoJ0KeIx5k9KmMCdcfQBia/zSHUbwZiecFsyjxqtIU0C3TDaX1OM4siJVDpgrXi+ocY86hiiYE79ygJf2IA==-MIIETDCCAjSgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTIwMTAxOTA5MDU1M1oXDTIyMTAyMTA5MDU1M1owHzEdMBsGA1UEAwwUcHJvZDJ5LWZyb20tMjAyMDEwMTkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCUlaUFc1wf+CfY9wzFWEL2euKQ5nswqb57V8QZG7d7RoR6rwYUIXseTOAFq210oMEe++LCjzKDuqwDfsyhgDNTgZBPAaC4vUU2oy+XR+Fq8nBixWIsH668HeOnRK6RRhsr0rJzRB95aZ3EAPzBuQ2qPaNGm17pAX0Rd6MPRgjp75IWwI9eA6aMEdPQEVN7uyOtM5zSsjoj79Lbu1fjShOnQZuJcsV8tqnayeFkNzv2LTOlofU/Tbx502Ro073gGjoeRzNvrynAP03pL486P3KCAyiNPhDs2z8/COMrxRlZW5mfzo0xsK0dQGNH3UoG/9RVwHG4eS8LFpMTR9oetHZBAgMBAAGjgZkwgZYwCQYDVR0TBAIwADAdBgNVHQ4EFgQUJNoRIpb1hUHAk0foMSNM9MCEAv8wSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggIBABKaDfYJk51mtYwUFK8xqhiZaYPd30TlmCmSAaGJ0eBpvkVeqA2jGYhAQRqFiAlFC63JKvWvRZO1iRuWCEfUMkdqQ9VQPXziE/BlsOIgrL6RlJfuFcEZ8TK3syIfIGQZNCxYhLLUuet2HE6LJYPQ5c0jH4kDooRpcVZ4rBxNwddpctUO2te9UU5/FjhioZQsPvd92qOTsV+8Cyl2fvNhNKD1Uu9ff5AkVIQn4JU23ozdB/R5oUlebwaTE6WZNBs+TA/qPj+5/we9NH71WRB0hqUoLI2AKKyiPw++FtN4Su1vsdDlrAzDj9ILjpjJKA1ImuVcG329/WTYIKysZ1CWK3zATg9BeCUPAV1pQy8ToXOq+RSYen6winZ2OO93eyHv2Iw5kbn1dqfBw1BuTE29V2FJKicJSu8iEOpfoafwJISXmz1wnnWL3V/0NxTulfWsXugOoLfv0ZIBP1xH9kmf22jjQ2JiHhQZP7ZDsreRrOeIQ/c4yR8IQvMLfC0WKQqrHu5ZzXTH4NO3CwGWSlTY74kE91zXB5mwWAx1jig+UXYc2w4RkVhy0//lOmVya/PEepuuTTI4+UJwC7qbVlh5zfhj8oTNUXgN0AOc+Q0/WFPl1aw5VV/VrO8FCoB15lFVlpKaQ1Yh+DVU8ke+rt9Th0BCHXe0uZOEmH0nOnH/0onD

通过对于IDEA提供的示例代码我们可以知道,License格式是分为了4部分

  1. licenseId 授权ID
  2. licensePartBase64 授权信息Base64
  3. signatureBase64 签名Base64
  4. certBase64 证书Base64

那么我们需要关注的就是授权信息Base64,我们解码看一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
"licenseId": "FV8EM46DQYC5AW9",
"licenseeName": "menorah parapet",
"licenseeType": "PERSONAL",
"assigneeName": "",
"assigneeEmail": "",
"licenseRestriction": "",
"checkConcurrentUse": false,
"products": [
{
"code": "PCWMP",
"fallbackDate": "2026-09-14",
"paidUpTo": "2026-09-14",
"extended": true
},
{
"code": "PRR",
"fallbackDate": "2026-09-14",
"paidUpTo": "2026-09-14",
"extended": true
},
{
"code": "PDB",
"fallbackDate": "2026-09-14",
"paidUpTo": "2026-09-14",
"extended": true
},
{
"code": "PSI",
"fallbackDate": "2026-09-14",
"paidUpTo": "2026-09-14",
"extended": true
},
{
"code": "II",
"fallbackDate": "2026-09-14",
"paidUpTo": "2026-09-14",
"extended": false
}
],
"metadata": "0220240702PSAX000005X",
"hash": "12345678/0-541816629",
"gracePeriodDays": 7,
"autoProlongated": false,
"isAutoProlongated": false,
"trial": false,
"aiAllowed": true
}

很明显可以看出来,主要内容在products中,我们只需要修改products即可。但是这里有一个问题,就是signatureBase64,如果我们修改了products,
那么signatureBase64也会改变,所以我们需要重新生成signatureBase64。在CheckLicense.java
中,我们可以看到

1
2
3
final Signature sig = Signature.getInstance("SHA1withRSA");
// Here it is only important that the key was signed with an authentic JetBrains certificate.
sig.initVerify(createCertificate(Base64.getMimeDecoder().decode(certBase64.getBytes(StandardCharsets.UTF_8)), Collections.emptySet(), false));

这里的certBase64就是证书Base64,是一个由JetProfile CA签名的子证书。

从这里我们可以想到什么呢,我们可以自己签发一套证书,然后使用agent Hook验证子证书的逻辑,从而实现自己签发License了。

从这里不得不配置始皇的思路,是真滴强!!!

破解实现

我们需要写一个java Agent来进行插桩增强,我们通过Hook Math方法来进行修改,使我们自签名的证书,可以通过证书校验,从而实现自签激活

实现Agent可以是使用ASM和Bytebuddy,这里我们使用Bytebuddy,有高级API简单一些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId> <!-- Or jdk15on, etc. depending on your JDK -->
<version>1.78.1</version> <!-- Use the latest version -->
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId> <!-- Or jdk15on, etc. -->
<version>1.78.1</version> <!-- Use the latest version -->
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.17.2</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.17.2</version>
</dependency>

gson是用来解析json的,bouncycastle是用来做证书的,bytebuddy是增强框架,bytebuddy-agent是增强框架的agent。

MyAgent.java

这是agent入口代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;
public class MyAgent {

/**
* java.security.Signature#verify(byte[])
* java.security.Signature#verify(byte[])
* java.security.SignatureSpi#engineInitSign(java.security.PrivateKey)
*/
public static void premain(String arguments, Instrumentation instrumentation) {
new AgentBuilder.Default()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
.ignore(ElementMatchers.none())
.with(new AgentBuilder.Listener() {
@Override
public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {
}

@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {
System.out.println(typeDescription.getCanonicalName() + "增强成功");
}

@Override
public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {
}

@Override
public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {
System.out.println(s + "增强失败");
System.out.println(throwable);
}

@Override
public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

}
})
// 匹配所有实现了目标接口的类
.type(ElementMatchers.named("java.math.BigInteger"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
.visit(Advice.to(BigIntegerAdvice.class)
.on(ElementMatchers.named("oddModPow"))))
.type(ElementMatchers.named("sun.net.www.http.HttpClient"))
.transform((builder, typeDescription, classLoader, javaModule, protectionDomain) -> {
return builder.visit(Advice.to(HttpClientAdvice.class).on(ElementMatchers.named("openServer")));
})

.installOn(instrumentation);


}
}

BigIntegerAdvice.java

这里是增强的代码,这里我们增强的是BigInteger的oddModPow方法,这个方法就是Math.pow()方法,我们通过Hook这个方法,来修改Math.pow()方法的返回值,从而实现自签激活。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import net.bytebuddy.asm.Advice;
import net.bytebuddy.implementation.bytecode.assign.Assigner;

import java.math.BigInteger;

public class BigIntegerAdvice {


@Advice.OnMethodExit
public static void intercept(
@Advice.This Object x,
@Advice.Argument(0) Object y,
@Advice.Argument(1) Object z,
@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) {
System.out.println("x:" + x);
System.out.println("y:" + y);
System.out.println("z:" + z);
if (x.equals(new BigInteger("668543865266660271851320132804574734353772756424032842728003425246848877267246728308078049592864919737551749108946930975745594949946068534816205363012823428756785334552190043573340622231976580621806677401574548075568022631712209726764671384003081399946015525223189756214791946907933154007960051392212667164611884613685005737824326491959745640935832149076031899222528233911940453541852127689390472442318299201854447408258829160075783937025367062344233491839646530271369146123303001730251317033959735309290615503750284532549155472446808085875006030509376932196983565177551280579449090720160896730686966226624495107056898957513582788595100764401145863297580416894823201304465019892884064808620445880987541907557526016267035832535420207752334568312988437114229571708239311033133120330459369207400093641962008761264716865342750031384052132960571647111368052606166687937809007525198651214764726994754712558210098197973142237884078991870517946359198329888115745098154497287551409366062678394227527539432876521764846402737125465134296271878158172011432299080920003252071724092669727397489448738261396956470226333952334768808080628569342061167065260927363667203042891357803520625329883558848539818536954889719679902134570724506881558822254016"))){
if (y.equals(new BigInteger("65537"))){
if (z.equals(new BigInteger("860106576952879101192782278876319243486072481962999610484027161162448933268423045647258145695082284265933019120714643752088997312766689988016808929265129401027490891810902278465065056686129972085119605237470899952751915070244375173428976413406363879128531449407795115913715863867259163957682164040613505040314747660800424242248055421184038777878268502955477482203711835548014501087778959157112423823275878824729132393281517778742463067583320091009916141454657614089600126948087954465055321987012989937065785013284988096504657892738536613208311013047138019418152103262155848541574327484510025594166239784429845180875774012229784878903603491426732347994359380330103328705981064044872334790365894924494923595382470094461546336020961505275530597716457288511366082299255537762891238136381924520749228412559219346777184174219999640906007205260040707839706131662149325151230558316068068139406816080119906833578907759960298749494098180107991752250725928647349597506532778539709852254478061194098069801549845163358315116260915270480057699929968468068015735162890213859113563672040630687357054902747438421559817252127187138838514773245413540030800888215961904267348727206110582505606182944023582459006406137831940959195566364811905585377246353"))){
result = new BigInteger("31872219281407242025505148642475109331663948030010491344733687844358944945421064967310388547820970408352359213697487269225694990179009814674781374751323403257628081559561462351695605167675284372388551941279783515209238245831229026662363729380633136520288327292047232179909791526492877475417113579821717193807584807644097527647305469671333646868883650312280989663788656507661713409911267085806708237966730821529702498972114194166091819277582149433578383639532136271637219758962252614390071122773223025154710411681628917523557526099053858210363406122853294409830276270946292893988830514538950951686480580886602618927728470029090747400687617046511462665469446846624685614084264191213318074804549715573780408305977947238915527798680393538207482620648181504876534152430149355791756374642327623133843473947861771150672096834149014464956451480803326284417202116346454345929350148770746553056995922154382822307758515805142704373984019252210715650875853634697920708113806880196144197384637328982263167395073688501517286678083973976140696077590122053014085412828620051470085033364773099146103525313018873319293728800442101520384088109603555959893639842091339193940338635838987849935607829263545048834505707814092016293326804334560882752464");
}
}
}
}

}

HttpClientAdvice.java

这里主要是阻断网络验证,手动造成断网现象

1
2
3
4
5
6
7
8
9
10
11
12
import net.bytebuddy.asm.Advice;
import java.net.SocketTimeoutException;

public class HttpClientAdvice {
@Advice.OnMethodExit
public static void intercept(@Advice.This Object x) throws Exception {
if (x.toString().contains("validateKey.action")){
throw new SocketTimeoutException();
}

}
}

计算X,Y,Z

XYZ是怎么计算出来的呢,别急,看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;

import java.io.*;
import java.math.BigInteger;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import java.util.concurrent.TimeUnit;

public class ActivationCodeGeneration {

static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* 计算验证结果
* @param userCertificate 证书
* @return 证书验证结果
*/
private static BigInteger calculateFakeResult(X509Certificate userCertificate) {
RSAPublicKey publicKey = (RSAPublicKey) userCertificate.getPublicKey();

BigInteger x = new BigInteger(1, userCertificate.getSignature());
return x.modPow(publicKey.getPublicExponent(), publicKey.getModulus());
}

public static CertificateKeyPair generateSelfSignedCert(
int validityDays,
String keyAlgorithm,
int keySize,
String signatureAlgorithm) throws Exception {

// 1. 生成密钥对
KeyPair keyPair = generateKeyPair(keyAlgorithm, keySize);

// 2. 构建证书信息
X500Name issuerName = new X500Name("CN=JetProfile CA"); // As specified in Python code
X500Name subjectName = new X500Name("CN=Mazp-from-2025-04-16");

Date[] validityPeriod = getValidityPeriod(validityDays);
BigInteger serial = generateSerialNumber();

// 3. 创建证书构建器
X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(
issuerName,
serial,
validityPeriod[0],
validityPeriod[1],
subjectName,
SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()));

// 4. 添加扩展
// addExtensions(certBuilder, keyPair.getPublic());

// 5. 签名并生成证书
X509Certificate cert = signCertificate(certBuilder, keyPair.getPrivate(), signatureAlgorithm);

return new CertificateKeyPair(cert, keyPair.getPrivate());
}

// 以下为私有辅助方法
private static KeyPair generateKeyPair(String algorithm, int size) throws NoSuchProviderException, NoSuchAlgorithmException {
KeyPairGenerator gen = KeyPairGenerator.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
gen.initialize(size, new SecureRandom());
return gen.generateKeyPair();
}

private static Date[] getValidityPeriod(int days) {
long now = System.currentTimeMillis();
return new Date[] {
new Date(now),
new Date(now + TimeUnit.DAYS.toMillis(days))
};
}

private static BigInteger generateSerialNumber() {
return new BigInteger(64, new SecureRandom());
}

private static void addExtensions(X509v3CertificateBuilder builder, PublicKey publicKey)
throws NoSuchAlgorithmException, IOException {
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
SubjectPublicKeyInfo pubKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
}

private static X509Certificate signCertificate(X509v3CertificateBuilder builder,
PrivateKey privateKey, String sigAlg) throws OperatorCreationException, CertificateException {
ContentSigner signer = new JcaContentSignerBuilder(sigAlg)
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.build(privateKey);

return new JcaX509CertificateConverter()
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.getCertificate(builder.build(signer));
}

public static CertificateKeyPair readCareAndKey(String certPath,String keyPath) {

try {
//读取证书文件
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
InputStream resourceAsStream = ActivationCodeGeneration.class.getClassLoader().getResourceAsStream(certPath);
InputStream resourceAsStream1 = ActivationCodeGeneration.class.getClassLoader().getResourceAsStream(keyPath);


X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(resourceAsStream);
PrivateKey privateKey = getPrivateKey(resourceAsStream1);
return new CertificateKeyPair(cert,privateKey);
} catch (CertificateException e) {
throw new RuntimeException(e);
}

}

private static PrivateKey getPrivateKey(InputStream stream) {
PrivateKey privateKey = null;
PrivateKeyInfo privateKeyInfo = null;

try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8);
PEMParser pemParser = new PEMParser(reader)) {

Object pemObject = pemParser.readObject();

if (pemObject == null) {
throw new IOException("No object found in PEM file: ");
}

System.out.println("Read object type from : " + pemObject.getClass().getName());

// --- Type Checking Logic ---
if (pemObject instanceof PEMKeyPair) {
System.out.println("Handling PEMKeyPair...");
PEMKeyPair pemKeyPair = (PEMKeyPair) pemObject;
privateKeyInfo = pemKeyPair.getPrivateKeyInfo();

} else if (pemObject instanceof PrivateKeyInfo) {
System.out.println("Handling PrivateKeyInfo...");
privateKeyInfo = (PrivateKeyInfo) pemObject;

} else if (pemObject instanceof PKCS8EncryptedPrivateKeyInfo) {
System.out.println("Handling PKCS8EncryptedPrivateKeyInfo (needs decryption)...");
// --- Decryption Logic (add if needed) ---
PKCS8EncryptedPrivateKeyInfo encryptedInfo = (PKCS8EncryptedPrivateKeyInfo) pemObject;
InputDecryptorProvider provider = new JceOpenSSLPKCS8DecryptorProviderBuilder()
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
.build(null);
privateKeyInfo = encryptedInfo.decryptPrivateKeyInfo(provider);
System.out.println("Decryption successful.");
// --- End Decryption Logic ---

} else {
throw new IOException("Unexpected object type '" + pemObject.getClass().getName() + "' in PEM file");
}

// --- Conversion to java.security.PrivateKey ---
if (privateKeyInfo != null) {
JcaPEMKeyConverter converter = new JcaPEMKeyConverter()
.setProvider(BouncyCastleProvider.PROVIDER_NAME); // Specify BC provider
privateKey = converter.getPrivateKey(privateKeyInfo); // Use getPrivateKey directly
System.out.println("Successfully converted to java.security.PrivateKey. Algorithm: " + privateKey.getAlgorithm());
} else {
throw new IOException("Failed to obtain PrivateKeyInfo from PEM object in file ");
}

} catch (IOException | OperatorCreationException | PKCSException e) {
// Rethrow specific exceptions or wrap them
System.err.println("Error processing PEM file: " + e.getMessage());
}
return privateKey;
}

public static void main(String[] args) {
try {
CertificateKeyPair certificateKeyPair = ActivationCodeGeneration.generateSelfSignedCert(3650, "RSA", 4096, "SHA256WithRSA");
certificateKeyPair.saveAsStandardFiles("idea2");
} catch (Exception e) {

}
CertificateKeyPair certificateKeyPair = ActivationCodeGeneration.readCareAndKey("idea2.crt", "idea2.key");
X509Certificate certificate = certificateKeyPair.getCertificate();
System.out.println("自定义证书的签名值 X:");
System.out.println(new BigInteger(1,certificate.getSignature()));

System.out.println("证书校验值");
System.out.println(calculateFakeResult(certificate));

}

}

只需要计算X和返回值即可,其他的是硬编码

生成license

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Base64;
import java.util.Random;

public class Main {

private static final String ALPHA_NUMERIC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static final Random random = new Random();

public static String generateRandomId(int length) {
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int index = random.nextInt(ALPHA_NUMERIC.length());
sb.append(ALPHA_NUMERIC.charAt(index));
}
return sb.toString();
}

public static void main(String[] args) throws Exception {

CertificateKeyPair certificateKeyPair = ActivationCodeGeneration.readCareAndKey("idea2.crt", "idea2.key");

// 自己修改 license内容
// 注意licenseId要一致
// 里面的内容是激活webstorm
String licensePart = "{\"licenseId\":\"6G5NXCPJZB\",\"licenseeName\":\"洞若观火\",\"assigneeName\":\"马泽朋\",\"assigneeEmail\":\"\",\"licenseRestriction\":\"\",\"checkConcurrentUse\":false,\"products\":[{\"code\":\"PSI\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true},{\"code\":\"PDB\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true},{\"code\":\"PMYBATISHELPER\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true},{\"code\":\"II\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":false},{\"code\":\"PPC\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true},{\"code\":\"PGO\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true},{\"code\":\"PSW\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true},{\"code\":\"PWS\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true},{\"code\":\"PPS\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true},{\"code\":\"PRB\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true},{\"code\":\"PCWMP\",\"fallbackDate\":\"2025-08-01\",\"paidUpTo\":\"2025-08-01\",\"extended\":true}],\"metadata\":\"0120220902PSAN000005\",\"hash\":\"TRIAL:-1078390568\",\"gracePeriodDays\":7,\"autoProlongated\":false,\"isAutoProlongated\":false}";
String licenseId = generateRandomId(10);

Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(licensePart, JsonObject.class);
if (args.length > 0) {
jsonObject.addProperty("licenseeName", args[0]);
} else {
jsonObject.addProperty("licenseeName", "专业版");
}
if (args.length > 1) {
jsonObject.addProperty("assigneeName", args[1]);
} else {
jsonObject.addProperty("assigneeName", "mazp");
}

/**
* 修改激活时间
*/
jsonObject.addProperty("licenseId", licenseId);
for (JsonElement products : jsonObject.getAsJsonArray("products")) {
JsonObject product = products.getAsJsonObject();
product.addProperty("fallbackDate", "2030-08-01");
product.addProperty("paidUpTo", "2030-08-01");
}
JsonObject stencil = new JsonObject();
stencil.addProperty("code","PMYBATISLOG");
stencil.addProperty("fallbackDate", "2030-08-01");
stencil.addProperty("paidUpTo", "2030-08-01");
jsonObject.getAsJsonArray("products").add(stencil);

JsonObject stencil2 = new JsonObject();
stencil2.addProperty("code","PC");
stencil2.addProperty("fallbackDate", "2030-08-01");
stencil2.addProperty("paidUpTo", "2030-08-01");
jsonObject.getAsJsonArray("products").add(stencil2);

JsonObject stencil_ws = new JsonObject();
stencil_ws.addProperty("code","WS");
stencil_ws.addProperty("fallbackDate", "2030-08-01");
stencil_ws.addProperty("paidUpTo", "2030-08-01");
jsonObject.getAsJsonArray("products").add(stencil_ws);



byte[] licensePartBytes = jsonObject.toString().getBytes(StandardCharsets.UTF_8);
String licensePartBase64 = Base64.getEncoder().encodeToString(licensePartBytes);
PrivateKey privateKey = certificateKeyPair.getPrivateKey();


Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privateKey);
signature.update(licensePartBytes);
byte[] signatureBytes = signature.sign();

String sigResultsBase64 = Base64.getEncoder().encodeToString(signatureBytes);

// Combine results as needed
String result = licenseId + "-" + licensePartBase64 + "-" + sigResultsBase64 + "-" + Base64.getEncoder().encodeToString(certificateKeyPair.getCertificate().getEncoded());
System.out.println("激活码是:");
System.out.println(result);

}

}

通过修改json的内容,可以实现激活任意产品。

获取插件code

通过请求https://plugins.jetbrains.com/api/plugins/{id}
即可看到code
idea_plugin_code.png

免责声明

本文/本帖内容涉及对IDEA激活机制的技术探讨与分析,其目的纯粹是为了技术学习、安全研究和理解软件保护机制。

请注意以下关键点:

  1. 仅为思路探讨: 本文内容仅限于对激活流程、可能采用的技术手段进行理论分析和思路猜想,不包含任何实际的、可运行的破解工具、代码、补丁、注册机、序列号或成品。
  2. 无意于破解或侵权: 作者无意提供、鼓励或支持任何形式的软件破解、盗版或侵犯知识产权的行为。探讨内容不应被视为绕过软件许可限制的指南或教程。
  3. 遵守法律法规与许可协议: 任何尝试绕过软件激活或技术保护措施的行为都可能违反软件最终用户许可协议(EULA),并可能触犯相关法律法规(例如《计算机软件保护条例》、《著作权法》等)。用户应尊重知识产权,通过合法途径获取和使用软件。
  4. 读者责任自负: 本文内容仅供参考,读者应对如何使用这些信息以及由此产生的任何后果承担全部责任。作者不对任何因阅读或使用本文信息而导致的直接或间接损失负责。
  5. 信息准确性: 文中分析可能基于有限的信息或推测,不保证其完全准确或适用于所有版本。

请务必在法律和道德允许的范围内进行技术研究。切勿将本文信息用于任何非法或侵权目的。


Idea Agent
https://mazepeng.com/2025/04/25/idea/idea-agent/
作者
马泽朋
发布于
2025年4月25日
许可协议