关于(JetBrains 2024)
JetBrains 是一家全球性软件公司,专门为软件开发者和团队打造可以提升工作效率的智能工具。总部位于捷克共和国布拉格,在多个国家/地区设有研发实验室和销售办事处。
环境
- IDEA
- JDK 17
- jadx
逆向分析

这块过程,直接省略吧;
代码各种混淆 跟 加密; 着实看不下去;
就在一筹莫展之际, 突然发现一个可行的方案;
这里以 GoLand 为例, 当 系统检测到未授权时,会弹出一个 license 框;
并且这个框在你输入license 之前退不了;
此刻, 我就想, 我们能不能 注入一些代码, 开启一个线程来检测 该 license 窗口, 并且来修改窗口属性呢??
一开始我自己写了一个 class, 代码如下:class WindowWatcher {
static {
System.out.println(">>>>>>> WindowWatcher");
}
}
然后把编译后的 WindowWatcher.class 随便找了一个 JetBrains 依赖的 JAR 塞进去了;
System.out.println(">>>>>>> WindowWatcher");
Thread watcherThread = new Thread(() -> {
while (watcherFlag) {
try {
// 每隔5秒执行一次遍历
Thread.sleep(5000);
Window[] windows = Window.getWindows();
for (Window window : windows) {
if (window instanceof JDialog dialog) {
List<JButton> buttons = getButtons(dialog);
for (JButton button : buttons) {
String text = button.getText();
// System.out.println("Button Text: " + text);
dialog.setTitle("K'ed by: marlkiller");
if (text != null && (text.contains("Quit") || text.contains("Close"))) {
// dialog.setTitle(dialog.getTitle() + " 请点击["+text+"] 按钮");
button.removeActionListener(button.getActionListeners()[0]);
button.setText("<Close>");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
watcherFlag = false;
dialog.setVisible(false);
}
});
}
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 将线程设置为守护线程,随着主线程结束而结束
watcherThread.setDaemon(true);
watcherThread.start();
然后用命令后启动 GoLand;
发现打印的日志并没有我的 WindowWatcher;
不愧是 JetBrains, 想必 是用了自己写的类加载器, classLoader, 而且并不会加载 jar 包里所有的 class;
所有我们之前找 依赖里的 class 来反编译然后, 添加我们的 static 静态代码
复制代码 隐藏代码System.out.println(">>>>>>> WindowWatcher"); Thread watcherThread = new Thread(() -> { while (watcherFlag) { try { // 每隔5秒执行一次遍历 Thread.sleep(5000); Window[] windows = Window.getWindows(); for (Window window : windows) { if (window instanceof JDialog dialog) { List<JButton> buttons = getButtons(dialog); for (JButton button : buttons) { String text = button.getText(); // System.out.println("Button Text: " + text); dialog.setTitle("K'ed by: marlkiller"); if (text != null && (text.contains("Quit") || text.contains("Close"))) { // dialog.setTitle(dialog.getTitle() + " 请点击["+text+"] 按钮"); button.removeActionListener(button.getActionListeners()[0]); button.setText("<Close>"); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { watcherFlag = false; dialog.setVisible(false); } }); } } } } } catch (InterruptedException e) { e.printStackTrace(); } } }); // 将线程设置为守护线程,随着主线程结束而结束 watcherThread.setDaemon(true); watcherThread.start();
代码逻辑如下:
定时监测所有的窗口,
检测到 Licenses 窗口时 ,清除原始 Quit 按钮按钮的事件,
并且添加一个 close 当前 Dialog 的事件…
之后将class 覆盖, 然后重启app
之后会看到一个效果:
当弹出未授权窗口时, 点几 Quit 按钮, 该窗口就被隐藏了…..
之后我们正常打开项目即可..

大概是考虑到社区版,以及不同产品的兼容性;
所以除了启动窗口的时候, 没看到有别的地方有什么限制;
除此之外, 还有一个思路;
用 Agent 来动态修改 字节码文件,
但是目前的 class混淆加密严重,着实不知道 agent 改给哪些clz 挂钩哦
搞了个 shell 脚本,一键替换打包资源
复制代码 隐藏代码target_app="/Users/voidm/Applications/GoLand.app" rewrite_file="$(pwd)/../out/production/java_dev/com/jetbrains/ls/responses/License.class" rewrite_file2="$(pwd)/../out/production/java_dev/com/jetbrains/ls/responses/License\$1.class" echo "Changing directory to ${target_app}/Contents/lib" cd "${target_app}/Contents/lib" # 查找包含目标 Class 的 jar 包 check_jar_for_class() { local directory="$1" local class_file="$2" local found=false for jar_file in "$directory"/*.jar; do if jar tf "$jar_file" | grep -q "$class_file"; then # 返回包含指定类文件的jar包名称 echo "$(basename "$jar_file")" found=true return fi done # 如果未找到指定文件,则输出日志并退出 if ! $found; then echo "target class_file not found" >&2 exit 1 fi } jar_name=$(check_jar_for_class "${target_app}/Contents/lib" "com/jetbrains/ls/responses/License.class") echo "target_jar is : $jar_name" jar_file="${target_app}/Contents/lib/${jar_name}" jar_file_back="${jar_file}_Backup" # 备份文件 if [ ! -f "$jar_file_back" ]; then echo "Backing up $jar_file to $jar_file_back" cp "$jar_file" "$jar_file_back" fi # 解压缩 Jar echo "Extracting ${jar_name}" jar -xvf ${jar_name} com/jetbrains/ls/responses/License.class # 替换文件 cp -f ${rewrite_file} "./com/jetbrains/ls/responses/License.class" cp -f ${rewrite_file2} "./com/jetbrains/ls/responses/License\$1.class" # 重新打包 echo "Compressing ${jar_name}" jar -uvf ${jar_name} "com/jetbrains/ls/responses/License.class" jar -uvf ${jar_name} "com/jetbrains/ls/responses/License\$1.class" # 清理临时文件 rm -rf ./com
后记
人啊, 不能太闲; 太闲的时候就会胡闹,比如这个胡闹出来的思路…..
找工作真tm难..
仅供研究学习使用,请勿用于非法用途
各位朋友,本网站本身不提供下载资源,以下资源地址均为网友整理提供,并且需离开本站,请各位网友谨慎选择,我站将不提供任何保障。另:如这些资源地址有违规或侵权行为,请联系66553826(@)qq.com,我方将在确认后第一时间断开链接。