使用 ja-netfilter 激活 DBeaver Ultimate 26.0

余名君 2026-03-24 11:41 1

最近想用一下 MongoDB 客户端,习惯用 DBeaver 了,还是最新的版本,发现很多教程都没法正常激活,干脆自己“照虎画猫”,顺带学习下始皇大佬的 ja-netfilter 的进阶用法,自己整了一下,有需要的自取。不够完善或有错误的地方,还望谅解。


目前在 MacOS ARM64 上验证通过,DBeaver 版本为:Version 26.0.0.202603091511



核心思路



  1. 自己生成 RSA 密钥对,密钥长度 2048,密钥指数为 65537,用自己的私钥生成 License 导入到 DBeaver 中

  2. 修改 dbeaver.ini 配置文件,使 DBeaver 使用 ja-netfilter 进行代理拦截

  3. 通过 ja-netfilter Power 插件绕过 RSA 密钥校验。

  4. 通过 ja-netfilter updns 插件绕过 License 证书网络校验


详细分析过程就不写了,可以看看文献,但是 26.0 版本的较 25.3 版本的有些变化,例如 LMECryption 类中的 keyPairs 方法被移除了,密钥对的生成要自己写(但也就几行的问题,easy)


生成 License


注意需要先从 plugins 中拷贝两个 jar 包(其他包是分析的时候用到的,但下面的代码只用到了两个包):



keys/dbeaver-ue-public.key 内容为:


--- PUBLIC KEY ---
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk7ciFU/aUCIgH5flBbGD0t7B3KOmfL0l
BMf2ENuLA0w/T8A1RvteUYk2EQo3UrZ7kMZ8rK93nmDjituN7jlv/bsxGyAox87BbKYSs9oH5f9P
hYHAiTE0PxoMODnl4NgR+Bpc+Ath8wDLHMC+BzYkOy4JQo8EX/ff58TT9UYP8eoDeGdSxQmW3FJC
i82UiC5zIk75dx20Al9ql0fdxnzo31q/2MbnNCAfSchsqrKtzBtheex4JvvqZjxn98wk5Te1QgZz
Caz4ay9dkLVjSt79QYm5hKb8Jt3O5SxSUsrjmYVeG+k2bQlidw8dENwLZmvJkIJi8kb94yEwY/dq
lENDkQIDAQAB

DBeaverLicenseCrack.java


package com.puppetdevz;

/**
* DBeaver Ultimate 版本许可证实现方法研究
* 注意事项:仅供学习研究使用
*/

import com.dbeaver.lm.api.*;
import org.jkiss.utils.Base64;

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;

