mac Charles v4.0.2详细破解教程

背景

Charles是一款十分优秀的抓包软件,尤为是在mac操做系统下。Charles是一款商用软件,其体验版虽然可以使用所有功能,可是有如下几个使用上不方便的地方:javascript

  1. 启动时有10s的提示购买窗口,而且每过4分钟,当你再次点击Charles进行操做时,还会弹出一个持续5s的提示购买窗口。提示购买窗口截图以下:html

  2. 一旦运行超过30分钟,就会弹出下面的error提示窗口,而且终止程序:java

出于学习和研究目的,在成功破解了Charles以后,发现Charles破解能够做为一个十分典型的Jar包破解教学,由于其破解流程具备如下几个特色:linux

  1. Jar通过了代码混淆。
  2. 破解思路多。
  3. 能够利用的破解工具多。

在详细地讲解Charles破解以前,我先介绍一下环境:windows

  • macOS 10.11.6
  • charles v4.0.2
  • jdk 1.8

好了,接下来,让咱们来详细地讲解一下如何对Charles进行破解。网络

破解流程

思路一

代码分析和定位

在背景中咱们介绍过了,Charles体验版未对功能作过阉割,因此第一种破解思路是取消掉Charles对体验版作的限制。无论怎么样,全部Jar包破解的第一步,都是经过反编译软件来阅读代码。这里咱们使用的是JD-GUI,这是一款十分优秀的java反编译软件,除了可以阅读反编译以后的代码以外,还能够进行搜索。oracle

咱们首先进入Charles,在mac下能够经过右键Charles的图标,而后选择显示包内容。进入到Java目录,而后用JD-GUI打开charles.jar:app

通过观察以后,咱们发现charles.jar通过了代码混淆,这样程序内部的不少逻辑只能靠经验去猜想了。因为提示购买窗口那里有个"Delay",因此咱们先搜索全部出现过"Delay"字符串的地方。经过分析搜索结果,咱们大胆猜想SplashWindow是用来处理窗口的相关逻辑,而且setDelay方法是用来设置窗口的显示时间:框架

而后咱们搜索全部调用setDelay方法的代码,十分幸运的是,咱们一会儿就发现了设置启动界面10s delay时间和设置每过4分钟后的5s delay时间的代码位置。jvm

删除启动界面的10s delay

第一处是位于com.xk72.charles.gui的V.class中:

为了给咱们接下来的操做打好基础,咱们首先须要对jar包进行解压缩。可是因为Charles作过了基于类名的代码混淆,这会致使jar包没法在文件名不区分大小写的操做系统上解压出来(好比a.class会在解压的过程当中被A.class给覆盖掉)。这是一种十分常见的混淆技术,因为咱们最经常使用的windows和mac操做系统都是不区分文件名大小写的操做系统,因此这种混淆办法能够将大部分的bad boy给拦截在外。下图为ProGuard混淆工具开启类名混淆的截图:

为了解决这种状况,通常我都会使用Linux系统来解压通过类名混淆过的Jar包。解压以后,咱们经过JBE字节码修改工具来对V.class的字节码进行修改。对于JBE的使用方法,你们能够参考我写的另外一篇文章:www.jianshu.com/p/a61f0f447…。修改V.class的方法很简单,只须要将run方法对应的字节码删除,只留下return便可。

删除每过4分钟的5s delay

第二处位于SplashWindow的a方法中:

修改方法很简单,只须要将对应的字节码除了return以外所有删除,使其成为一个空方法便可。

删除半个小时退出的代码

最后,咱们须要删去半个小时退出的代码。定位代码的思路很简单,搜索error对话框中出现过的字符串便可,这里咱们经过JD-GUI搜索"unlicensed copy",从搜索结果中,咱们能够找到com.xk72.charles包下的e.class中有对应的逻辑:

修改方法同上,利用JBE将run方法对应的字节码除了return以外所有删除,使其成为一个空方法便可。

最后

将上述全部hack过的class文件打包进原来的jar包中(必定要在linux系统下),替换原来charles app下的charles.jar,启动后咱们发现已被成功破解。

思路二

代码分析和定位

其实思路一并非一种常规思路,大部分状况下,咱们都会对处理"License"的方法进行破解。若是你们完整地走过一遍思路一的方法,那么确定会发如今com.xk72.charles包下有一个叫作License.class的类,而且该类的a方法常常被外部调用,用来判断是否已经注册成功,好比每过4分钟显示提示购买窗口的逻辑:

修改判断是否已经注册方法

咱们能够大胆地认定该方法是用来判断是否已经注册的。顺着该思路,咱们先来尝试将该方法修改成永远返回true。经过JBE将a方法对应的字节码修改成:

iconst_1
ireturn复制代码

