首页
论坛
课程
招聘
[原创]IDEA 2019.1版本的破解文件JetbrainsCrack.jar分析
2019-5-28 16:35 32312

[原创]IDEA 2019.1版本的破解文件JetbrainsCrack.jar分析

2019-5-28 16:35
32312

0x1, 原因:

从网上找到IDEA的破解文件,好像各个版本都进行了保护处理,但是确实想了解它的实现,主要是关心它打补丁的类和对应处理,所以整理一下。
对应分析版本见附件,分析如下。

0x1.1, 反混淆:

这个jar文件从逆向的结果看应该是做了字符加密和混淆,考虑看是否可以反混淆:

λ **java -jar deobfuscator-1.0.0.jar --config detect.yml**
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator - Loading classpath
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator - Loading input
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator - Detecting known obfuscators
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator -
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator - RuleSuspiciousClinit: Zelix Klassmaster typically embeds decryption code in <clinit>. This sample may have been obfuscated with Zelix Klassmaster
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator -    Found suspicious <clinit> in fuck_the_regulations/ce
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator - Recommend transformers:
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator -    None
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator -
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator - RuleEnhancedStringEncryption: Zelix Klassmaster has several modes of string encryption. This mode is similar to the simple mode, but adds an additional layer of decryption by calling a method with signature (II)Ljava/lang/String;
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator -    Found potential enhanced string encrypted class fuck_the_regulations/dF
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator - Recommend transformers:
[main] INFO com.javadeobfuscator.deobfuscator.Deobfuscator -    com.javadeobfuscator.deobfuscator.transformers.zelix.string.EnhancedStringEncryptionTransformer
λ **java -jar deobfuscator-1.0.0.jar --config config.yml**

从上面的信息可以知道是使用了ZKM(Zelix Klassmaster)工具处理保护,所以配置对应的transformers:
由于支持有限,可以进行字符解密,得到了没有字符加密的jar文件。

0x1.2代码分析:

通过Manifest.mf中的配置信息,定位premain为Premain-Class: fuck_the_regulations.fN :
premain()
+-ew.main() # 作者信息打印
+-bk.b(instrumentation) # 重点分析
作者信息字符串:

System.out.print("\n\n ====================================================\n 
                 =======        Jetbrains License Crack       =======\n 
                 =======           https://zhile.io           =======\n ====================================================\n\n 
                 @See: https://zhile.io/2018/08/17/jetbrains-license-server-crack.html\n\n 
                 @Version: 2.0.1, @Build Date: 2019-04-03\n\n\n");

调用处理函数:

         public static void b(final Instrumentation instrumentation) {
             final int[] b = b();
             try {
                 try {
                     aP.a("jetbrains-license-server", InetAddress.getByName("v2.wowchina.me").getHostAddress());
                 }
                 catch (Exception ex4) {}
                 final StringBuilder sb = new StringBuilder("fuck_the_regulations.c0");
                 sb.reverse();
                 instrumentation.addTransformer((ClassFileTransformer)Class.forName(fa.a(sb.reverse().toString())).getDeclaredConstructor((Class<?>[])new Class[0]).newInstance(new Object[0]));
             }
                    ......
         }

可以看到字符串已经解密了,对于javaagent的关键代码应该是addTransformer操作,从上面的字符串信息应该在fuck_the_regulations.c0处理。
找到对应的fuck_the_regulations.c0:
transform函数就是进行破解修改的核心函数,它的原型:
public byte[] transform(final ClassLoader loader, final String className, final Class<?> classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer)
至此对这个破解文件中的热代理修改就清楚了,通过查找类sun/security/rsa/RSASignature和sun/net/www/protocol/https/Handler,再定位到修改类,调用javaassist进行代码更新.

关键jar中的类信息,进行混淆关键代码还原:

通过和javassist的代码分析:
bN ===> javassist.CtClass
aO ===> javassist.ClassPool
dd ===> javassist.CtField
dc ===> javassist.CtConstructor
dL ===> javassist.CtBehavior ###
dH ===> javassist.CtNewMethod

0x1.3 破解调试:

在配置了对应的javaagent参数后,开始进行激活,同时监控idea发送的数据包信息:
1,PING
/rpc/ping.action
2,获取证书信息:
/rpc/obtainTicket.action
因此从这个分析中,它会配置激活服务器:http://jetbrains-license-server,上面的代码中有一处对应处理:

 aP.a("jetbrains-license-server", InetAddress.getByName("v2.wowchina.me").getHostAddress());

通过分析数据抓包,上面的两个请求目标IP为:47.88.242.176 ,但是这个地址是w2.wowchina.me的DNS解析结果,原来上面的这句操作是动态更新JVM的DNS缓存,基本就是自动修改hosts文件吧。
另外,测试服务器请求:

http://47.88.242.176/rpc/obtainTicket.action?buildDate=20190326&buildNumber=2019.1.2+Build+IU-191.7141.44&clientVersion=6&hostName=hangzhou.wawaha&machineId=6d244116-d184-4219-asdf-dac34567890c&productCode=49c202d4-ac56-452b-bb84-735056242fb3&productFamilyId=49c202d4-ac56-452b-bb84-735056242fb3&salt=1559706767295&secure=false&userName=wawaha&version=2019100&versionNumber=2019100

就不上结果了,可以自己测试,会返回一个XML格式结果。
同时,因为IDEA又更新了2019.1.3,作者5.29号又更新了文件,这次使用了新的加密,上面的反混淆不太好用了,不过作者没有重写逻辑,应该是做了适应Patch修改,其实关健字符串通过手工添加println的方式输出就OK了,因为加密都是静态变量,附件代码补充了新的版本的破解信息,不过没有测试和完成,有兴趣的同学可以交流继续,本文只是学:
1, 了解反混淆;
2, 分析了反混淆框架deobfuscator;
3, 了解了字节码,在最新的版本中,通过Recaf直接给字节码插入打印语句,输出结果还是比较好玩的,不需要那么费事。
4, TODO:附件代码测试可以破解2019.1.2 版本,但是依赖作者的认证服务器:v2.wowchina.me,不过发现作者在做服务器发现的时候,能自动填上,不太清楚怎么做的,没有去找代码分析了。

0x2, 分析结论:

从上面的处理中,应该包括两部分:
1,需要认证服务器: 网上有一些版本的代码;没有测试,从返回的认证XML内容估计逻辑差不多。
2,处理授权,通过替换Public Key.
3,处理在线验证,通过对“sun/net/www/protocol/https/Handler”解决。
4,其实另外也有一个作者:rover12421作了一个本地颁发激活码的方式,不过他的jar真恶心,全是不可见字符的混淆,不和他磕了,查找他早期的keygen, patch还是有不少内容的,有他们及时更新就OK了。
这次是最后更新


第五届安全开发者峰会(SDC 2021)议题征集正式开启!

最后于 2019-12-26 09:30 被nevinhappy编辑 ,原因: Upload My Source code .
上传的附件:
收藏
点赞6
打赏
分享
最新回复 (44)
雪    币: 464
活跃值: 活跃值 (1600)
能力值: ( LV12,RANK:400 )
在线值:
发帖
回帖
粉丝
UzJu 活跃值 7 2019-5-28 16:45
2
0
雪    币: 233
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
周癫 活跃值 2019-5-28 16:53
3
0
雪    币: 834
活跃值: 活跃值 (1898)
能力值: ( LV9,RANK:176 )
在线值:
发帖
回帖
粉丝
nevinhappy 活跃值 2 2019-6-5 18:59
4
0
更新了测试代码,算是结束了,这个作者的思路和其它在码云上找到的版本还有一些不同,学习了一把。
雪    币: 834
活跃值: 活跃值 (1898)
能力值: ( LV9,RANK:176 )
在线值:
发帖
回帖
粉丝
nevinhappy 活跃值 2 2019-6-19 19:24
5
0
整了这么久,怎么没人出来提点啥? 哪怕说上次提供的代码不能用也行!!!
雪    币: 7004
活跃值: 活跃值 (440)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zpob 活跃值 2019-6-19 20:17
6
0
不错啊,还差生成证书自签就完整了
雪    币: 834
活跃值: 活跃值 (1898)
能力值: ( LV9,RANK:176 )
在线值:
发帖
回帖
粉丝
nevinhappy 活跃值 2 2019-6-20 09:04
7
0
已经有参考了,估计需要按版本区分验证算法和生成公、私钥就可以了。
https://gitee.com/zrla/JetBrains-License-Server
雪    币: 1891
活跃值: 活跃值 (194)
能力值: ( LV7,RANK:116 )
在线值:
发帖
回帖
粉丝
kalikaikai 活跃值 1 2019-6-20 12:00
8
0
感谢分享思路 
雪    币: 89
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
kyleo 活跃值 2019-6-22 15:57
9
0
感谢楼主!!
最后于 2019-6-22 16:16 被kyleo编辑 ,原因: 无
雪    币: 732
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
MrChuck 活跃值 2019-12-26 00:03
10
0
0x1.1, 反混淆 执行下面的命令后
java -jar deobfuscator-1.0.0.jar --config detect.yml 
没有生成 jar,是为何?
雪    币: 834
活跃值: 活跃值 (1898)
能力值: ( LV9,RANK:176 )
在线值:
发帖
回帖
粉丝
nevinhappy 活跃值 2 2019-12-26 09:28
11
0
MrChuck 0x1.1, 反混淆 执行下面的命令后 java -jar deobfuscator-1.0.0.jar --config detect.yml 没有生成 jar,是为何?
进行反混淆有两步,第一步是使用detect.yml,进行混淆探测,通过查看探测到的信息,进行反混淆transformer的配置;第二步,通过配置后的config.yml,再生成反混淆后的结果。
雪    币: 732
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
MrChuck 活跃值 2019-12-26 22:13
12
0
nevinhappy 进行反混淆有两步,第一步是使用detect.yml,进行混淆探测,通过查看探测到的信息,进行反混淆transformer的配置;第二步,通过配置后的config.yml,再生成反混淆后的结果。
多谢
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
kekeY 活跃值 2020-1-6 11:49
13
0
所以作者的认证服务器挂了, 那些激活码都没用了。 如果有本地的更好
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
git_57087fredrik93-tech 活跃值 2020-1-11 23:47
14
1
The line
       aP.a("jetbrains-license-server", InetAddress.getByName("v2.wowchina.me").getHostAddress());
resolves v2.wowchina.me and adds the ip to java hosts file associating the simbolic name jetbrains-license-server

It modifies
       sun.security.rsa.RSASignature.engineInitVerify(java.security.PublicKey p)
adding
       private static final PublicKey __k_joca;
    private static final PublicKey __k_jnca;
    private static final PublicKey __k_loca;
    private static final PublicKey __k_lnca;
    private static final BigInteger ______e=new BigInteger("65537");

 try{
       __k_joca=KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(new BigInteger("<JetProfileCAModulus>"),______e));
       __k_jnca=KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(new BigInteger("<FakeJetProfileCAModulus>"),______e));
       __k_loca=KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(new BigInteger("<JetbrainsModulus"),______e));
       __k_lnca=KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(new BigInteger("<FakeJetbrainsModulus>"),______e));
       } catch(Exception e){
               throw new RuntimeException(e);
       }
       if($1.equals(__k_joca))
               $1=__k_jnca;
       else if($1.equals(__k_loca))
               $1=__k_lnca;
       
