記錄一下YAHFA相關

首先寫一個安卓demo如下

    findViewById(R.id.sample_text).setOnClickListener(v -> {
            try {
                Method doWork1 = MainActivity.class.getDeclaredMethod("doWork1");
                Method doWork2 = MainActivity.class.getDeclaredMethod("doWork2");
                Method doWork3 = MainActivity.class.getDeclaredMethod("doWork3");

                calledBefore(doWork1,doWork2,doWork3);
                HookMain.backupAndHook(doWork1,doWork2,doWork3);
                calledAfter(doWork1,doWork2,doWork3);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        });
    }

    private static void doWork1() {
        Log.i(TAG, "doWork1");
    }
    private static void doWork2() {
        Log.i(TAG, "doWork2");
    }
    private static void doWork3() {
        Log.i(TAG, "doWork3");
    }

    public native void calledBefore(Method doWork1, Method doWork2, Method doWork3);
    public native void calledAfter(Method doWork1, Method doWork2, Method doWork3);

兩個native方法(calledBefore/calledAfter)在native層啥也不用做 只是拿到一個反射方法

順帶附上hook代碼,主要是用frida展示artmethod指針內存的變化

var getArtMethod = new NativeFunction(Module.findExportByName('libnative-lib.so','getArtMethod'),'pointer',['pointer','pointer'])

Interceptor.attach(Module.findExportByName('libnative-lib.so','Java_com_lzy_yahfa_MainActivity_calledBefore'),{
    onEnter:function(args){
        LOG("\n----------------------- Before -----------------------\n",LogColor.RED)
        showLog(args[0],args[2],args[3],args[4])
    },
    onLeave:function(ret){

    }
})

Interceptor.attach(Module.findExportByName('libnative-lib.so','Java_com_lzy_yahfa_MainActivity_calledAfter'),{
    onEnter:function(args){
        LOG("\n----------------------- After -----------------------\n",LogColor.RED)
        showLog(args[0],args[2],args[3],args[4])
    },
    onLeave:function(ret){

    }
})

function showLog(a0,a1,a2,a3){

    LOG(" ----- ORG  ----- ",LogColor.YELLOW)
    var method = getArtMethod(a0,a1)
    seeHexA(method,p_size*8)
    LOG("entry_point_from_quick_compiled_code -> "+method.add(p_size*7).readPointer()+" ---> "+method.add(p_size*7).readPointer().readPointer())
    LOG("\n")
    
    LOG(" ----- Hook  ----- ",LogColor.YELLOW)
    var method = getArtMethod(a0,a2)
    seeHexA(method,p_size*8)    
    LOG("entry_point_from_quick_compiled_code -> "+method.add(p_size*7).readPointer()+" ---> "+method.add(p_size*7).readPointer().readPointer())
    LOG("\n")
    
    LOG(" ----- Back  ----- ",LogColor.YELLOW)
    var method = getArtMethod(a0,a3)
    seeHexA(method,p_size*8)
    LOG("entry_point_from_quick_compiled_code -> "+method.add(p_size*7).readPointer()+" ---> "+method.add(p_size*7).readPointer().readPointer())
}

這里我用的是google原生系統 8.1
直接去參考源碼得到 artMethod 704行 結構體長這樣:

4       GcRoot<mirror::Class> declaring_class_;

4       std::atomic<std::uint32_t> access_flags_;   

4       uint32_t dex_code_item_offset_;

4       uint32_t dex_method_index_;

2       uint16_t method_index_;

2       uint16_t hotness_count_;

12      struct PtrSizedFields {
4           ArtMethod** dex_cache_resolved_methods_;

4           void* data_;

4           void* entry_point_from_quick_compiled_code_;
        } ptr_sized_fields_;

運行起來點擊textview即可得到一下日志

三個java方法的art結構體信息

cpu三級流水線可知程序運行到0xf48bc018的時候
pc應該是往后的兩條指令,即為0xf48bc020


ORG的entry_point_from_quick_compiled_code

這里計算一下跳板地址跳到了哪里


跳轉位置

很明顯這個位置就是 hook 函數的 entry_point_from_quick_compiled_code_

繼續看一下 BackUp 函數的實現


實現

第一條指令
ldr r0, [pc, #0xc]
就是把 pc+0x2+0xc位置的值給到了r0,即等價于
ldr r0,=0xf410307c

第二條指令
stmdb sp!, {r0}
r0壓棧

第三條指令
ldr r0, [pc]
等價于
ldr r0,=0xf36174d1 (這個地址就是他的默認入口)

第四條指令
ldm sp!, {pc}
將sp出到pc,也就是配置r0的值為第一個org method指針,并恢復pc為默認的函數入口 0xf36174d1

tips:

  1. 這里的 ldm stmdb 進行入棧出棧并不影響棧頂指針
  2. 這里的函數入口處對sp的讀寫沒關系,不用關心覆蓋問題

總的來說:
替換函數用到了跳板操作
備份函數用到了跳板操作加上一個備份還原,用到了sp,在函數開時候用不用管覆蓋問題,在中途用可以考慮使用超出棧頂指針的部分內存-

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容