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甚至是本身從新編譯的方式來修改原來的字節碼。

參考資料

相關文章
相關標籤/搜索