#### 背景
> 项目使用`Mongodb`,当然有一款`MongoDB`链接工具那是非常重要的,本教程提供的`Studio 3T`是一个非官方的非常强大的操作客户端,但是需要收费,网上找了都是试用期假破解,我看到老版本的破解是替换`jar`, 灵机一动从`jar`文件中找到程序入口,进行代码追踪,找到核心的判断`license`逻辑进行修改。
#### 安装 Studio 3T
* [下载][https://studio3t.com/download/]并安装最新 **Studio 3T**

* 初始用户会有30天试用期,反之则提示导入`license`
* 退出`studio 3t`到安装文件中找到`data-man-mongodb-ent-xxxx.x.x.jar` 下文称 `xxx.jar`
#### 打开 Intellij Idea 将 xxx.jar 导入工程
* 用Intellij 随便创建一个`maven`工程
* 将xxx.jar 导入工程

* 查看`MANIFEST.MF` -> `Build-Jdk-Spec`决定后面反编译使用`JDK`版本

> 本次使用的是 JDK 11
* 从`MANIFEST.MF`可以看出来主入口所在哪个文件
> ```java
> // 我们根据提示去对应包中找到对应的class文件
> Main-Class: t3.dataman.mongodb.app.Studio3TApp
> ```
#### 解析验签源码
* Main 逻辑
```java
public static void main(String[] var0) {
// 根据源码追踪可以看出来 这一块逻辑就是判断与读取配置文件,和校验程序运行所需的参数,还有支持更新与如果是Mac 获取宿主机主题,来改变软件的相关设置;
System.setProperty("swt.autoScale", bz.isMac() ? "false" : "integer200");
System.setProperty("jna.nosys", "true");
Nx();
ae.Nv();
List var1 = ManagementFactory.getRuntimeMXBean().getInputArguments();
if (bm(var1)) {
bl(var1);
System.exit(1);
}
if (!NA()) {
System.exit(1);
}
g.abu();
a.bdX();
if (g.av()) {
Nz();
System.exit(-1);
}
a var2 = a.bdT();
p var3 = var2.bel();
if (bz.isMac() && (var3 == p.system_theme || Display.isSystemDarkTheme() && var3 == p.dark_theme)) {
System.setProperty("org.eclipse.swt.display.useSystemTheme", "true");
}
n.bEc.a(var3);
// =================================================================================
// 下面的Nw() function 是本教程的重点
Nw();
if (Arrays.stream(var0).anyMatch((var0x) -> {
return var0x.equals("--log-licenses");
})) {
Logger.info(i.as());
}
ab.run();
}
```
* Nw 逻辑
```java
private static void Nw() {
Display var0 = new Display();
n.bEc.g(var0);
try {
if (!(new u()).ce()) {
System.exit(-1);
}
t3.utils.ac.n.ap(var0.getActiveShell());
g.abs();
if (g.aw() && !g.az()) {
g.L();
} else if (g.ax() && !g.az()) {
c var1 = g.abm();
c var2 = g.abo();
e var3 = new e(g.aM(), var1.Z() || var1.isNone(), var2 instanceof t3.common.lic.a.a);
if (var3.dy()) {
g.M();
}
} else {
a.bdT().k(g.aM());
a.bdT().ahK();
}
if (!g.abn()) {
b.aY().b(10000);
} else {
b.aY().b(4000);
}
g.abs();
if (!g.abn()) {
(new l(var0.getActiveShell())).open();
t3.common.lic.b.a.l.a(var0.getActiveShell(), true);
}
g.abs();
// 看到这个方法时候很开心是不是,很明显这个是 未发现 active license 程序就退出逻辑,我们就跟着这块往下追踪,上面我们先不看,我们就直接判断 g.abn()
if (!g.abn()) {
Logger.error("No active license, exiting.");
System.exit(-1);
}
} catch (Exception var7) {
Logger.error(var7, "Unexpected exception while running setup wizard.");
System.exit(-1);
} finally {
var0.dispose();
}
}
```
* g.abn()
```java
public static boolean abn() {
return abl().getStatus().ar();
}
//1 abl() 返回 c 的实例 ao
public static c abl() {
return ao;
}
//2 替换 ao.getStatus() -> c.getStatus()
public interface c {
d getStatus();
}
//3 c.getStatus() 返回是 对象 d 实例,所以到这里 abn 最终被精简为
public class d {
public boolean ar() {
return this.W == e.ACTIVE;
}
}
public static boolean anb() {
return d.ar();
}
//4 经过查看 this.W 是 d 类中 一个 e 类型,而 e 类型是一个 枚举类型
public enum e {
ACTIVE,
LICENSE_EXPIRED,
USAGE_TOKEN_EXPIRED,
MACHINE_LIMIT_REACHED,
NO_SEAT,
USAGE_DENIED_UNKNOWN_REASON;
private e() {
}
}
```
* 干活
> 我们找到了判断`License` 是否 `ACTIVE` 主要就是判断 `class d` 中的各个方法,到这里 **You know how to change it now?**
* 在随便那个目录按照 **/xxx/t3/common/lic** 新建一个`d.java` 文件

> 把 `d` 的 `class`文件整个拷贝到 `d.java`文件中,按照如下进行修改
```java
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package t3.common.lic;
public class d {
private final e W;
private final String X;
private d(e var1, String var2) {
this.W = var1;
this.X = var2;
}
public e ai() {
return this.W;
}
public static d t(String var0) {
return new d(e.ACTIVE, var0);
}
public static d u(String var0) {
return new d(e.LICENSE_EXPIRED, var0);
}
public static d aj() {
return new d(e.USAGE_TOKEN_EXPIRED, "Please go online");
}
public static d ak() {
return new d(e.MACHINE_LIMIT_REACHED, "License is being used in too many computers");
}
public static d al() {
return new d(e.NO_SEAT, "No seat assigned");
}
public static d am() {
return new d(e.USAGE_DENIED_UNKNOWN_REASON, "Update required");
}
public String getTitle() {
return this.X;
}
// 划重点 ======================================================
public boolean an() {
// return this.W == e.LICENSE_EXPIRED;
return false;
}
public boolean ao() {
//return this.W == e.USAGE_TOKEN_EXPIRED;
return false;
}
public boolean ap() {
return this.W == e.MACHINE_LIMIT_REACHED;
}
public boolean aq() {
//return this.W == e.NO_SEAT;
return false;
}
public boolean ar() {
//return this.W == e.ACTIVE;
return true;
}
// ===============================================================
}
```
#### 将 d.java -> d.class -> import 到 data-man-mongodb-ent-xxxx.x.x.jar
* 终端进入到存放`d.java`的 t3 目录这一层,然后执行如下命令
> 注意: 这里执行时候要确保 java 是使用 jdk 11, 如果你是多版本jdk,Linux/Mac 可以使用 export 临时申明下
>
> ```shell
> javac -classpath /Applications/Studio\ 3T.app/Contents/Resources/app/data-man-mongodb-ent-xxxx.x.x.jar /xxxx/studio3t_crack/src/t3/common/lic/d.java -d .
> ```
>
> 执行之后不出意外在 **xxx/t3/common/lic** 目录下生成 **d.class**
* 下面将**d.class** 打包到 **data-man-mongodb-ent-xxx.jar**包中替换原来的**d.class**
```shell
jar uf /Applications/Studio\ 3T.app/Contents/Resources/app/data-man-mongodb-ent-xxxx.x.x.jar t3/common/lic/d.class
```
> 如果不出意外 **Congratulations**启动软件即可
#### 效果展示

**注: M1 架构的启动报文件已损坏需要到Studio 3T 镜像目录下执行如下命令**
```shell
cd /Applications/Studio 3T.app
xattr -rd com.apple.quarantine .
```
**参考**
https://www.zhoujunwen.com/2020/%E9%80%9A%E8%BF%87%E5%8F%8D%E7%BC%96%E8%AF%91%E7%A0%B4%E8%A7%A3-mongodb-%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%B7%A5%E5%85%B7-studio-3t/
![Studio 3T 任意版本在Inter/M1 架构上破解教程 [亲测有效]](https://www.nuo-promise.cn/upload/2021/10/studio3t-06-e335ec786dc74f12a7e89ae8ab236f59.png)
Studio 3T 任意版本在Inter/M1 架构上破解教程 [亲测有效]