/**
* DBeaver许可证主类
*
* 该类实现了完整的DBeaver Ultimate许可证生成流程
* 包括密钥生成、许可证创建等功能
*/
public class DBeaverLicenseCrack {

// ==================== 许可证基本信息配置 ====================

/** 产品标识符 - DBeaver Ultimate Edition */
private static final String PRODUCT_ID = "dbeaver-ue";

/** 产品版本号 */
private static final String PRODUCT_VERSION = "26.0";

/** 所有者ID */
private static final String OWNER_ID = "10006";

/** 所有者公司名称 */
private static final String OWNER_COMPANY = "DBeaver Corporation";

/** 所有者姓名 */
private static final String OWNER_NAME = "Ultimate User";

/** 所有者邮箱 */
private static final String OWNER_EMAIL = "[email protected]";

// ==================== 路径配置 ====================

/** DBeaver安装目录路径 */
private static final String DBEAVER_ECLIPSE_HOME = "/Applications/DBeaverUltimate.app/Contents/Eclipse";

/** 项目主目录路径 - 用于存储生成的密钥文件 */
private static final String CRACK_HOME = "~/codespace/crack-dbeaver";

// ==================== 文件路径变量 ====================

/** 私钥文件路径 */
private static File privateKeyFile;

/** 公钥文件路径 */
private static File publicKeyFile;

/** 许可证文件路径 */
private static File licenseFile;

/** JAR包中使用的公钥文件路径 */
private static File jarPublicKey;

// ==================== 静态初始化块 ====================

/**
* 静态初始化块 - 在类加载时执行
*
* 功能:
* 1. 创建必要的目录结构
* 2. 初始化所有文件路径变量
* 3. 输出调试信息
*
* 执行时机:类第一次被加载时自动执行
*/
static {
try {
// 构建密钥存储目录路径
File keysDir = new File(CRACK_HOME, "keys");

// 如果目录不存在则创建
if (!keysDir.exists()) {
if (keysDir.mkdirs()) {
System.out.println("[INFO] 成功创建密钥目录: " + keysDir.getAbsolutePath());
} else {
System.err.println("[ERROR] 创建密钥目录失败: " + keysDir.getAbsolutePath());
}
}

System.out.println("[DEBUG] 密钥存储目录: " + keysDir.getAbsolutePath());

// 初始化各个文件的完整路径
privateKeyFile = new File(keysDir, "private-key.txt");
publicKeyFile = new File(keysDir, "public-key.txt");
licenseFile = new File(keysDir, "license.txt");
jarPublicKey = new File(keysDir, "dbeaver-ue-public.key");

// 输出调试信息
System.out.println("[DEBUG] 私钥文件路径: " + privateKeyFile.getAbsolutePath());
System.out.println("[DEBUG] 公钥文件路径: " + publicKeyFile.getAbsolutePath());
System.out.println("[DEBUG] 许可证文件路径: " + licenseFile.getAbsolutePath());
System.out.println("[DEBUG] JAR公钥文件路径: " + jarPublicKey.getAbsolutePath());

} catch (Exception e) {
System.err.println("[ERROR] 初始化目录时发生错误: " + e.getMessage());
e.printStackTrace();
}
}

// ==================== 主方法 ====================

/**
* 程序入口点
* @Param args 命令行参数(未使用)
* @throws Exception 如果执行过程中发生任何错误
*/
public static void main(String[] args) throws Exception {
System.out.println("=========================================");
System.out.println(" DBeaver Ultimate 许可证破解工具");
System.out.println("=========================================");
System.out.println("[INFO] 开始执行DBeaver许可证破解流程...");

// ==================== 第一步:验证DBeaver安装环境 ====================
System.out.println("\n[STEP 1] 验证DBeaver安装环境");

// 检查DBeaver主目录是否存在
File dbeaverHome = new File(DBEAVER_ECLIPSE_HOME);
if (!dbeaverHome.exists()) {
System.err.println("[ERROR] DBeaver安装目录不存在: " + DBEAVER_ECLIPSE_HOME);
System.err.println("[SOLUTION] 请检查DBEAVER_ECLIPSE_HOME配置是否正确");
return;
}
System.out.println("[SUCCESS] DBeaver安装目录验证通过");

// 检查插件目录是否存在
String dbeaverPluginDir = DBEAVER_ECLIPSE_HOME + File.separator + "plugins";
File pluginDir = new File(dbeaverPluginDir);
if (!pluginDir.exists()) {
System.err.println("[ERROR] 插件目录不存在: " + dbeaverPluginDir);
System.err.println("[SOLUTION] 请确认DBeaver安装完整");
return;
}
System.out.println("[SUCCESS] 插件目录验证通过: " + dbeaverPluginDir);

// ==================== 第三步:生成密钥和许可证 ====================
System.out.println("\n[STEP 2] 生成密钥对和许可证");
generateKeyLicenseAndPatch();

// ==================== 完成 ====================
System.out.println("\n=========================================");
System.out.println(" 执行完成!");
System.out.println("=========================================");
System.out.println("[NEXT STEP] 请启动DBeaver并输入生成的许可证");
}

/**
* 生成RSA密钥对、创建许可证
*
* 核心功能流程:
* 1. 生成2048位RSA密钥对
* 2. 将公钥保存到文件
* 3. 使用私钥加密生成许可证
* @throws LMException 如果许可证生成过程出错
* @throws IOException 如果文件操作失败
*/
public static void generateKeyLicenseAndPatch() throws LMException, IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException {
// 判断 RSA 密钥对是否已经存在,如果不存在,则生成
if (!(privateKeyFile.exists() && publicKeyFile.exists())) {
System.out.println("[INFO] 未检测到现成的RSA密钥对文件,开始生成 RSA 密钥对...");

// 生成RSA密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

// 使用 RSAKeyGenParameterSpec 显式指定密钥长度 (2048) 和 公钥指数 (65537)
// RSAKeyGenParameterSpec.F4 就是内置的常量 BigInteger.valueOf(65537)
RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4);
keyPairGenerator.initialize(spec);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();

// 通过 writeFileToPath 将密钥对写入到 keys/ 中
writeFileToPath(Base64.encode(publicKey.getEncoded()), publicKeyFile, "公钥", true);
writeFileToPath(Base64.encode(privateKey.getEncoded()), privateKeyFile, "私钥", true);
}

// 如果 RSA 密钥对已经存在,则直接读取为 Key 使用
System.out.println("[INFO] 检测到现成的RSA密钥对文件,开始读取密钥...");
PublicKey publicKey = LMEncryption.generatePublicKey(Base64.decode(Files.readString(publicKeyFile.toPath()).trim()));
PrivateKey privateKey = LMEncryption.generatePrivateKey(Base64.decode(Files.readString(privateKeyFile.toPath()).trim()));

LMProduct TEST_PRODUCT = new LMProduct(PRODUCT_ID, "DB", "DBeaver Ultimate", "DBeaver Ultimate Edition", PRODUCT_VERSION, LMProductType.DESKTOP, new Date(), new String[0]);
String licenseID = LMUtils.generateLicenseId(TEST_PRODUCT);
// System.out.println("[INFO] 生成的 License ID: " + licenseID);
LMLicense license = new LMLicense(licenseID, LMLicenseType.ULTIMATE, new Date(), new Date(), (Date) null, LMLicense.FLAG_UNLIMITED_SERVERS, PRODUCT_ID, PRODUCT_VERSION, OWNER_ID, OWNER_COMPANY, OWNER_NAME, OWNER_EMAIL);
byte[] licenseData = license.getData();
byte[] licenseEncrypted = LMEncryption.encrypt(licenseData, privateKey);

PowerArgsGenerator powerArgsGenerator = new PowerArgsGenerator((RSAPublicKey) publicKey, jarPublicKey.getAbsolutePath());
String patch = powerArgsGenerator.generatePowerArgs();
System.out.println("\n--- 生成的 PowerArgs ---");
System.out.println(patch);
writeFileToPath(patch, new File(CRACK_HOME, "keys/power-args.txt"), "PowerArgs", true);

String licenseContent = Base64.splitLines(Base64.encode(licenseEncrypted), 76);
System.out.println("\n--- LICENSE ---");
System.out.println(licenseContent);
System.out.println("--- 处理完成,请打开软件使用以上授权码(已复制到剪切板) ---");
copyToClipboard(licenseContent);
writeFileToPath(licenseContent, licenseFile, "授权码", true);
}

