MyBatisCodeHelper-Pro-3.3.6的新激活方案

查看 158|回复 13
作者:wyakuan   
感谢大佬@lvbuqing 的帖子,原帖地址:
https://www.52pojie.cn/thread-1967307-1-1.html
感谢大佬@ljkgpxs  提供的修改反序列化的思路:
通过修改反序列化,添加 userMac、valid、validTo、paidKey 的属性值,激活时输入任意字符,即可实现在线激活或者离线激活
1、找到修改反序列化的类和方法
安装插件后,咱们分别试下在线激活和离线激活,输入任意字符点激活,
在线激活:报错不好定位错误在哪,离线激活:报错直接显示错误在哪


2024-10-15_155125.png (86.33 KB, 下载次数: 0)
下载附件
2024-10-15 17:13 上传

咱们就从离线激活入手,报错信息如下:
[Java] 纯文本查看 复制代码激活码不正常java.lang.RuntimeException: com.ccnode.codegenerator.af.f.b: 密文有问题
at com.ccnode.codegenerator.af.f.d.b(SourceFile:281)
at com.ccnode.codegenerator.af.f.e.a(SourceFile:19)
at com.ccnode.codegenerator.af.b.a.a(SourceFile:412)
at com.ccnode.codegenerator.af.c.a(SourceFile:65)
at com.ccnode.codegenerator.b.a.doOKAction(SourceFile:219)
打开反编译工具 jadx-gui-1.5.0.exe,将 instrumented-MyBatisCodeHelper-Pro241-3.3.6+2321.jar 拖进去。
找到 com.ccnode.codegenerator.af.f.d.b(SourceFile:281):
这是激活时验证公钥的地方,这不是我们要找的。


2024-10-15_162321.png (141.6 KB, 下载次数: 0)
下载附件
2024-10-15 17:13 上传

找到 com.ccnode.codegenerator.af.f.e.a(SourceFile:19):
看到 Base64.getDecoder().decode 和 f1767a.fromJson(str2, f.class),这是对字符串(str)进行解码,然后反序列化转成对象(f)的过程,这就是我们要找的。


2024-10-15_162841.png (110.57 KB, 下载次数: 0)
下载附件
2024-10-15 17:13 上传

我们看一下方法返回的对象(f)的结构:


2024-10-15_163739.png (96.64 KB, 下载次数: 0)
下载附件
2024-10-15 17:13 上传

到这我们就找到了反序列化的方法,我们修改一下这个类的方法,添加 userMac、valid、validTo、paidKey 的属性值,
修改这个方法需要添加 gson 和 jettison 两个Jar包,可以通过Maven添加依赖后下载(pom.xml添加以下依赖)。
[XML] 纯文本查看 复制代码
   com.google.code.gson
   gson
   2.11.0
    org.codehaus.jettison
    jettison
    1.5.4
[Java] 纯文本查看 复制代码File oldJar = new File("D:\\test\\instrumented-MyBatisCodeHelper-Pro241-3.3.6+2321.jar");
String decodeClassFullName = "com.ccnode.codegenerator.af.f.e";
String jarDir = oldJar.getParent();
// 加载类
ClassPool classPool = ClassPool.getDefault();
// 添加需要修改和所依赖的Jar包
classPool.appendClassPath(oldJar.getAbsolutePath());
classPool.appendClassPath("D:\\test\\gson-2.11.0.jar");
classPool.appendClassPath("D:\\test\\jettison-1.5.4.jar");
// 获取需要修改的解码类
CtClass decodeCtClass = classPool.get(decodeClassFullName);
// 解码类的解码方法并修改
CtMethod decodeCtMethod = Arrays.stream(decodeCtClass.getDeclaredMethods())
        .filter(method -> {
            try {
                return Modifier.isPublic(method.getModifiers())
                        && method.getParameterTypes().length == 1
                        && String.class.getSimpleName().equals(method.getParameterTypes()[0].getSimpleName());
            } catch (NotFoundException e) {
                throw new RuntimeException(e);
            }
        }).findFirst().orElseThrow();