So here is the key replacement.
       
There are two other transformers that are similar among them but seems that are not used:
       fuck_the_regulations.eQ
       fuck_the_regulations.Y
       
Seems that xml response contains a comment with signature and fake certificate that should pair with server fake private key.
雪    币: 197
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
jon1scr 活跃值 2020-1-15 21:27
15
0
https://bayfiles.com/d0d7S5Mcna/jetbrains-agent-latest_zip
雪    币: 24
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
CSinper 活跃值 2020-5-31 16:44
16
0
4-10号的jetbrains-agent用deobfuscator 已经不能成功了
雪    币: 3017
活跃值: 活跃值 (39)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
blowfish 活跃值 2020-5-31 19:40
17
0
不知道有人验证过这个模拟floating server的keygen working不
雪    币: 200
活跃值: 活跃值 (44)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
goldenegg 活跃值 2 2020-7-8 22:01
18
1
感谢你的内容,在你的基础上研究了下,已经都搞明白了。
服务端也自己写了,你这个还是重用原作者的。
已经成功搞定目前的2020系列全家桶。
同时改动很小,理论上只需要 HOOK 一个函数
(连那个sun/net/www/protocol/https/Handler都好像不必须,因为在线验证好像没了,anyway,还留着它。)

雪    币: 58
活跃值: 活跃值 (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gogogoyouxi 活跃值 2020-7-16 10:10
19
0
goldenegg 感谢你的内容,在你的基础上研究了下,已经都搞明白了。 服务端也自己写了,你这个还是重用原作者的。 已经成功搞定目前的2020系列全家桶。 同时改动很小,理论上只需要 HOOK 一个函数 (连那 ...
大牛,可以参考一下吗,谢谢
雪    币: 35
活跃值: 活跃值 (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
浪里小白龙 活跃值 2020-8-4 19:52
20
0
goldenegg 感谢你的内容,在你的基础上研究了下,已经都搞明白了。 服务端也自己写了,你这个还是重用原作者的。 已经成功搞定目前的2020系列全家桶。 同时改动很小,理论上只需要 HOOK 一个函数 (连那 ...
大牛有分析思路么,想学习学习
雪    币: 30
活跃值: 活跃值 (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
retaaa 活跃值 2020-9-3 15:01
21
0
小白不懂求问,早期jetbrains破解都是keygen,keygen里的私钥cracker是怎么获得的?
雪    币: 834
活跃值: 活跃值 (1898)
能力值: ( LV9,RANK:176 )
在线值:
发帖
回帖
粉丝
nevinhappy 活跃值 2 2021-3-19 09:12
22
0

同步更新一个:

上传的附件:
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_X_120 活跃值 2021-3-19 09:40
23
0
雪    币: 2415
活跃值: 活跃值 (604)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
guduzhe 活跃值 2021-4-26 14:01
24
2
nevinhappy 同步更新一个:

现在的破解失效,原来就是密钥被取消了,/etc/hosts屏蔽掉这个地址就可以了


127.0.0.1     bs.studycoder.com


BetterIntelliJ-1.20的代码

package com.asm.test;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.Iterator;
import java.util.List;

public class IdeaTransformer implements ClassFileTransformer {

    @Override
    public byte[] transform(ClassLoader var1, String var2, Class var3, ProtectionDomain var4, byte[] var5) throws IllegalClassFormatException {
        if (var2.equals("java/io/ByteArrayInputStream")) {
            ClassReader var9 = new ClassReader(var5);
            ClassNode var10 = new ClassNode();
            var9.accept(var10, 0);

            List var11 = var10.methods;
            Iterator var12 = var11.iterator();
            while (var12.hasNext()) {
                MethodNode var13 = var12.next();
                if (var13.name.equals("") && var13.desc.equals("([B)V")) {
                    InsnList var14 = var13.instructions;
                    InsnList var15 = new InsnList();

                    //非static方法,变量0为this对象

                    //调用父类构造方法
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 0));
                    var15.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/io/InputStream", "", "()V", false));

                    //修改mark值为0
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 0));
                    var15.add(new InsnNode(Opcodes.ICONST_0));
                    var15.add(new FieldInsnNode(Opcodes.PUTFIELD, "java/io/ByteArrayInputStream", "mark", "I"));

                    //将构造方法参数byte[]经过base64编码后存入变量2
                    var15.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/util/Base64", "getEncoder", "()Ljava/util/Base64$Encoder;", false));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 1));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/util/Base64$Encoder", "encodeToString", "([B)Ljava/lang/String;", false));
                    var15.add(new VarInsnNode(Opcodes.ASTORE, 2));

                    //字符串和变量2比较是否一致
                    var15.add(new LdcInsnNode("MIIEPjCCAiagAwIBAgIBBTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTE1MTEwMjA4MjE0OFoXDTE4MTEwMTA4MjE0OFowETEPMA0GA1UEAwwGcHJvZDN5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcQkq+zdxlR2mmRYBPzGbUNdMN6OaXiXzxIWtMEkrJMO/5oUfQJbLLuMSMK0QHFmaI37WShyxZcfRCidwXjot4zmNBKnlyHodDij/78TmVqFl8nOeD5+07B8VEaIu7c3E1N+e1doC6wht4I4+IEmtsPAdoaj5WCQVQbrI8KeT8M9VcBIWX7fD0fhexfg3ZRt0xqwMcXGNp3DdJHiO0rCdU+Itv7EmtnSVq9jBG1usMSFvMowR25mju2JcPFp1+I4ZI+FqgR8gyG8oiNDyNEoAbsR3lOpI7grUYSvkB/xVy/VoklPCK2h0f0GJxFjnye8NT1PAywoyl7RmiAVRE/EKwIDAQABo4GZMIGWMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGEpG9oZGcfLMGNBkY7SgHiMGgTcMEgGA1UdIwRBMD+AFKOetkhnQhI2Qb1t4Lm0oFKLl/GzoRykGjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBggkA0myxg7KDeeEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQC9WZuYgQedSuOc5TOUSrRigMw4/+wuC5EtZBfvdl4HT/8vzMW/oUlIP4YCvA0XKyBaCJ2iX+ZCDKoPfiYXiaSiH+HxAPV6J79vvouxKrWg2XV6ShFtPLP+0gPdGq3x9R3+kJbmAm8w+FOdlWqAfJrLvpzMGNeDU14YGXiZ9bVzmIQbwrBA+c/F4tlK/DV07dsNExihqFoibnqDiVNTGombaU2dDup2gwKdL81ua8EIcGNExHe82kjF4zwfadHk3bQVvbfdAwxcDy4xBjs3L4raPLU3yenSzr/OEur1+jfOxnQSmEcMXKXgrAQ9U55gwjcOFKrgOxEdek/Sk1VfOjvS+nuM4eyEruFMfaZHzoQiuw4IqgGc45ohFH0UUyjYcuFxxDSU9lMCv8qdHKm+wnPRb0l9l5vXsCBDuhAGYD6ss+Ga+aDY6f/qXZuUCEUOH3QUNbbCUlviSz6+GiRnt1kA9N2Qachl+2yBfaqUqr8h7Z2gsx5LcIf5kYNsqJ0GavXTVyWh7PYiKX4bs354ZQLUwwa/cG++2+wNWP+HtBhVxMRNTdVhSm38AknZlD+PTAsWGu9GyLmhti2EnVwGybSD2Dxmhxk3IPCkhKAK+pl0eWYGZWG3tJ9mZ7SowcXLWDFAk0lRJnKGFMTggrWjV8GYpw5bq23VmIqqDLgkNzuoog=="));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 2));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false));

                    //创建两个标签,用于跳转,创建位置随意,主要看添加位置
                    LabelNode var16 = new LabelNode();
                    LabelNode var17 = new LabelNode();

                    //字符比较结果,一致为true,true时跳转到var16标签位置
                    var15.add(new JumpInsnNode(Opcodes.IFNE, var16));

                    //不一致继续比较下一个字符串
                    var15.add(new LdcInsnNode("MIIFOzCCAyOgAwIBAgIJANJssYOyg3nhMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0EwHhcNMTUxMDAyMTEwMDU2WhcNNDUxMDI0MTEwMDU2WjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0tQuEA8784NabB1+T2XBhpB+2P1qjewHiSajAV8dfIeWJOYGy+ShXiuedj8rL8VCdU+yH7Ux/6IvTcT3nwM/E/3rjJIgLnbZNerFm15Eez+XpWBlm5fDBJhEGhPc89Y31GpTzW0vCLmhJ44XwvYPntWxYISUrqeR3zoUQrCEp1C6mXNXEpqIGIVbJ6JVa/YI+pwbfuP51o0ZtF2rzvgfPzKtkpYQ7m7KgA8g8ktRXyNrz8boiwg7RRPeqs4uL/RK8d2KLpgLqcAB9WDpcEQzPWegbDrFO1F3z4UVNH6hrMfOLGVAxoiQhNFhZj6RumBXlPS0rmCOCkUkWrDr3l6Z3spUVgoeea+QdX682j6t7JnakaOwjzwY777SrZoi9mFFpLVhfb4haq4IWyKSHR3/0BlWXgcgI6w6LXm+V+ZgLVDON52FLcxnfftaBJz2yclEwBohq38rYEpb+28+JBvHJYqcZRaldHYLjjmb8XXvf2MyFeXrSopYkdzCvzmiEJAewrEbPUaTllogUQmnv7Rv9sZ9jfdJ/cEn8e7GSGjHIbnjV2ZMQ9vTpWjvsT/cqatbxzdBo/iEg5i9yohOC9aBfpIHPXFw+fEj7VLvktxZY6qThYXRRus1WErPgxDzVpNp+4gXovAYOxsZak5oTV74ynv1aQ93HSndGkKUE/qA/JECAwEAAaOBhzCBhDAdBgNVHQ4EFgQUo562SGdCEjZBvW3gubSgUouX8bMwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAjrPAZ4xC7sNiSSqh69s3KJD3Ti4etaxcrSnD7r9rJYpKBMviCKZRKFbLv+iaF5JK5QWuWdlgA37ol7mLeoF7aIA9b60Ag2OpgRICRG79QY7ouLviF/yRMqm6yno7NYkGLd61e5Huu+BfT459MWG9RVkG/DY0sGfkyTHJS5xrjBV6hjLG0lf3orwqOlqSNRmhvn9sMzwAP3ILLM5VJC5jNF1zAk0jrqKz64vuA8PLJZlLS9TZJIYwdesCGfnN2AETvzf3qxLcGTF038zKOHUMnjZuFW1ba/12fDK5GJ4i5y+nfDWVZVUDYOPUixEZ1cwzmf9Tx3hR8tRjMWQmHixcNC8XEkVfztID5XeHtDeQ+uPkX+jTDXbRb+77BP6n41briXhm57AwUI3TqqJFvoiFyx5JvVWG3ZqlVaeU/U9e0gxn8qyR+ZA3BGbtUSDDs8LDnE67URzK+L+q0F2BC758lSPNB2qsJeQ63bYyzf0du3wB/gb2+xJijAvscU3KgNpkxfGklvJD/oDUIqZQAnNcHe7QEf8iG2WqaMJIyXZlW3me0rn+cgvxHPt6N4EBh5GgNZR4l0eaFEV+fxVsydOQYo1RIyFMXtafFBqQl6DDxujlFeU3FZ+Bcp12t7dlM4E0/sS1XdL47CfGVj4Bp+/VbF862HmkAbd7shs7sDQkHbU="));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 2));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false));

                    //字符比较结果,不一致时跳转到var17标签位置
                    var15.add(new JumpInsnNode(Opcodes.IFEQ, var17));

                    //以上两处字符串比较一致时都运行到此处
                    //标记var16标签
                    var15.add(var16);

                    //替换传入参数
                    var15.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/util/Base64", "getDecoder", "()Ljava/util/Base64$Decoder;", false));
                    var15.add(new LdcInsnNode("MIIDlzCCAn+gAwIBAgIBCTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDEw1KZXRQcm9maWxlIENBMCAXDTE4MTEwMTEyMjk0NloYDzIwOTkwODA5MDIyNjA3WjBoMQswCQYDVQQGEwJDWjEOMAwGA1UECBMFTnVzbGUxDzANBgNVBAcTBlByYWd1ZTEZMBcGA1UEChMQSmV0QnJhaW5zIHMuci5vLjEdMBsGA1UEAxMUcHJvZDN5LWZyb20tMjAxODExMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdXyaNhhRySH1a8d7c8SlLLFdNcQP8M3gNnq7gudcpHC651qxRrN7Qks8gdXlIkA4u3/lp9ylp95GiIIDo4ydYje8vlTWDq02bkyWW/G7gZ3hkbBhRUK/WnNyr2vwWoOgwx5CfTRMjKkPkfD/+jffkfNfdGmGcg9yfnqPP9/AizKzWTsXSeS+0jZ8Nw5tiYFW+lpceqlzwzKdTHug7Vs0QomUPccRtZB/TBBEuiC7YzrvLg4Amu0I48ETAcch/ztt00nx/oj/fu1DTnz4Iz4ilrNY+WVIEfDz/n3mz+PKI9kM+ZeB0jAuyLsiC7skGpIVGX/2HqmZTtJKBZCoveAiVAgMBAAGjgZkwgZYwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TAJBgNVHRMEAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsGA1UdDwQEAwIFoDAdBgNVHQ4EFgQUYSkb2hkZx8swY0GRjtKAeIwaBNwwDQYJKoZIhvcNAQELBQADggEBAJZOakWgjfY359glviVffBQFxFS6C+4WjYDYzvzjWHUQoGBFKTHG4xUmTVW7y5GnPSvIlkaj49SzbD9KuiTc77GHyFCTwYMz+qITgbDg3/ao/x/be4DD/k/byWqW4Rb8OSYCshX/fNI4Xu+hxazh179taHX4NaH92ReLVyXNYsooq7mE5YhR9Qsiy35ORviQLrgFrMCGCxT9DWlFBuiPWIOqN544sL9OzFMz+bjqjCoAE/xfIJjI7H7SqGFNrx/8/IuF0hvZbO3bLIz+BOR1L2O+qT728wK6womnp2LLANTPbwu7nf39rpP182WW+xw2z9MKYwwMDwGR1iTYnD4/Sjw="));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", "(Ljava/lang/String;)[B", false));
                    var15.add(new VarInsnNode(Opcodes.ASTORE, 1));


                    //标记var17标签
                    var15.add(var17);

                    //buf赋值
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 0));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 1));
                    var15.add(new FieldInsnNode(Opcodes.PUTFIELD, "java/io/ByteArrayInputStream", "buf", "[B"));

                    //pos赋值0
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 0));
                    var15.add(new InsnNode(Opcodes.ICONST_0));
                    var15.add(new FieldInsnNode(Opcodes.PUTFIELD, "java/io/ByteArrayInputStream", "pos", "I"));

                    //count赋值数组长度
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 0));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 1));
                    var15.add(new InsnNode(Opcodes.ARRAYLENGTH));
                    var15.add(new FieldInsnNode(Opcodes.PUTFIELD, "java/io/ByteArrayInputStream", "count", "I"));

                    //返回
                    var15.add(new InsnNode(Opcodes.RETURN));

                    var14.clear();
                    var14.add(var15);

                    var13.exceptions.clear();
                    var13.visitEnd();

                    ClassWriter var18 = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
                    var10.accept(var18);

                    return var18.toByteArray();
                }
            }
        }
        if (var2.equals("java/util/Arrays")) {
            ClassReader var9 = new ClassReader(var5);
            ClassNode var10 = new ClassNode();
            var9.accept(var10, 0);

            List var11 = var10.methods;
            Iterator var12 = var11.iterator();
            while (var12.hasNext()) {
                MethodNode var13 = var12.next();
                if (var13.name.equals("equals") && var13.desc.equals("([B[B)Z")) {
                    InsnList var14 = var13.instructions;
                    InsnList var15 = new InsnList();

                    LabelNode var16 = new LabelNode();
                    LabelNode var17 = new LabelNode();

                    //static方法,变量0为第一个参数,null跳到var16
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 0));
                    var15.add(new JumpInsnNode(Opcodes.IFNULL, var16));

                    var15.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/util/Base64", "getEncoder", "()Ljava/util/Base64$Encoder;", false));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 0));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/util/Base64$Encoder", "encodeToString", "([B)Ljava/lang/String;", false));
                    var15.add(new VarInsnNode(Opcodes.ASTORE, 2));


                    var15.add(new LdcInsnNode("dcc+F+1UvLoQW9oLY67mo3ImO2dEDv6t0aMRLmu3bUMZJ5c5c8EAWOGZ75ek809JiWLd1k5IcgZaXccSIKGaAQ=="));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 2));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false));

                    //一致时跳转到var17
                    var15.add(new JumpInsnNode(Opcodes.IFNE, var17));

                    var15.add(new LdcInsnNode("AXilfPnlA2jsnBcIuPj+SOz4yBvnVKtbRcaw5aPMcGvIo+y1BrbiDlhVeLzpOOccp6goKo3j82bLrEBf5tcG7w=="));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 2));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false));


                    //不一致时转到var16
                    var15.add(new JumpInsnNode(Opcodes.IFEQ, var16));

                    //以上两处字符串比较一致时都运行到此处
                    var15.add(var17);

                    //返回true
                    var15.add(new InsnNode(Opcodes.ICONST_1));
                    var15.add(new InsnNode(Opcodes.IRETURN));

                    var15.add(var16);

                    //以上代码插入到方法最前最前
                    var14.insertBefore(var14.getFirst(), var15);

                    var13.visitEnd();

                    ClassWriter var18 = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
                    var10.accept(var18);

                    return var18.toByteArray();
                }
            }
        }
        if (var2.equals("java/net/URL")) {
            ClassReader var9 = new ClassReader(var5);
            ClassNode var10 = new ClassNode();
            var9.accept(var10, 0);

            List var11 = var10.methods;
            Iterator var12 = var11.iterator();
            while (var12.hasNext()) {
                MethodNode var13 = var12.next();
                //public URL(URL context, String spec, URLStreamHandler handler)
                if (var13.name.equals("") && var13.desc.equals("(Ljava/net/URL;Ljava/lang/String;Ljava/net/URLStreamHandler;)V")) {
                    InsnList var14 = var13.instructions;
                    InsnList var15 = new InsnList();

                    LabelNode var16 = new LabelNode();

                    var15.add(new VarInsnNode(Opcodes.ALOAD, 2));
                    var15.add(new JumpInsnNode(Opcodes.IFNULL, var16));

                    var15.add(new VarInsnNode(Opcodes.ALOAD, 2));
                    var15.add(new LdcInsnNode("https://account.jetbrains.com/lservice/rpc/validateKey.action"));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "startsWith", "(Ljava/lang/String;)Z", false));
                    var15.add(new JumpInsnNode(Opcodes.IFEQ, var16));

                    //替换网址
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 2));
                    var15.add(new LdcInsnNode("https://account.jetbrains.com/lservice/rpc/validateKey.action"));
                    var15.add(new LdcInsnNode("http://bs.studycoder.com/lservice/rpc/validateKey.action"));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "replace", "(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;", false));
                    var15.add(new VarInsnNode(Opcodes.ASTORE, 2));

                    var15.add(var16);

                    var14.insertBefore(var14.getFirst(), var15);

                    var13.visitEnd();

                }

                if (var13.name.equals("getHost") && var13.desc.equals("()Ljava/lang/String;")) {
                    InsnList var14 = var13.instructions;
                    InsnList var15 = new InsnList();

                    LabelNode var16 = new LabelNode();

                    var15.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", "()[Ljava/lang/StackTraceElement;", false));
                    var15.add(new InsnNode(Opcodes.ICONST_2));
                    var15.add(new InsnNode(Opcodes.AALOAD));
                    //变量0为this,无参数,存储到变量1
                    var15.add(new VarInsnNode(Opcodes.ASTORE, 1));

                    //字符串和host比较
                    var15.add(new LdcInsnNode("bs.studycoder.com"));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 0));
                    var15.add(new FieldInsnNode(Opcodes.GETFIELD, "java/net/URL", "host", "Ljava/lang/String;"));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false));

                    //不一致跳转
                    var15.add(new JumpInsnNode(Opcodes.IFEQ, var16));

                    //字符串和path比较
                    var15.add(new LdcInsnNode("/lservice/rpc/validateKey.action"));
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 0));
                    var15.add(new FieldInsnNode(Opcodes.GETFIELD, "java/net/URL", "path", "Ljava/lang/String;"));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false));

                    //不一致跳转
                    var15.add(new JumpInsnNode(Opcodes.IFEQ, var16));

                    //取上面保存变量
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 1));
                    //null跳转
                    var15.add(new JumpInsnNode(Opcodes.IFNULL, var16));

                    //比较调用堆栈的类所属包
                    var15.add(new VarInsnNode(Opcodes.ALOAD, 1));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false));
                    var15.add(new LdcInsnNode("com.jetbrains"));
                    var15.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "startsWith", "(Ljava/lang/String;)Z", false));
                    //不一致跳转
                    var15.add(new JumpInsnNode(Opcodes.IFEQ, var16));

                    var15.add(new LdcInsnNode("account.jetbrains.com"));
                    var15.add(new InsnNode(Opcodes.ARETURN));

                    var15.add(var16);

                    var14.insertBefore(var14.getFirst(), var15);

                    var13.visitEnd();
                }
            }
            ClassWriter var18 = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
            var10.accept(var18);
            return var18.toByteArray();
        }
        return var5;
    }
}


最后于 2021-4-26 15:17 被guduzhe编辑 ,原因:
雪    币: 834
活跃值: 活跃值 (1898)
能力值: ( LV9,RANK:176 )
在线值:
发帖
回帖
粉丝
nevinhappy 活跃值 2 2021-4-26 16:08
25
0
guduzhe nevinhappy 同步更新一个: 现在的破解失效,原来就是密钥被取消了,/etc/hosts屏蔽掉这个地址就可以了127.0.0.1& ...
你这个是还原的,还是自己写的?
游客
登录 | 注册 方可回帖
返回