而后启动Chalres发现一直卡在Loading Preferences界面。为了找出缘由,再介绍一个小技巧,咱们能够经过命令行的方式来启动程序:java -jar ../Charles.app/Contents/Java/charles.jar,而后咱们能够看到控制台会输出对应的错误堆栈。从错误堆栈中咱们能够看到有空指针的异常:

能够看到是License的b方法:

修改显示License名称方法

咱们大胆猜想该方法是用来显示License名称的,咱们将其修改成返回一个固定的字符串(本身想叫什么就叫什么)。读者若是对java字节码不是很熟悉的话,有一种最简单的作法是本身先写一个demo java程序,而后用JBE查看对应的字节码:

ldc "wooyoo"
areturn复制代码

继续运行时又抛出了VerifyError:

这个错误是JVM字节码校验失败产生的。该问题很大几率是由于JBE的bug,为了解决这个问题,咱们有如下3种解决方法:

  1. 关闭JVM的字节码校验。
  2. 使用javassist来修改字节码。
  3. 本身编译License
关闭JVM的字节码校验

为了关闭JVM的字节码校验,咱们须要添加额外的JVM启动参数。因为个人电脑的java环境是1.8,因此只能经过添加-noverify参数,若是是1.7的话,还可使用-XX:-UseSplitVerifier。咱们能够在Charles程序目录下的info.plist文件里面添加关闭参数:

......
<key>JVMOptions</key>
<array>
<string>-noverify</string>
......复制代码
使用javassist来修改字节码

javassist经常使用来动态地修改字节码,普遍地用于各个java框架里面(这里用它来破解软件真是有点很差意思)。修改代码以下:

public class Test {
    public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
        ClassPool classPool = ClassPool.getDefault();
        classPool.insertClassPath("/path/to/charles.jar");
        CtClass license = classPool.get("com.xk72.charles.License");
        // 修改a方法
        CtMethod aOldMethod = license.getDeclaredMethod("a", null);
        CtMethod aNewMethod = CtNewMethod.copy(aOldMethod, license, null);
        aOldMethod.setName("a_old");
        aNewMethod.setBody("{return true;}");
        aNewMethod.setName("a");
        license.addMethod(aNewMethod);
        // 修改b方法
        CtMethod bOldMethod = license.getDeclaredMethod("b", null);
        CtMethod bNewMethod = CtNewMethod.copy(bOldMethod, license, null);
        bOldMethod.setName("b_old");
        bNewMethod.setBody("{return \"wooyoo\";}");
        bNewMethod.setName("b");
        license.addMethod(bNewMethod);
        // 输出新的License.class
        license.writeFile("/path/to/License.class");
    }
}复制代码

须要注意的是,在使用javassist的时候,咱们没法移除原来方法里面的逻辑。基于此,咱们有如下两种作法:

  • 先copy原来方法,而后调用setBody方法往新方法中塞入本身的逻辑。上述代码采用的就是这种方法。

  • 能够在原来的方法中调用insertBefore方法,好比:

    CtMethod bMethod = license.getDeclaredMethod("b", null);
    bMethod.insertBefore("{if(1<2) return \"wooyoo\"}")复制代码

    咱们经过一个确定会执行的if语句,来达到仅执行本身逻辑的效果。

本身编译License

该方法也是参考了网络上另外一我的的破解文章:blog.csdn.net/endlu/artic…,我这里就再也不赘述了,有兴趣的读者能够看这篇文章。

最后

将上述hack过的License.class文件打包进原来的jar包中。这里咱们不必定要在Linux系统下完成打包,能够借用jar命令直接完成class文件的替换:jar -uvf charles.jar com/xk72/charles/License.class。而后将新的jar包替换原来charles app下的charles.jar,启动后咱们发现已被成功破解。

总结

再次声明以上教程都是基于学习和研究的目的,咱们强烈建议你们有能力的话仍是要购买正版软件。好了咱们来总结一下经过此次破解咱们须要掌握的知识点:

  • 通过类名混淆过的Jar没法在不区分文件名大小写的操做系统上进行压缩或者解压缩。咱们能够借用Linux操做系统来完成压缩或者解压缩操做。
  • 破解的思路通常都是修改处理"License"的逻辑。可是咱们不能局限于此,好比在本例中,咱们能够去除掉体验版的限制,一样达到破解的目的。
  • 某些状况下若是破解不成功,咱们能够经过命令行启动程序,而后经过观察控制台输出的错误堆栈来看究竟是哪里出了问题。另外若是程序有日志文件的话,咱们还能够去日志文件中分析错误缘由。
  • 咱们能够经过JBE、javassist甚至是本身从新编译的方式来修改原来的字节码。

参考资料

相关文章
相关标签/搜索