/**
* 写入文件内容(提供默认参数),默认为不覆盖
*
* @param content 待写入的内容
* @param filePath 要写入的文件路径
* @param tip 提示
*/
public static void writeFileToPath(String content, File filePath, String tip) {
// 通过方法重载实现默认值为 false
writeFileToPath(content, filePath, tip, false);
}

/**
* 写入文件内容,可选强制覆盖
*
* @param content 待写入的内容
* @param filePath 要写入的文件路径
*@param tip 提示
* @param overwrite 是否强制覆盖(true:覆盖现有文件;false:若文件存在则不写入)
*/
public static void writeFileToPath(String content, File filePath, String tip, boolean overwrite) {
if (filePath == null || content == null){
System.err.println("写入中止:文件路径或内容不能为空");
return;
}
Path path = filePath.toPath();
// 1. 处理文件已存在且未开启覆盖的情况
if (!overwrite && Files.exists(path)) {
System.out.printf("[%s内容] 写入跳过:文件已存在且未开启覆盖模式(%s)%n", tip, path);
return;
}
// 2. 严格检查父目录是否存在:不存在则打印日志并中止
Path parentDir = path.getParent();
if (parentDir != null && !Files.exists(parentDir)) {
System.err.printf("[%s内容] 写入中止:父目录不存在,已拒绝自动创建(%s)%n", tip, parentDir);
return;
}
try {
//3. 规范化处理:显式指定 UTF-8 字符集
Files.write(path, content.getBytes(StandardCharsets.UTF_8));
System.out.printf("[%s内容] 已成功写入文件:%s%n", tip, path);

}catch (IOException e) {
System.err.printf("[%s内容] 写入文件发生异常:%s%n", tip, path);
e.printStackTrace();
}
}

/**
* 将指定字符串复制到剪切板
*
* @param text
*/
public static void copyToClipboard(String text) {
StringSelection stringSelection = new StringSelection(text);
Clipboard clipboard = Toolkit.getDefaultToolkit()
.getSystemClipboard();
clipboard.setContents(stringSelection, null);
}
}

PowerArgsGenerator.java


