Intellij上的 mybatis插件 是一个十分优秀的插件,但是需要付费。在网上搜索一番之后,发现果然有破解版,遂来研究一番破解原理。
该工具的使用方式很简单。具体界面如下:
jbe是基于jclasslib的字节码修改工具,十分强大。假设我们要修改某个方法对应的字节码,具体步骤如下图所示:
软件破解的一般思路,都是hack进校验license的函数,修改里面的校验逻辑。有个小技巧可以帮助我们更快地定位校验激活码的函数:我们可以全局地搜一下”license”、”activate”、”key”以及”valid”等词语,搜索出来的代码一般都是跟处理激活码有关的。
~/Library/Application/ Support/IntelliJIdea2016.2/mybatis_plus/lib
。主要的代码位于mybatis_plus.jar中。 修改stop方法,原来的方法:
我们需要将这段代码逻辑删去,我们通过jbe修改字节码,原来的字节码如下:
aload_0 iconst_1 putfield com/seventh7/mybatis/service/JavaService/stopped Z invokestatic com/seventh7/mybatis/setting/MybatisSetting/getInstance()Lcom/seventh7/mybatis/setting/MybatisSetting; getstatic com/seventh7/mybatis/ref/license/LicenseData/EMPTY Lcom/seventh7/mybatis/ref/license/LicenseData; invokevirtual com/seventh7/mybatis/setting/MybatisSetting/setLicenseData(Lcom/seventh7/mybatis/ref/license/LicenseData;)V goto 9 astore_1 return
我们将不需要的字节码全部删去,只留下return语句:
return
保存之后我们再看反编译之后的stop方法如下:
我们可以看到,原来的逻辑都被删除了。
修改refValid方法,原来的方法如下:
最直观的做法是在方法的最后将valid和validated重置为true,原来的字节码较长,只截取了 return valid
的字节码:
...... getstatic com/seventh7/mybatis/util/JavaUtils/valid Z ireturn
所以我们需要在getstatic之前添加重置为true的字节码:
...... iconst_1 putstatic com/seventh7/mybatis/util/JavaUtils/validated Z iconst_1 putstatic com/seventh7/mybatis/util/JavaUtils/valid Z getstatic com/seventh7/mybatis/util/JavaUtils/valid Z ireturn
iconst_1表示将常量1推入操作数栈,然后通过putstatic修改validated和valid的值。保存之后我们再看反编译之后的refValid方法如下:
修改notifyLicenseInvalid方法,原来方法如下:
修改这个方法的思路和修改JavaService一样,将代码逻辑删除即可,最后的方法如下:
修改activate方法,原来方法如下:
这段代码的修改可能会比较复杂,我直接参考了网上别人的思路。我们需要删去原来代码中通过http请求校验license的逻辑,并且返回一个自己mock的ActivationResult对象。我们观察原来的字节码:
aload_0 invokestatic org/apache/commons/lang/StringUtils/isBlank(Ljava/lang/String;)Z ifeq 7 ldc "License key invalid" invokestatic com/seventh7/mybatis/ref/license/ActivationResult/fail(Ljava/lang/String;)Lcom/seventh7/mybatis/ref/license/ActivationResult; areturn invokestatic com/intellij/openapi/util/Ref/create()Lcom/intellij/openapi/util/Ref; astore_1 new com/seventh7/mybatis/ref/license/ActivationDriver$1 dup aload_1 invokespecial com/seventh7/mybatis/ref/license/ActivationDriver$1/<init>(Lcom/intellij/openapi/util/Ref;)V astore_2 invokestatic com/seventh7/mybatis/util/JavaUtils$SystemData/getInstance()Lcom/seventh7/mybatis/util/JavaUtils$SystemData; astore_3 invokestatic com/seventh7/mybatis/ref/http/HttpPostBuilder/builder()Lcom/seventh7/mybatis/ref/http/HttpPostBuilder; ldc "https://www.codesmagic.com/activate" invokevirtual com/seventh7/mybatis/ref/http/HttpPostBuilder/url(Ljava/lang/String;)Lcom/seventh7/mybatis/ref/http/HttpPostBuilder; ldc "no" aload_0 invokevirtual com/seventh7/mybatis/ref/http/HttpPostBuilder/param(Ljava/lang/String;Ljava/lang/String;)Lcom/seventh7/mybatis/ref/http/HttpPostBuilder; ldc "md5" aload_3 invokevirtual com/seventh7/mybatis/util/JavaUtils$SystemData/getMacAddress()Ljava/lang/String; invokevirtual com/seventh7/mybatis/ref/http/HttpPostBuilder/param(Ljava/lang/String;Ljava/lang/String;)Lcom/seventh7/mybatis/ref/http/HttpPostBuilder; invokevirtual com/seventh7/mybatis/ref/http/HttpPostBuilder/build()Lorg/apache/http/client/methods/HttpPost; astore 4 ldc2_w 1000 new com/seventh7/mybatis/ref/http/RetryFixedTimes dup iconst_3 invokespecial com/seventh7/mybatis/ref/http/RetryFixedTimes/<init>(I)V invokestatic com/seventh7/mybatis/ref/http/HttpExecutorFactory/newRetryExecutor(JLcom/seventh7/mybatis/ref/http/RetryStrategy;)Lcom/seventh7/mybatis/ref/http/RetryHttpExecutor; aload 4 aload_2 invokevirtual com/seventh7/mybatis/ref/http/RetryHttpExecutor/execute(Lorg/apache/http/client/methods/HttpUriRequest;Lcom/seventh7/mybatis/ref/http/HttpHandler;)V aload_1 invokevirtual com/intellij/openapi/util/Ref/get()Ljava/lang/Object; checkcast com/seventh7/mybatis/ref/license/ActivationResult areturn
从第9行开始,也就是 HttpHandler<LicenseData> httpHandler = new HttpHandler()
,到第37行,也就是 return (ActivationResult)ref.get();
,这中间的代码我们都需要删除。然后我们插入下面的字节码:
new com/seventh7/mybatis/ref/license/LicenseData dup ldc "123" ldc "123" invokespecial com/seventh7/mybatis/ref/license/LicenseData/<init>(Ljava/lang/String;Ljava/lang/String;)V astore_2 aload_1 aload_2 invokestatic com/seventh7/mybatis/ref/license/ActivationResult/success(Lcom/seventh7/mybatis/ref/license/LicenseData;)Lcom/seventh7/mybatis/ref/license/ActivationResult; invokevirtual com/intellij/openapi/util/Ref/set(Ljava/lang/Object;)V
其中第1行到第6行,翻译成java代码为:
LicenseData localLicenseData = new LicenseData("123", "123");
这里我们自己模拟了一个License对象,然后从第7行到第10行,翻译成java代码为:
localRef.set(ActivationResult.success(localLicenseData));
这里我们将License对象转换成ActivationResult,并且将其set至ref对象中。总的字节码如下:
aload_0 invokestatic org/apache/commons/lang/StringUtils/isBlank(Ljava/lang/String;)Z ifeq 7 ldc "License key invalid" invokestatic com/seventh7/mybatis/ref/license/ActivationResult/fail(Ljava/lang/String;)Lcom/seventh7/mybatis/ref/license/ActivationResult; areturn invokestatic com/intellij/openapi/util/Ref/create()Lcom/intellij/openapi/util/Ref; astore_1 new com/seventh7/mybatis/ref/license/LicenseData dup ldc "123" ldc "123" invokespecial com/seventh7/mybatis/ref/license/LicenseData/<init>(Ljava/lang/String;Ljava/lang/String;)V astore_2 aload_1 aload_2 invokestatic com/seventh7/mybatis/ref/license/ActivationResult/success(Lcom/seventh7/mybatis/ref/license/LicenseData;)Lcom/seventh7/mybatis/ref/license/ActivationResult; invokevirtual com/intellij/openapi/util/Ref/set(Ljava/lang/Object;)V aload_1 invokevirtual com/intellij/openapi/util/Ref/get()Ljava/lang/Object; checkcast com/seventh7/mybatis/ref/license/ActivationResult areturn
修改之后的activate方法如下所示:
做完了以上操作,重启intellij,就可以看到插件已被成功破解啦~