String returnType = decodeCtMethod.getReturnType().getName();
decodeCtMethod.setBody("{"
        // 添加 userMac、valid、validTo、paidKey 属性值
        + " org.codehaus.jettison.json.JSONObject jsonObject;"
        + " try {"
        + "     jsonObject = new org.codehaus.jettison.json.JSONObject($1);"
        + " } catch (Exception e) {"
        + "     jsonObject = new org.codehaus.jettison.json.JSONObject();"
        + " }"
        + " if (!jsonObject.has(\"userMac\") || jsonObject.get(\"userMac\") == null) {"
        + "     String macAddress;"
        + "     try {"
        + "         java.net.InetAddress ip = java.net.InetAddress.getLocalHost();"
        + "         java.net.NetworkInterface network = java.net.NetworkInterface.getByInetAddress(ip);"
        + "         byte[] mac = network.getHardwareAddress();"
        + "         StringBuilder stringBuilder = new StringBuilder();"
        + "         for (int i = 0; i > 4) & 0xF, 16));"
        + "             stringBuilder.append(Character.forDigit(b & 0xF, 16));"
        + "             stringBuilder.append(\"-\");"
        + "         }"
        + "         macAddress = stringBuilder.substring(0, stringBuilder.length() - 1).toUpperCase();"
        + "     } catch (Exception e) {"
        + "         macAddress = \"00-00-00-00-00-00\";"
        + "     }"
        + "     jsonObject.put(\"userMac\", macAddress);"
        + " }"
        + " jsonObject.put(\"valid\", true);"
        + " jsonObject.put(\"validTo\", 4102415999000L);"
        + " jsonObject.put(\"paidKey\", java.util.UUID.randomUUID().toString());"
        + " $1 = jsonObject.toString();"
        // 将Json字符串转换成指定对象
        + "com.google.gson.Gson gson = new com.google.gson.Gson();"
        + returnType + " result = (" + returnType + ")gson.fromJson($1," + returnType + ".class);"
        + "return result;"
        + "}");
// 将修改后的解码类文件写到本地
decodeCtClass.writeFile(jarDir);
// 修改强制退出类
String exitClassFullName = "com.ccnode.codegenerator.myconfigurable.Profile";
CtClass exitCtClass = classPool.get(exitClassFullName);
exitCtClass.getDeclaredMethod("getIfUseNewMapping").setBody("{return 1;}");
// 将修改后的解码类文件写到本地
exitCtClass.writeFile(jarDir);
我们将修改好的 com.ccnode.codegenerator.af.f.e.class 文件替换原来Jar包里的文件,试着在线和离线激活,随意输入字符都能激活成功


2024-10-15_165603.png (67.81 KB, 下载次数: 0)
下载附件
2024-10-15 17:13 上传

PS:后面新版本如何快速找到这个类?在 jadx-gui-1.5.0.exe 的工具栏点文本搜索,输入“private static Gson”,一下子就找到了
2、哈哈,显示激活成功了,是不是很高兴,别急还有坑。
在使用插件生成代码时,会出现弹窗,然后强制idea退出


2024-10-15_165753.png (23.23 KB, 下载次数: 0)
下载附件
2024-10-15 17:13 上传

在 jadx-gui-1.5.0.exe 的工具栏点文本搜索,输入“你正在使用”,点击进去就能看到插件做了判断:
getIfUseNewMapping() > 100 就会出现弹窗,然后强制退出


2024-10-15_172745.png (37.37 KB, 下载次数: 0)
下载附件
2024-10-15 17:32 上传

