破解 jar 包之直接修改 .class 文件方式

一、常規 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 加密設定,如果有直接刪除,再打包運行就可以了。


大大們有更好更簡潔的方法還請不吝賜教!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章