首先感谢两个大佬写的文章
https://linux.do/t/topic/469
https://linux.do/t/topic/62342
看了两个大佬的文章,我在想能不能打包一个jar把某彩虹和JB一起扬了,于是就有了这篇没有技术含量的文章。
jadx分析
还是按照惯例用jadx打开插件jar包
跟着大佬的思路走到这里,我们只需要让f960
这三个检测都返回False即可。
C0335.m1875()是检测ja-netfilter的,我们参考https://linux.do/t/topic/469 li佬的思路,没用上,所以不用管。
C0565.m3293()
和C0130.m715()
的代码分别如下
观察两段代码可以看到catch语句中均会赋值false,这正是我们想要的结果,所以我们只需要让try代码块中抛出异常即可。两个函数的try代码块中又都调用了Class.forName方法,这不是更加美滋滋,直接使用bytebuddy库来hook它,实现一鱼两吃。
C0565.m3293()的第一个Class.forName中传入的参数 C0361.m2037() 结果为com.intellij.diagnostic.VMOptions
C0130.m715()的第一个Class.forName中传入的参数 C0361.m2041() 结果为jdk.internal.org.objectweb.asm.Type
检测到参数与它们相等直接抛出异常
代码实现
首先修改一下li佬的MyAgent类,加一个过rainbow的检测 ,其它原封不动
public class MyAgent {
public static void premain(String agentArgs, Instrumentation inst) throws Exception {
System.out.println("premain");
AgentBuilder agentBuilder = new AgentBuilder.Default()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.ignore(ElementMatchers.nameStartsWith("net.bytebuddy."));
// .with(new MyAgentListener());
// 使得证书验证通过
agentBuilder.type(ElementMatchers.named("java.math.BigInteger"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
.visit(Advice.to(BigIntegerAdvice.class)
.on(ElementMatchers.named("oddModPow"))))
.installOn(inst);
// 使得软件无法联查询license是否有效
agentBuilder.type(ElementMatchers.named("sun.net.www.http.HttpClient"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
.visit(Advice.to(HttpClientAdvice.class)
.on(ElementMatchers.named("openServer"))))
.installOn(inst);
//过rainbow检测
agentBuilder.type(ElementMatchers.named("java.lang.Class"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
.visit(Advice.to(ForNameAdvice.class)
.on(ElementMatchers.isStatic().and(ElementMatchers.named("forName")).and(ElementMatchers.takesArgument(0, String.class)))))
.installOn(inst);
}
}
ForNameAdvice实现如下
public class ForNameAdvice{
@Advice.OnMethodEnter
public static void intercept(@Advice.Argument(0) String className) throws ClassNotFoundException {
if ("com.intellij.diagnostic.VMOptions".equals(className)) {
System.out.println("find VMOptions");
throw new ClassNotFoundException("Blocking access to " + className);
}
if ("jdk.internal.org.objectweb.asm.Type".equals(className)) {
System.out.println("find asm.Type");
throw new ClassNotFoundException("Blocking access to " + className);
}
}
}
license代码实现直接复制li佬的代码,再加上热老提供的license
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import java.io.FileInputStream;
import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws Exception {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream("ca.crt"));
// 自己修改 license内容
// 注意licenseId要一致
// 里面的内容是激活webstorm
// String licensePart = "{\"licenseId\":\"MOUGH5FKDV\",\"licenseeName\":\"haha\",\"assigneeName\":\"novice.li\",\"assigneeEmail\":\"\",\"licenseRestriction\":\"\",\"checkConcurrentUse\":false,\"products\":[{\"code\":\"PCWMP\",\"fallbackDate\":\"2026-09-14\",\"paidUpTo\":\"2026-09-14\",\"extended\":true},{\"code\":\"PSI\",\"fallbackDate\":\"2026-09-14\",\"paidUpTo\":\"2026-09-14\",\"extended\":true},{\"code\":\"WS\",\"fallbackDate\":\"2026-09-14\",\"paidUpTo\":\"2026-09-14\",\"extended\":false}],\"metadata\":\"0120230914PSAX000005\",\"hash\":\"TRIAL:-1920204289\",\"gracePeriodDays\":7,\"autoProlongated\":false,\"isAutoProlongated\":false}";
// String licenseId = "MOUGH5FKDV";
String licensePart = "{\"licenseId\":\"F2VYMQ9U6T\",\"licenseeName\":\"whyyy\",\"licenseeType\":\"PERSONAL\",\"assigneeName\":\"\",\"assigneeEmail\":\"\",\"licenseRestriction\":\"\",\"checkConcurrentUse\":false,\"products\":[{\"code\":\"PRAINBOWBRACKET\",\"fallbackDate\":\"2024-05-22\",\"paidUpTo\":\"2025-03-04\",\"extended\":true}],\"metadata\":\"0120240412PPAM000005\",\"hash\":\"56351327\\/0:1542276074\",\"gracePeriodDays\":7,\"autoProlongated\":true,\"isAutoProlongated\":true,\"trial\":false,\"aiAllowed\":true}"
String licenseId = "F2VYMQ9U6T";
byte[] licensePartBytes = licensePart.getBytes(StandardCharsets.UTF_8);
String licensePartBase64 = Base64.getEncoder().encodeToString(licensePartBytes);
PrivateKey privateKey = getPrivateKey();
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privateKey);
signature.update(licensePartBytes);
byte[] signatureBytes = signature.sign();
String sigResultsBase64 = Base64.getEncoder().encodeToString(signatureBytes);
// verify
// Signature verifySignature = Signature.getInstance("SHA1withRSA");
// verifySignature.initVerify(cert.getPublicKey());
// verifySignature.update(Base64.getDecoder().decode(licensePartBase64));
// boolean verify = verifySignature.verify(Base64.getDecoder().decode(sigResultsBase64));
// System.out.println(verify);
// Combine results as needed
String result = licenseId + "-" + licensePartBase64 + "-" + sigResultsBase64 + "-" + Base64.getEncoder().encodeToString(cert.getEncoded());
System.out.println(result);
}
static PrivateKey getPrivateKey() throws Exception {
Security.addProvider(new BouncyCastleProvider());
PEMParser pemParser = new PEMParser(new FileReader("ca.key"));
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
Object object = pemParser.readObject();
KeyPair kp = converter.getKeyPair((PEMKeyPair) object);
return kp.getPrivate();
}
}
想用python生成license也行
from cryptography import x509
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.backends import default_backend
import base64
def load_certificate(cert_path):
with open(cert_path, 'rb') as cert_file:
cert = x509.load_pem_x509_certificate(cert_file.read(), default_backend())
return cert
def load_private_key(key_path, password=None):
with open(key_path, 'rb') as key_file:
private_key = load_pem_private_key(key_file.read(), password, default_backend())
return private_key
def main():
cert = load_certificate("ca.crt")
private_key = load_private_key("ca.key")
license_part = "{\"licenseId\":\"F2VYMQ9U6T\",\"licenseeName\":\"why\",\"licenseeType\":\"PERSONAL\",\"assigneeName\":\"\",\"assigneeEmail\":\"\",\"licenseRestriction\":\"\",\"checkConcurrentUse\":false,\"products\":[{\"code\":\"PRAINBOWBRACKET\",\"fallbackDate\":\"2024-05-22\",\"paidUpTo\":\"2025-03-04\",\"extended\":true}],\"metadata\":\"0120240412PPAM000005\",\"hash\":\"56351327\\/0:1542276074\",\"gracePeriodDays\":7,\"autoProlongated\":true,\"isAutoProlongated\":true,\"trial\":false,\"aiAllowed\":true}"
license_id = "F2VYMQ9U6T"
license_part_bytes = license_part.encode('utf-8')
license_part_base64 = base64.b64encode(license_part_bytes).decode('utf-8')
signature = private_key.sign(
license_part_bytes,
padding.PKCS1v15(),
hashes.SHA1()
)
sig_results_base64 = base64.b64encode(signature).decode('utf-8')
# cert_bytes = cert.public_bytes(serialization.Encoding.PEM)
# cert_base64 = base64.b64encode(cert_bytes).decode('utf-8')
# 获取以DER编码的证书字节
cert_der_bytes = cert.public_bytes(serialization.Encoding.DER)
# 对DER编码的证书字节进行Base64编码
cert_base64 = base64.b64encode(cert_der_bytes).decode('utf-8')
result = "{}-{}-{}-{}".format(license_id, license_part_base64, sig_results_base64, cert_base64)
print(result)
if __name__ == "__main__":
main()
验证一波
成功白嫖
叠甲
除了我提及的额外操作,其它过程都和li佬的一样,自己打包成jar然后按照li佬说的方式放到该放的地方即可白嫖,这里就不提供成品了。不懂jvav,代码都是gpt生成然后自己随便改改的,大佬轻喷(要喷就喷gpt )再次感谢一下所有大佬和热老。