我们修改下 com.ccnode.codegenerator.myconfigurable.Profile 的 getIfUseNewMapping(),直接返回1即可。[Java] 纯文本查看 复制代码// 修改强制退出类
String exitClassFullName = "com.ccnode.codegenerator.myconfigurable.Profile";
CtClass exitCtClass = classPool.get(exitClassFullName);
exitCtClass.getDeclaredMethod("getIfUseNewMapping").setBody("{return 1;}");
// 将修改后的解码类文件写到本地
exitCtClass.writeFile(jarDir);
将修改好的 com.ccnode.codegenerator.myconfigurable.Profile.class 文件替换原来Jar包里的文件,就不会出现弹窗了。
3、将修改好的 class 文件替换原来Jar包里的文件,手动替换容易出错,咱们用Java来替换,生成新的Jar包[Java] 纯文本查看 复制代码// 生成新Jar包,并将修改好的类文件添加到新的Jar包中
File newJar = new File(oldJar.getAbsolutePath().replace(".jar", "-new" + ".jar"));
// 修改好的类文件
List editClasses = Stream.of(decodeClassFullName, exitClassFullName).map(item -> item.replace(".", "/") + ".class").toList();
try (JarFile jarFile = new JarFile(oldJar); JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(newJar))) {
    Enumeration entries = jarFile.entries();
    while (entries.hasMoreElements()) {
        JarEntry entry = entries.nextElement();
        // 将修改后的类文件和原Jar包的类文件,都添加到新的JAR中
        try (InputStream inputStream = editClasses.contains(entry.getName()) ? new FileInputStream(new File(jarDir, entry.getName())) : jarFile.getInputStream(entry)) {
            jarOutputStream.putNextEntry(new JarEntry(entry.getName()));
            byte[] bytes = inputStream.readAllBytes();
            jarOutputStream.write(bytes);
            jarOutputStream.closeEntry();
        }
    }
}

文件, 下载次数

wyakuan
OP
  

添加一个修改好的
wyakuan
OP
  

如果可以连网,那就用在线激活,在线激活有个一劳永逸的方案,就是修改 Gson Jar包中的Gson.fromJson方法,添加 valid、validTo、paidKey 的属性值即可激活。
好处:不用每个版本都去破解一次,只要将修改好的 gson-2.11.0_modify.jar 放到 MyBatisCodeHelper-Pro 插件的lib目录下即可。


2024-10-16_175220.png (129.36 KB, 下载次数: 0)
下载附件
2024-10-16 18:51 上传

PS:后期如果在idea内直接升级插件的话,记得重新复制 gson-2.11.0_modify.jar 过去,因为在idea内升级,它是先把旧插件删除的,gson包也会被删除
论坛爱好者   

楼主你好,有两个问题还请解答下
1,在修改解码json方法时com.ccnode.codegenerator.af.f.e ,
为什么要引入两个处理操作json的包呢? 是否可以只引入一个?
classPool.appendClassPath("D:\\test\\gson-2.11.0.jar");
classPool.appendClassPath("D:\\test\\jettison-1.5.4.jar");
2,引入gson-2.11jar 这个我明白 这个mybatiscodehelper这个项目lib文件夹下存在这个包,
而jettison 这个包并不存在lib文件夹下,即使你编译进源码中,那么程序执行的时候,不会因为不存在这个包报错吗?
xin1you1di1   

感谢分析 6666666
wyakuan
OP
  


Bigdangjia 发表于 2024-10-21 21:55
最后使用了替换gson的方式解决了,直接下IDEA插件库的,然后替换随便输入激活码替换即可

OK,能用就行,其实添加gson包是最方便的,每个版本都能用
似水流年小小   

有人试试嘛?  有没有毒
jun269   


wyakuan 发表于 2024-10-15 18:45
添加一个修改好

高手,牛
jun269   


wyakuan 发表于 2024-10-15 18:45
添加一个修改好

楼主,您打包的这个东西是不是就是一个成品,软件安装完后直接拖进去即可?您这个是不是适合于JetBrains这款软件系列的所有产品?谢谢!
暗影拽神   

先收藏在点赞
您需要登录后才可以回帖 登录 | 立即注册

返回顶部