package com.puppetdevz;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class PowerArgsGenerator {

private static final String POWER_ARGS_TEMPLATE = "EQUAL,65537,%s->65537,%s";

private final RSAPublicKey currentPublicKey;

private final String oldPublicKey;

public PowerArgsGenerator(RSAPublicKey currentPublicKey, String oldPublicKey) {
this.currentPublicKey = currentPublicKey;
this.oldPublicKey = oldPublicKey;
}

/**
* 从 PEM 文件中加载 RSA 公钥
* 兼容多种 PEM 头尾格式:
* - 标准格式:-----BEGIN PUBLIC KEY----- / -----END PUBLIC KEY-----
* - 自定义格式:--- PUBLIC KEY --- 等
*/
public static RSAPublicKey loadPublicKeyFromPem(Path pemPath)
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {

String pemContent = Files.readString(pemPath);

// 用正则去除所有形如 "-{2,5}\s*PUBLIC KEY\s*-{2,5}" 的头尾标记行
String base64Key = pemContent
.replaceAll("-{2,5}\\s*(BEGIN\\s+)?PUBLIC\\s+KEY\\s*-{2,5}", "")
.replaceAll("\\s+", "");

byte[] keyBytes = Base64.getDecoder().decode(base64Key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");

return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}

/**
* 生成 power[Args] 字符串
*/
public String generatePowerArgs()
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {

RSAPublicKey oldKey = loadPublicKeyFromPem(Path.of(oldPublicKey));
BigInteger oldN = oldKey.getModulus();
BigInteger newN = currentPublicKey.getModulus();

return String.format(POWER_ARGS_TEMPLATE, oldN.toString(), newN.toString());
}
}

修改 dbeaver.ini



/Applications/DBeaverUltimate.app/Contents/Eclipse/dbeaver.ini



-startup
....中间省略
../Eclipse/plugins/org.eclipse.equinox.launcher.cocoa.macosx.aarch64_1.2.1400.v20250801-0854
-vm /Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents/Home/bin/java
-vmargs
....中间省略
-Dlm.debug.mode=true
-javaagent:/path-to-ja-netfilter/ja-netfilter.jar

核心只有三行配置:


-vm /Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents/Home/bin/java
-Dlm.debug.mode=true
-javaagent:/path-to-ja-netfilter/ja-netfilter.jar


一般遇到启动不了的,原因可能有以下三个:



  • ja-netfilter 路径写错了

  • vm 没改或路径写错了(之所以要改 vm,是因为 DBeaver 自带的 vm 为 阉割版,缺少部分 ja-netfilter 依赖)

  • 有多个 vm



修改power.conf和updns.conf


将上面生成的 Power Patch 粘贴到 power.conf 末尾



在 updns.conf 中添加网络解析拦截(为什么不用 dns.conf 或 url.conf 呢?好像是因为 ohttp3 被 dns 和 url 插件捕获)



调试小tips


直接在终端启动 DBeaver 可查看程序运行过程日志,例如:/Applications/DBeaverUltimate.app/Contents/MacOS/dbeaver


参考文献



  • 求助 DBeaver Ultimate 25.3 激活问题 - 开发调优 / 开发调优, Lv1 - LINUX DO

  • DBeaver Ultimate 22.1 旗舰版激活方法 – 知了

  • DBeaver Ultimate Edition License 验证分析 25.3.0版本 - 吾爱破解 - 52pojie.cn

最新回复 (19)
  • Grogu 03-24 11:42
    1

    佬友太强了 ^-^,感谢佬友分享 ^-^

  • cheryH 03-24 12:04
    2

    感谢佬友分享,写的很详细 ^-^

  • 原来是我啊 03-24 12:11
    3

    看看{:4_90:}

  • 爱你们 03-24 12:12
    4

    我感觉免费的就够用了

  • 齐德隆 03-24 12:14
    5


    • 绕过 RSA 密钥校验。

    • 通过 ja-netfilter updns 插件



    感谢分享

  • yi124773651 03-24 12:15
    6

    感谢分享

  • 大帅哥 03-24 12:16
    7

    感谢大佬。

  • LeonShaw 03-24 12:17
    8

    感谢大佬!感谢引用

  • neon 03-24 12:18
    9

    感谢分享,学习了

  • 𝓜𝒾𝓻𝒶𝓰ℯ 03-24 12:18
    10

    果然除了我全是大佬啊

  • 西行寺幽幽子 03-24 12:22
    11

    大佬,请问dbeaver有没有像navicat一样直接导出数据库结构和数据到sql文件的功能?用navicat导出一个sql文件,然后导入的时候直接运行sql就完成数据库迁移了。

    我之前看datagrip还要用dump之类的工具,而且是每个表一个sql文件,感觉很不方便。

    dbeaver用的不多,好像没有看到直接导出数据库到sql文件的地方

  • 𝕃𝔼𝕆𝕎𝕐 03-24 12:24
    12

    very good!

  • alex5 03-24 12:27
    13

    DBeaver不是开源的吗

  • 今晚打老虎 03-24 12:33
    14

    大佬太强了

  • 余名君 楼主 03-24 12:57
    15

    是的,之前也一直在用的免费版,但是发现部分数据库用不了,例如MongoDB

  • 余名君 楼主 03-24 12:57
    16

    部分数据库需要证书激活才能用

  • 余名君 楼主 03-24 13:00
    17

    有的,不过DBeaver分得比较细,可以先导出 DDL,再导出数据。


    导出 DDL


    选中需要数据表以导出数据

  • 连朝雨 03-24 14:36
    18

    佬,这个updns插件从哪搞的,我没找到啊!

  • 余名君 楼主 03-24 14:43
    19

    updns.jar.zip (23.7 KB)


    需要自行在config目录下新增一个同名的配置文件:updns.conf

* 帖子来源Linux.do
返回