一、常規 JAVA 軟件破解流程
先講一下常規jar包的破解流程。
1. 快速定位。
1) 通過procmon監控相關軟件,查看程序都訪問了些啥。
2) 用jd-gui反編譯 jar 包,得到源碼。
3) 搜索關鍵字以定位。
這種定位方法只是千萬種中的一種,根據不同軟件的不同執行特性再具體實施不同的定位方案。
2. 修改破解。
1) 用 dex2jar 將 JAR 包轉成 Dex 文件。
2) 再將 Dex 解出 Smali。
3) 修改 Smali 代碼
4) 將修改後的文件重新打包回 Dex
5) 最後轉成 JAR 包,破解完成。
二、直接修改 .class 字節碼的方式實現破解
上面的方式基本已經可以解決破解JAR包的需求。但最近研究了一下直接修改.class 字節碼的形式來實現修改程序流程的方法,總有會用得上的應用場景的。下面進入正題。
很多時候別人的 jar 包,反編譯過來後是沒辦法直接用Eclipse創建java 工程再編譯通過的。各種引用及反編譯帶來的錯誤會讓人抓狂。既然破解的關鍵點已經找到了,我們可以不可以直接修改.class 字節碼以實現破解呢,答案是肯定的。
此處省略定位環節,不是本文重點。
準備工具
1. jclasslib 源碼地址:https://github.com/ingokegel/jclasslib
2. 010 Editor 神器不多說
參考資料
1. The class file format
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6
2. 中文版Class文件結構
http://gityuan.com/2015/10/17/jvm-class-instruction/
Start
假設通過反編譯我們已經知道了關鍵代碼的位置。
知道函數路徑後,用jclasslib 打開 .class 文件定位的相關函數處。
點擊右邊的相關指令可以跳轉到指令查詢頁面:
可以看到 aload_0 對應的字節碼爲 0x2a。以此類推,查詢到我們需要的特徵指令對應的字節碼。
指令:
aload_0
ifnonnull 6 (+5)
iconst_5
ireturn
aload_0
字節碼
2a c7 xx xx 08 ac 2a (xx xx 是 ifnonnull 後面跟的 2 字節立即數)
用 010 Editor 打開 .class 文件,會自動加載其文件格式的 .bt 格式解析文件
通過jclasslib 我們知道目標函數在methods 函數表中的19號索引位置,用010找到相應的位置
通過 .class 文件結構我們知道,具體代碼在 struct attribute_info attributes 裏面 u4attribute_length 描述了代碼區長度。接着下面給出了以1字節爲單位的代碼區數組。通過查詢 attribute_info 結構體我們知道這裏的 info 數組其實還包含了很多結構信息在裏面,我們可以手工對應一下。
因爲我們查看的是 Methods表 u2 attribute_name_index 通常指向的是 Code 結構體,表明這段結構體是 Code 結構體。看一下 Code 結構的說明:
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
通過jd-gui 反編譯時我們已經知道,這個函數返回的是一個Int型數值,函數體內做了一些判斷處理,這裏我們將把這個函數修改成直接返回我們需要的數值。
比如 return 1000;
上面這句話對應jvm 指令爲:
sipush 1000
ireturn
對應的字節碼是:
11 03 E8 AC (03 E8= 1000數字是高字節序)
修改完後的樣子
然後,結構體後面多餘的字節就可以直接刪除了。
現在大功告成,將修改後的 .class 文件替換原來的就可以了。
需要注意的細節坑
1. 010 Editor在解析 .class 常量池數組時對 01 0000 (空的 CONSTANT_Utf8 類型)的支持不好,可能導致出錯。調試時可以先將出錯的這三個字節碼刪除,並對應修改constant_pool_count 常量池個數,再按 F5 重新解析。
注意:此時索引的序號指向可能是錯的,可以結合 jclasslib 查看對應值。
2. 重新打包 JAR 包,運行時提示"AWT-EventQueue-0" java.lang.SecurityException: SHA-256 digesterror for ***.class。查看Manifest文件看看有沒有RSA 加密設定,如果有直接刪除,再打包運行就可以了。
大大們有更好更簡潔的方法還請不吝賜教!