Loading... <div class="tip share">请注意,本文编写于 155 天前,最后修改于 6 天前,其中某些信息可能已经过时。</div> # 引言 tb上买过教育版,结果用了一年多就封了,我记得之前用过ja-netfilter,用的是激活码,但是看起来直接替换的这种解决方案不太靠谱(网上的方案不排除存在jar投毒,当然,我并不是说这种方案不好,只是我目前没有理解,如果不放心可以通过jadx反编译一下),现在是使用jetbra.in激活服务器激活,但是如果断网条件下,或者某一天这个网站down了,就没办法了,尝试过通过fiddler拦截激活服务器的响应,发现相同请求所获得的响应是不同的,加密算法也搞不懂,power.conf也看不懂,用着就不放心,<span style='color:#DC143C'>还是社区版搞起吧,毕竟社区版也够用了。</span>这里也是从52大神那里作为参考,想到的另一种方案,此方法仅供技术研究和讨论,切勿用于商业用途,否则后果自负。 # 注意 <span style='color:#DC143C'> idea 2024.2.3 版本已经失效</span> ## 更新说明 2024年8月16日 文章已被修改,原来的版本会导致某些窗体打开失败{如:datagrip的修改表} 解决方案:setTitle中添加try-catch # 测试通过的版本 idea 2024.1.3 idea 2024.1.4 idea 2024.1.6 clion 2024.1.4 datagrip 2024.1.2 datagrip 2024.1.4 # 准备工作 jadx idea arthas jdk # 思路 ## 找到窗口 ![image.png](https://www.zunmx.top/usr/uploads/2024/06/799549738.png) ![image.png](https://www.zunmx.top/usr/uploads/2024/06/3547910640.png) 通过arthas获取awt的窗口`$ ognl '@java.awt.Window@getWindows()'`, 尝试关闭窗口`ognl '@javax.swing.JDialog@getWindows()[3].dispose()'` 发现idea并没有完全退出,如果直接手动点退出的话,程序会结束 ## 找到类名 上文中找到窗口了,类名其实也就出来了,但是如何判断`com.intellij.openapi.ui.impl.DialogWrapperPeerImpl$MyDialogWrapperImpl`具体在哪个包里,还是有些困难,通过`sc -d -f com.intellij.openapi.ui.impl.DialogWrapperPeerImpl`并没有找到,这里就是猜,猜到app-client.jar文件 ## 分析代码 找到注入位置这里也踩了很多坑,比如说关闭了不该关闭的窗口,但是开发过java的应该都熟悉get/set方法,那么在setTitle时检查名称是不是就可以判断出这个窗口是不是应该关闭了? ## 写代码 ### 依赖 ```xml <dependencies> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.28.0-GA</version> </dependency> </dependencies> ``` ### 代码 ```java package org.example; import javassist.*; import java.io.*; import java.util.Enumeration; import java.util.jar.*; public class ModifyDialogWrapperPeerImpl { public static void main(String[] args) { try { ClassPool pool = ClassPool.getDefault(); String jarPath = "G:\\test\\app-client-old.jar"; // jar文件路径 String exportPath = "G:\\test\\app-client.jar"; // jar文件路径 pool.insertClassPath(jarPath); CtClass ctClass = pool.get("com.intellij.openapi.ui.impl.DialogWrapperPeerImpl"); // 类名 CtMethod setTitleMethod = ctClass.getDeclaredMethod("setTitle", new CtClass[]{pool.get("java.lang.String")}); // 方法名 setTitleMethod.insertBefore("{ System.out.println(\"即将打开窗口-->\"+$1);" + "boolean isLicenseWindow = false;" + "try {\n"+ " if($1.indexOf(\"许可证\")>-1) {isLicenseWindow=true; this.dispose();}\n" + " if($1.indexOf(\"Licenses\")>-1) {isLicenseWindow=true; this.dispose();}\n" + " if(isLicenseWindow) System.out.println(\"发现激活窗口,即将关闭\");\n" + " Exception e = new Exception(\"↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓\");\n" + " System.out.println(\"调用栈信息-->\");\n" + " e.printStackTrace();\n" + " }\n" + "catch (Exception ex) {\n" + " System.out.println(\"出现错误-->\");\n" + " ex.printStackTrace();\n" + " }" + "}"); // 注入的代码 String tempDir = "G:\\test\\modified_classes"; ctClass.writeFile(tempDir); ctClass.detach(); updateJarFile("G:\\test\\app-client-old.jar", tempDir, exportPath); System.out.println("Method modified successfully."); } catch (NotFoundException | CannotCompileException | IOException e) { e.printStackTrace(); } } public static void updateJarFile(String originalJarPath, String modifiedClassesPath, String outputJarPath) throws IOException { JarFile originalJar = new JarFile(originalJarPath); FileOutputStream fos = new FileOutputStream(outputJarPath); JarOutputStream jos = new JarOutputStream(fos); // 复制原始JAR中的所有文件到新的JAR中,跳过要修改的类文件 Enumeration<JarEntry> entries = originalJar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); if (!entry.getName().equals("com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.class")) { // 跳过要修改的类文件 InputStream is = originalJar.getInputStream(entry); jos.putNextEntry(new JarEntry(entry.getName())); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { jos.write(buffer, 0, bytesRead); } is.close(); jos.closeEntry(); } } originalJar.close(); // 添加修改后的类文件到新的JAR中 File modifiedClassesDir = new File(modifiedClassesPath); addModifiedFilesToJar(modifiedClassesDir, "", jos); jos.close(); } private static void addModifiedFilesToJar(File source, String parent, JarOutputStream jos) throws IOException { File[] files = source.listFiles(); for (File file : files) { if (file.isDirectory()) { addModifiedFilesToJar(file, parent + file.getName() + "/", jos); } else { FileInputStream fis = new FileInputStream(file); jos.putNextEntry(new JarEntry(parent + file.getName())); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { jos.write(buffer, 0, bytesRead); } fis.close(); jos.closeEntry(); } } } } ``` 执行完成后,需要把生成的文件替换回去。 # 测试 ![image.png](https://www.zunmx.top/usr/uploads/2024/06/2847269302.png) ![image.png](https://www.zunmx.top/usr/uploads/2024/06/709101366.png) # 注意 <div class="tip inlineBlock warning"> 这里需要注意的是,上文代码中的Licenses和许可证是写死的,如果使用其他语言的语言包,需要手动修改一下。 </div> <div class="tip inlineBlock warning"> jar文件路径 idea == > app-client.jar clion ==> app-client.jar datagrip ==> app.jar 操作前需要先备份一下 </div> <div class="tip inlineBlock warning"> 经过测试,MyDialog是所有子窗口的类,如果一股脑全部关闭,设置,新建,打开,关于,你都将无法看到。 但是用了这个方法,注册窗口也是无法显示出来的 </div> <div class="tip inlineBlock warning"> 这种方法不能绕过插件的激活 </div> # 工程实例 ![image.png](https://www.zunmx.top/usr/uploads/2024/06/3344638210.png) ![image.png](https://www.zunmx.top/usr/uploads/2024/06/92482229.png) ## 示例下载 下载链接:[jetbrains_cracker.zip](https://www.zunmx.top/usr/uploads/2024/06/1200008417.zip) 运行: ```bash java -jar jetbrains_cracker-1.0-SNAPSHOT-jar-with-dependencies.jar ``` ## 示例git git链接:[git - jetbrains_cracker](http://git.zunmx.top/zunmx/jetbrains_cracker) ⚠ 仅以开源和学习精神,切勿用于商业用途。 # 结语 当然52论坛里的那个人也是我。 请支持正版,仅供研究学习使用,请勿用于非法用途。 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 1 如果觉得我的文章对你有用,请随意赞赏