Charles 是常用的抓包软件,可以用于分析 http(s) 流量,使用 Java 编写。目前最新版是 4.6.2,来试下它的破解。

工具

Java Decompiler 反编译 Java 字节码 https://github.com/java-decompiler/jd-gui/releases
Recaf 编辑 Java 字节码 https://github.com/Col-E/Recaf/releases

破解

Charles 启动时会提示“This is a 30 day trial version”,用 Java Decompiler 打开安装目录下 lib\charles.jar 直接搜索字符串,搜到字符串位于 SplashWindow.class 文件中,同时也能看到相关的引用

...
public void showSharewareStatus() {
  showStatus("This is a 30 day trial version. If you continue using Charles you must\npurchase a license. Please see the Help menu for details.");
}

public void close() {
  setVisible(false);
  dispose();
}

public static void a(Window paramWindow, Runnable paramRunnable) {
  SplashWindow splashWindow = new SplashWindow(paramWindow);
  splashWindow.showSharewareStatus();
  splashWindow.setDelay(5);
  splashWindow.setVisible(true);
  a.a(new ad(splashWindow, paramRunnable));
}

public void executeDelay() {
  repaint();
  while (getDelay() > 0) {
    try {
      Thread.sleep(1000L);
    } catch (InterruptedException interruptedException) {}
    setDelay(getDelay() - 1);
    repaint();
  }
}

public void showRegistrationStatus() {
  if (p.a()) {
    showStatus("Registered to: " + p.c());
  } else {
    showSharewareStatus();
  }
}
...

点击 L31 的 p.a() 跳转,可以看到 a() 是一个静态函数,将注册状态简单以 bool 值返回,所以在这里爆破改成 return true; 就好了。

public class p {
  ...
  private static p ab;
  ...
  public static boolean a() {
    return ab.d();
  }
  ...
}

用 Recaf 打开 charles.jar 定位到 p.a() 后改成

DEFINE PUBLIC STATIC a()Z
ICONST_1
IRETURN

并保存就可以了。

替换原始文件,运行,会发现启动界面卡住了,进不去主界面。显然还有问题没解决,但是界面上并没有明显的提示。这里我们可以用命令行运行 Charles。运行后会打印异常堆栈。

...
Caused by: java.lang.NullPointerException
        at com.xk72.charles.p.e(Unknown Source)
        at com.xk72.charles.p.c(Unknown Source)
        at com.xk72.charles.gui.SplashWindow.showRegistrationStatus(Unknown Source)
        at com.xk72.charles.gui.X.run(Unknown Source)
        at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
        at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
        at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
...

是个空指针异常,而上面 p.c() 是个和 p.a() 一样的静态函数,它用来返回静态实例中的注册用户名。

public static String c() {
  return ab.e();
}

因为实际上并没有走完验证流程,所以也没有给 p 的静态变量 ab 新建实例,因此会有空指针异常。
所以这里改巴改巴,直接 return new String(“???”) 返回就好了,收工。启动 10 秒和运行半小时限制都没了。
如果想尝试注册机也可以,算法都在写在同一个 class 文件里,直接看就行。
crack charles

注册机

鸽了,可参考大佬搞的注册机 https://www.zzzmode.com/mytools/charles/