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 文件里,直接看就行。

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

发错地方了吧?