一種新的修改字節(jié)碼的思路

博客地址: dim.red

0x00 前言

分析最近的 Crash , 排在前列基本是第三方SDK導(dǎo)致. 遇到這樣的問題, 我們需要尋求官方的支持, 但是官方的支持總是來(lái)得比較晚. 在Android上, 第三方SDK一般是兩種, 一種是jar, 一種是so. so的修改成本過大, 我們放棄它, 我們現(xiàn)在探討對(duì) jar 的修改.

0x02 問題

在之前 使用AOP來(lái)為第三方SDK打CALL 文章 我們使用 AOP 對(duì)第三方 SDK 的問題進(jìn)行修復(fù). 貌似能這樣解決這個(gè)問題.
但是 AOP 存在局限性:
1、它不夠直觀. 定義的規(guī)則需要通過編譯后才能確定.
2、學(xué)習(xí)成本較高.
3、可操作的范圍不夠大. 只能切方法.
例子:
在一些因素下,我們升級(jí)某個(gè)推送SDK版本. 但是發(fā)現(xiàn)有大量的NPE異常出現(xiàn). 通過反編譯 jar 定位問題.

  private Handler p = null;
  private void b() {
        if (this.p != null) {
            this.p.removeMessages(2);
        } else {
            this.p = new Handler(Looper.getMainLooper(), new com.xxx.b(this));
        }
        this.p.sendEmptyMessageDelayed(2, 3000L);
   }
  private void c() {
        if (this.p != null) {
            this.p.removeMessages(2);
            this.p = null;
        }
   }
  public void d(){
  ...
    // 代碼塊A  開始
    if(p != null){
      this.p.sendEmptyMessageDelayed(3, 3000L);
    }
    // 代碼塊A  結(jié)束
  ...
  }

異常發(fā)生在方法this.p.sendEmptyMessageDelayed(2, 3000L);.在一個(gè)判斷空還會(huì)出現(xiàn)NPE, 說明這是一個(gè)多線程并發(fā)下的bug. 通過分析我們需要

  1. 對(duì)b c 方法使用synchronized 修飾
  2. 對(duì)代碼塊A 進(jìn)行 synchronized(this) 包裹

在這種場(chǎng)景下使用AOP將費(fèi)力不討好.

0x03 解決方案

我們可以嘗試使用一種更簡(jiǎn)單的方式來(lái)處理這件事情. 輸入一個(gè)原始的 jar , 經(jīng)過轉(zhuǎn)換生成新的 jar.

  • 步驟1: 對(duì) jar 中需要修改的 class 反編譯成 java 文件.
  • 步驟2: 對(duì) java 文件進(jìn)行代碼邏輯上的 bug fix.
  • 步驟3: 使用 javac 編譯 java 文件成 class 文件.
  • 步驟4: 替換 jar 中對(duì)應(yīng)的修改的 class 文件生成新的 jar 文件.

0x04 問題

Q : javac 編譯失敗.
A: 當(dāng)你 java 調(diào)用的方法不在原有的 jar 中, 導(dǎo)致 javac 編譯的時(shí)候找不到對(duì)應(yīng)的方法,拋出異常.
解決方式:使用 asm 對(duì) jar 中進(jìn)行指令分析, 對(duì)指令 invokestatic, invokevirtual , invokeinterface , invokedynamic ( android 上可以忽略這個(gè)指令) 和 getfield , getstatic 指令的分析. 我們可以生成一個(gè)空的實(shí)現(xiàn)的jar , 來(lái)為 javac 編譯提供環(huán)境支持.

Q : 內(nèi)部類的問題.
A: 匿名內(nèi)部的生成的規(guī)則是 外部類類名$Number. Number 是在源碼中出現(xiàn)的位置. 當(dāng)你新增和調(diào)整位置的時(shí)候會(huì)導(dǎo)致生成的類和之前的類不匹配. 解決方式. 在對(duì)外部類操作的時(shí)候, 直接對(duì)匿名內(nèi)部類進(jìn)行刪除. 等 javac 命令的生成新的內(nèi)部類直接替換進(jìn)去.

0x05 改進(jìn)

通過和 idea 結(jié)合提供一整套的解決方案.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容