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/
发错地方了吧?