Charles是一款十分優秀的抓包軟件,尤爲是在mac操做系統下。Charles是一款商用軟件,其體驗版雖然可以使用所有功能,可是有如下幾個使用上不方便的地方:javascript
啓動時有10s的提示購買窗口,而且每過4分鐘,當你再次點擊Charles進行操做時,還會彈出一個持續5s的提示購買窗口。提示購買窗口截圖以下:html
一旦運行超過30分鐘,就會彈出下面的error提示窗口,而且終止程序:java
出於學習和研究目的,在成功破解了Charles以後,發現Charles破解能夠做爲一個十分典型的Jar包破解教學,由於其破解流程具備如下幾個特色:linux
在詳細地講解Charles破解以前,我先介紹一下環境:windows
好了,接下來,讓咱們來詳細地講解一下如何對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
第一處是位於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便可。
第二處位於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名稱的,咱們將其修改成返回一個固定的字符串(本身想叫什麼就叫什麼)。讀者若是對java字節碼不是很熟悉的話,有一種最簡單的作法是本身先寫一個demo java程序,而後用JBE查看對應的字節碼:
ldc "wooyoo"
areturn複製代碼
繼續運行時又拋出了VerifyError:
這個錯誤是JVM字節碼校驗失敗產生的。該問題很大機率是由於JBE的bug,爲了解決這個問題,咱們有如下3種解決方法:
爲了關閉JVM的字節碼校驗,咱們須要添加額外的JVM啓動參數。因爲個人電腦的java環境是1.8,因此只能經過添加-noverify參數,若是是1.7的話,還可使用-XX:-UseSplitVerifier。咱們能夠在Charles程序目錄下的info.plist文件裏面添加關閉參數:
......
<key>JVMOptions</key>
<array>
<string>-noverify</string>
......複製代碼
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語句,來達到僅執行本身邏輯的效果。
該方法也是參考了網絡上另外一我的的破解文章: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,啓動後咱們發現已被成功破解。
再次聲明以上教程都是基於學習和研究的目的,咱們強烈建議你們有能力的話仍是要購買正版軟件。好了咱們來總結一下經過此次破解咱們須要掌握的知識點: