某括号炒冷饭

首先感谢两个大佬写的文章
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 :crazy_face:)再次感谢一下所有大佬和热老。

25 个赞

牛哇

2 个赞

强!!

1 个赞

?那么快的回复

1 个赞

都住在坛子里了是吧

1 个赞

眼花缭乱,绝世武功!

1 个赞

过了过了,纯抄作业

1 个赞

牛啊

1 个赞

牛哇,现在Java都做混淆了啊

1 个赞

万物皆可混淆 :dog:

1 个赞

太强了!

1 个赞

好好好

1 个赞

欲练此功

1 个赞

等下去试试 :+1:

1 个赞

666 括号还不需要升级新版本,看来还没想好怎么增加难度

2 个赞

很强

1 个赞

学到了

1 个赞

如此优秀!

janetfilter 插件比较方便

逮到大佬啦,ja插件确实更方便