ASM 修改位元組碼 引發的R8 編譯報錯
問題原因
首先看下 這段新浪微博的程式碼
裡面有deviceId的獲取,目前這個程式碼是不合規的對吧,我想把這段程式碼替換掉
那怎麼做呢? 我們先寫一個demo class 看看能否hook成功》?
然後就是操作我們的自己碼了,我們用asm來做
很顯然我們的思路就是 將 TelephoneManager.getDeviceId這個操作 在編譯期間 利用asm 來 替換成 FakeTelephoneManager的getFakeDeviceId 這個方法 但是注意了,我這裡的getFake方法是一個 靜態方法
然後重新build 發現TestHook這個類編譯成功了,
然後我又增加了一個配置 去hook 文章開頭的新浪微博的DeviceInfo這個類
結果transform這個地方執行成功了,但是 dexBuilder那裡執行失敗報錯了
具體報錯原因如下:
[CIRCULAR REFERENCE: com.android.tools.r8.internal.Hc: Different stack heights at jump target: 0 != 1]
這就很奇怪了, 為啥r8這裡會報錯呢? 看報錯原因 似乎是有迴圈引用? 還是r8和asm不相容?
我嘗試的去掉 deviceInfo 只保留testhook類 發現是ok的
看來問題就出現在asm hook deviceInfo上
是asm的寫法 有問題 導致了 r8 這邊有報錯(到這裡其實大概率能猜到 r8這個報錯其實是誤報了,根源在asm hook上)
自習排查以後 發現
deviceInfo裡面的呼叫 時invokevirtual的操作符,我們這裡修改的本質其實是:
物件成員函式的呼叫 修改成靜態函式呼叫。
所以如果要這麼做的話 需要修改 引數的入棧邏輯才行 因為之前是有個物件入棧的邏輯的
那改成靜態函式呼叫的話 這一步操作就沒有了,所以你要額外處理之前的引數入棧邏輯
這裡為了簡單一點,我們可以 在定義fake靜態函式的時候 加上一個對應的引數就可以了,這樣就可以利用之前的引數的入棧邏輯,而不用大改了
這裡可以看下 hook的方法中 對desc做了修改,新增了android/telephony/TelephonyManager作為引數
private fun MethodInsnNode.optimize(klass: ClassNode, method: MethodNode) {
// 判斷是否是deviceId(0)這個方法
val flag = (this.desc == "(I)Ljava/lang/String;" && this.name == "getDeviceId")
this.owner = fakeOwner
if (flag) {
this.name = fakeTelephonyManagerTakeIdMethodName
this.desc = "(Landroid/telephony/TelephonyManager;I)Ljava/lang/String;"
} else {
this.name = fakeTelephonyManagerMethodName
this.desc = "(Landroid/telephony/TelephonyManager;)Ljava/lang/String;"
}
this.opcode = Opcodes.INVOKESTATIC
this.itf = false
}
位元組碼對比
可以看下對比 test1 這裡是呼叫了一個物件的函式,test2 則是呼叫的靜態函式
可以很明顯的看出來 指令的區別 ,對於物件的函式來說 是有 astore和aload的指令的,有入棧的操作
而靜態函式則沒有
再看下我們之前錯誤的asm 修改
這裡的aload3 其實就是load了 telephonemagner的物件 入棧頂了,但是invokestatic 卻沒使用這個
報錯就是在這裡了, 所以解決方案也很簡單,我們靜態函式增加一個telephonemagner的引數即可,這樣就可以利用到這個zhan頂的元素了。 從而規避掉這個問題
否則你還要想辦法 去掉這個aload的指令 那樣確實是太麻煩了 哈哈
- Jetpack Compose - Effect與協程 (十五)
- 谷歌的bug:當 CompileSdk 33 遇上Kotlin
- Jetpack Compose - DrawModifier (十三)
- Jetpack Compose - Transition動畫 (十)
- Jetpack Compose - 慣性衰減動畫AnimateDecay(八)
- Jetpack Compose - AnimationSpec (七)
- Jetpack Compose - Animatable與animateAsState (六)
- Jetpack Compose - 淺談 CompositionLocal (五)
- ASM 修改位元組碼 引發的R8 編譯報錯
- Go語言 基於gin框架從0開始構建一個bbs server(二)-使用者登入
- Go語言 基於gin定義一個簡單的web server 開發框架(三)
- Go語言 基於gin定義一個簡單的web server 開發框架(二)
- Go語言 viper與web服務的關機,重啟
- Go語言 zap日誌系統與gin繼承
- Go語言 go-redis與watch
- Go 語言 MySql 基本操作
- Go 語言 常用標準庫 介紹
- Go語言 併發-select 與 鎖
- Go語言 併發-Channel
- Go語言 錯誤處理以及資源管理