自己动手,丰衣足食

0x00.前言

原文地址:mac App 破解之路六 studio 3t

突然过期
突然过期
草
必须按年订阅
必须按年订阅

百度(拒绝搜了一大圈,发现大都是这套已经失效的.bat批处理脚本

1
FOR /f "tokens=1,2,* " %%i IN ('reg query "HKEY_CURRENT_USER\Software\JavaSoft\Prefs\3t\mongochef\enterprise" ^| find /V "installation" ^| find /V "HKEY"') DO ECHO yes | reg add "HKEY_CURRENT_USER\Software\JavaSoft\Prefs\3t\mongochef\enterprise" /v %%i /t REG_SZ /d ""

原理是重置激活时间,但是到现在这个版本(2019.7.0)即使你删掉全部键值:计算机\HKEY_CURRENT_USER\Software\JavaSoft\Prefs\3t\mongochef\enterprise,下次启动时仍然会自动加载
而且你去修改那个所谓的installation-date-2019.7.0也是无济于事的……

注册表
注册表

谷歌搜罗了一圈终于找到个源码逆向的,太不容易了(

0x01.开工

data-man-mongodb-ent-2019.7.0.jar
data-man-mongodb-ent-2019.7.0.jar

直接上jadx-gui-1.0.0-3-with-jre-windows伺候

trial
trial
+1s
+1s
thank
thank

看了两眼发现与原文源码几乎完全一致,突然就懒得再去截图了……

发现 IDEA 也自带反编译工具,而且成功率要更高
发现 IDEA 也自带反编译工具,而且成功率要更高

Fernflower还是强啊(wsl
这里贴一下2019.7.1版本的t3.common.lic.ag以供参考

1
//
2
// Source code recreated from a .class file by IntelliJ IDEA
3
// (powered by Fernflower decompiler)
4
//
5
6
package t3.common.lic;
7
8
import java.time.Instant;
9
import java.time.LocalDate;
10
import java.time.LocalDateTime;
11
import java.time.ZoneOffset;
12
import java.time.chrono.ThaiBuddhistChronology;
13
import java.time.format.DateTimeFormatter;
14
import java.time.format.DateTimeParseException;
15
import java.util.EnumSet;
16
import java.util.function.Predicate;
17
import org.pmw.tinylog.Logger;
18
import t3.utils.cp;
19
import t3.utils.t.b;
20
21
public final class ag implements f {
22
    public static final int as = 30;
23
    public static final int at = 7;
24
    public static final int au = 7;
25
    private static final DateTimeFormatter M;
26
    private boolean P;
27
    private boolean av;
28
    private boolean aw;
29
    private Instant N;
30
    private a O;
31
    private LocalDate ax;
32
    private boolean ay;
33
34
    protected ag() {
35
    }
36
37
    public boolean ac() {
38
        return this.P;
39
    }
40
41
    void c(boolean var1) {
42
        this.P = var1;
43
    }
44
45
    public boolean aO() {
46
        return this.av;
47
    }
48
49
    public void a(Boolean var1) {
50
        this.av = var1;
51
    }
52
53
    public Instant aa() {
54
        return this.N;
55
    }
56
57
    void a(Instant var1) {
58
        var1 = Instant.ofEpochSecond(var1.getEpochSecond());
59
        this.N = var1;
60
    }
61
62
    boolean aP() {
63
        return this.aw;
64
    }
65
66
    void h(boolean var1) {
67
        this.aw = var1;
68
    }
69
70
    public boolean aQ() {
71
        return this.ay;
72
    }
73
74
    void i(boolean var1) {
75
        this.ay = var1;
76
    }
77
78
    a ab() {
79
        return this.O;
80
    }
81
82
    boolean i(a var1) {
83
        if (this.ab() == null) {
84
            return var1.b(2018, 3, 0) ? true : true;
85
        } else {
86
            return this.ab().b(var1);
87
        }
88
    }
89
90
    void h(a var1) {
91
        this.O = var1;
92
    }
93
94
    public boolean aR() {
95
        return !this.aO() && !this.aP();
96
    }
97
98
    public int ag() {
99
        if (null == this.ax) {
100
            return 0;
101
        } else {
102
            int var1 = (int)(this.ax.toEpochDay() - LocalDate.now().toEpochDay());
103
            if (var1 >= 1) {
104
                ++var1;
105
            }
106
107
            var1 = Math.min(this.aS(), var1);
108
            var1 = Math.max(0, var1);
109
            return this.P ? 0 : var1;
110
        }
111
    }
112
113
    public LocalDate af() {
114
        return this.ax;
115
    }
116
117
    void d(LocalDate var1) {
118
        this.ax = var1;
119
    }
120
121
    public int aS() {
122
        if (this.aO()) {
123
            return 7;
124
        } else {
125
            return this.aP() ? 7 : 30;
126
        }
127
    }
128
129
    public String toString() {
130
        return String.format("%b|%b|%b|%s|%s", this.ac(), this.aO(), this.aP(), this.aa() != null ? M.format(this.aa()) : "", this.ab() != null ? this.ab().h() : "");
131
    }
132
133
    public static ag E(String var0) {
134
        ag var1 = G(var0);
135
        if (var1 == null) {
136
            var1 = F(var0);
137
        }
138
139
        if (var1 != null) {
140
            var1.i(b.awy().axT());
141
        }
142
143
        return var1;
144
    }
145
146
    private static ag F(String var0) {
147
        String[] var1 = var0.split("\\|");
148
        if (var1.length != 3) {
149
            return null;
150
        } else {
151
            ag var2 = new ag();
152
153
            try {
154
                var2.c(Boolean.valueOf(var1[0]));
155
                var2.a(Boolean.valueOf(var1[1]));
156
                var2.h(false);
157
                var2.a(H(var1[2]));
158
                var2.h((a)null);
159
                return var2;
160
            } catch (DateTimeParseException var4) {
161
                Logger.error(var4, "Date Formatting Issue", new Object[0]);
162
                return null;
163
            }
164
        }
165
    }
166
167
    private static ag G(String var0) {
168
        String[] var1 = var0.split("\\|", -1);
169
        if (var1.length != 5) {
170
            return null;
171
        } else {
172
            ag var2 = new ag();
173
174
            try {
175
                var2.c(Boolean.valueOf(var1[0]));
176
                var2.a(Boolean.valueOf(var1[1]));
177
                var2.h(Boolean.valueOf(var1[2]));
178
                var2.a(H(var1[3]));
179
                var2.h((a)a.a(var1[4]).orElse((Object)null));
180
                return var2;
181
            } catch (DateTimeParseException var4) {
182
                Logger.error(var4, "Date Formatting Issue", new Object[0]);
183
                return null;
184
            }
185
        }
186
    }
187
188
    private static Instant H(String var0) {
189
        Predicate var1 = (var0x) -> {
190
            Instant var1 = LocalDate.of(2000, 1, 1).atStartOfDay().toInstant(ZoneOffset.UTC);
191
            Instant var2 = LocalDateTime.now().plusYears(50L).toInstant(ZoneOffset.UTC);
192
            return var0x.isAfter(var1) && var0x.isBefore(var2);
193
        };
194
        Instant var2 = (Instant)M.parse(var0, Instant::from);
195
        if (!var1.test(var2)) {
196
            Instant var3 = (Instant)M.withChronology(ThaiBuddhistChronology.INSTANCE).parse(var0, Instant::from);
197
            if (var1.test(var3)) {
198
                var2 = var3;
199
            }
200
        }
201
202
        return var2;
203
    }
204
205
    public boolean x() {
206
        return true;
207
    }
208
209
    public String getName() {
210
        return "TRIAL";
211
    }
212
213
    public boolean z() {
214
        return true;
215
    }
216
217
    public Object accept(m var1) {
218
        return var1.a(this);
219
    }
220
221
    public EnumSet getEditions() {
222
        return EnumSet.of(t3.utils.ag.ENTERPRISE);
223
    }
224
225
    public g getStatus() {
226
        if (this.ac()) {
227
            return g.a("Your trial license has expired.", "Thank you for evaluating Studio 3T. \n\nTo continue using Studio 3T, you will need to purchase a license key.\nPlease visit " + cp.STUDIO_3T_OVERVIEW + " to find out more about available licensing options.\n\nTo continue evaluating Studio 3T, please email us at " + cp.SUPPORT_EMAIL + " and we’ll help you out.");
228
        } else {
229
            String var1;
230
            if (this.ag() > 0) {
231
                var1 = String.format("Your trial license expires in %d days", this.ag());
232
            } else {
233
                var1 = "Your trial license expires in less than 24 hours";
234
            }
235
236
            return g.c(var1);
237
        }
238
    }
239
240
    static {
241
        M = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss").withZone(ZoneOffset.UTC);
242
    }
243
}

0x02.studio_3t_trial

然后当天自然干到了凌晨一点?后无果(Java零基础过草
凌晨过后就直接躺床上准备睡觉了(当天甚至都不想看里番),回想起还没去gh瞅瞅,结果一下子就搜到了2333
核心代码如下(直接贴代码希望托管于ghblog源仓库不要被巨硬给DMCA

1
/**
2
  * 无限试用期
3
  * @param className
4
  * @return
5
  */
6
private byte[] trial(String className) {
7
    if ("t3/common/lic/ag".equals(className)) {
8
        System.out.println("========== trial ==========");
9
        System.out.println(className);
10
        try {
11
            String loadName = className.replaceAll("/", ".");
12
            CtClass ctClass = ClassPool.getDefault().get(loadName);
13
            CtMethod ctMethod1 = ctClass.getDeclaredMethod("ac");
14
            ctMethod1.setBody("{return false;}");
15
            CtMethod ctMethod2 = ctClass.getDeclaredMethod("ag");
16
            ctMethod2.setBody("{return Integer.MAX_VALUE;}");
17
            CtMethod ctMethod3 = ctClass.getDeclaredMethod("aS");
18
            ctMethod3.setBody("{return Integer.MAX_VALUE;}");
19
            return ctClass.toBytecode();
20
        } catch (Exception e) {
21
            e.printStackTrace();
22
        }
23
    }
24
    return null;
25
}

次日社畜到家之后立即克隆了一份仓库到本地

添加 package 的命令行参数
添加 package 的命令行参数

又把pom.xml文件增加了一处<defaultGoal>compile</defaultGoal>就可以成功编译出炸(jar)包了

RT
RT

接着修改Studio 3T.vmoptions该文件

1
# Enter one VM parameter per line
2
# For example, to adjust the maximum memory usage to 512 MB, uncomment the following line:
3
# -Xmx512m
4
# To include another file, uncomment the following line:
5
# -include-options [path to other .vmoption file]
6
7
# -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:50064
8
# -Xdebug
9
10
# -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=50064
11
-javaagent:D:\yuangezhizao\Documents\IdeaProjects\studio_3t_trial\target\studio_3t_crack-1.2.jar

启动,见证奇迹的时刻到了

Your trial license expires in 2147483647 days
Your trial license expires in 2147483647 days

更新到最新版(2019.7.1),重新修改Studio 3T.vmoptions该文件,再启动!

2019.7.1
2019.7.1

0x03.后记

  1. 未混淆明文源码看起来好爽啊,虽然并不能看得太懂
  2. 出现了!公钥替换大法,然而却被生成自己的x509密钥所困住,对于openssl还是不熟悉
  3. 其中原文所说的删除文件方法,由于本人是Windows平台异于macOS试了多次无果,Preferences.userRoot()倒是应该对应注册表,怀疑是其他文件(夹)没删彻底
    已删文件(夹)包括:
    1
    C:\Users\yuangezhizao\.3T\studio-3t\soduz3vqhnnja46uvu3szq--\settings.dat
    2
    C:\Users\yuangezhizao\.cache\ftuwWNWoJl-STeZhVGHKkQ--\5rpyYIZGkVBXle1pseFY2g
    3
    4
    C:\Users\Public\t3\dataman\mongodb\app\AppRunner\soduz3vqhnnja46uvu3szq--1967207156
    5
    C:\Users\yuangezhizao\AppData\Local\t3\dataman\mongodb\app\AppRunner\soduz3vqhnnja46uvu3szq--\data.dat
    6
    C:\Users\yuangezhizao\AppData\Local\Temp\t3\dataman\mongodb\app\AppRunner\soduz3vqhnnja46uvu3szq--.tmp
  4. 2019-12-5 16:31:28更新:听说这玩楞某宝有百元一份来出售的,过草

0x04.免责声明

本文的目的只有一个就是学习更多的破解技巧和思路,如果有人利用本文技术去进行非法商业获取利益带来的法律责任都是操作者自己承担,和本文以及作者没关系

未完待续……