日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android inline hook手记

發(fā)布時間:2025/1/21 Android 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android inline hook手记 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

許久沒搞安全方面的東西了。最近有些時間看了看android下面的開發(fā),看去看來總是想往內(nèi)深入,結(jié)果又往Native和內(nèi)核挖過去了……

研究了一下ARM架構(gòu)下面的inline實現(xiàn),網(wǎng)上搜了搜似乎沒有找到多少資料。想了想還是寫出來吧,當(dāng)作筆記。由于時間不多,也不是為工作而看, 僅僅是做了粗略的實現(xiàn)和研究,并沒有深入下去。這篇手記的目的不在于詳細(xì)描述整個HOOK實現(xiàn)的過程,而僅僅對一些關(guān)鍵點作一些描述。

說到Inline hook,了解這個詞的同志們都應(yīng)該知道,無非是修改目標(biāo)函數(shù)處的指令,跳轉(zhuǎn)到自己的函數(shù),并且提供調(diào)用原函數(shù)的stub,即可完成整個流程。但是在 ARM下面情況和我們熟悉的x86有所不同。ARM芯片的運(yùn)行狀態(tài)分為arm和thumb兩種模式,分別有不同的指令集,arm指令為定長32 位,thumb指令為定長16位(thumb-2中進(jìn)行了擴(kuò)展,可以使用32位thumb指令)。同一段代碼中可以混用兩套指令集,通過一些帶有 interworking功能的跳轉(zhuǎn)或者load指令可以在兩種模式間切換。做ARM下的inline,首先遇到的就是指令模式的問題。另外,ARM架構(gòu) 下,CPU也具有分開的指令緩存和數(shù)據(jù)緩存,類似x86下的DTLB和ITLB。但是在實現(xiàn)過程中發(fā)現(xiàn),arm的緩存作用非常明顯,而且刷新機(jī)制不太確 定,因此自修改代碼需要經(jīng)常主動控制緩存的刷新。這一點,可以通過NDK的API cacheflush實現(xiàn)。

下面簡單說說一些主要問題:

  • 關(guān)于頁保護(hù)

    這一點對于熟悉Linux編程的同志們應(yīng)該不是問題,mprotect修改為PROT_READ | PROT_WRITE | PROT_EXEC即可。頁面大小可以通過包含ndk下面<asm/page.h>文件,里面定義的一系列宏用于獲得頁面大小和進(jìn)行對齊運(yùn) 算。

  • 關(guān)于模式轉(zhuǎn)換和跳轉(zhuǎn)

    Arm下主要的分支指令如BX,BLX等,都可以切換指令模式。詳見arm的用戶手冊。這里主要討論模式的選擇和切換時機(jī)。只有一個問題需要注 意,arm處理器執(zhí)行時,由于流水線的關(guān)系,會預(yù)取兩條指令,因此當(dāng)前指令取到的pc值,始終是之后第三條指令的地址。比如當(dāng)前指令地址是0×8000, 那么當(dāng)前pc的值,在thumb下面是0×8000 + 2 * 2, 在arm下面是0×8000 + 4 * 2。

    由于運(yùn)行時我沒有找到簡便的辦法能夠確切知道被hook的目標(biāo)函數(shù)指令集,所以這個問題留給了hook的使用者來決定。Hook之前應(yīng)通過逆向工具獲知所有目標(biāo)函數(shù)是arm還是thumb指令。

    如果要根據(jù)目標(biāo)函數(shù)指令集的不同而對hook函數(shù)采用不同的 編譯選項,顯然是一件麻煩的事情。而arm模式的指令由于單條指令包含的語義更多,是我們的首選。因此可以考慮主僅使用arm指令編譯hook函數(shù),而在跳轉(zhuǎn)的同時切換到arm模式。

    關(guān)于跳轉(zhuǎn)插入的指令方面,由于arm指令帶立即數(shù)的跳轉(zhuǎn)范圍只有4M,thumb的跳轉(zhuǎn)范圍只有256字節(jié)。所以首選ldr pc,xxxx指令來實現(xiàn)。對于arm指令的目標(biāo),這個指令很容易選擇。如下:

    ldr pc, [pc,#-4]

    32位跳轉(zhuǎn)絕對地址

    指令為單個32位數(shù)字:0xE51FF004。

    但是thumb模式下的16位ldr指令沒有辦法向pc中l(wèi)oad,選擇就很成問題。如果單純使用16位thumb指令的話,跳轉(zhuǎn)部分需要占用大量 字節(jié)數(shù),而因為arm下面編譯器常常使用pc的值作為基址來計算地址,被搬動過的指令中就極有可能存在這種指令。搬動過后的代碼中就必須對這部分指令進(jìn)行 修正,而又由于thumb所能夠支持的立即數(shù)很小,跳轉(zhuǎn)范圍也很小,這種修正往往非常麻煩,需要用幾條同等指令來替換一條指令。經(jīng)過考慮,還是決定放棄對 ARMv5的支持,直接使用ARMv6T2之后支持的thumb-2指令集。thumb-2支持32位thumb指令,也支持ldr以pc為目標(biāo)寄存器:

    ldr.w pc,[pc,#0]

    32位跳轉(zhuǎn)絕對地址

    指令為單個32位數(shù)字:0x00F0DFF8

    所有需要跳轉(zhuǎn)的地址,需要注意的是bit0的處理。如果bit0為1,跳轉(zhuǎn)后會切換到thumb指令模式,如果bit0為0,會切換至arm模式。 當(dāng)目標(biāo)為arm的時候,我們不需要特殊處理,編譯器會處理地址的計算。但是當(dāng)目標(biāo)為thumb的時候,從hook指令跳轉(zhuǎn)到hook函數(shù),以及調(diào)用原始函 數(shù)的時候,都需要注意地址bit0的處理。

  • 關(guān)于搬出來的原始指令

    按照win32下Detours庫的實現(xiàn)方式,被HOOK函數(shù)的前面幾條指令,會搬到一個trampoline中,并在這些指令后添加跳轉(zhuǎn)至原代碼 后續(xù)部分的指令。在搬動過程中,需要對被移動的指令進(jìn)行地址修正。在處理ARM平臺inline的過程中也需要作這樣的工作。但是實際上在處理的時候會發(fā) 現(xiàn),要做到這一點是非常困難的。ARM下常常會生成下面這種將pc作為地址參照的指令塊

    而由于arm平臺尋址范圍較小,編譯器通常選擇將數(shù)據(jù)和指令在內(nèi)存中的存放混雜在一起。thumb模式下,由于指令中能包含的立即數(shù)非常小,這種問 題會表現(xiàn)得異常突出,修正的時候也常常一條指令被拉長為數(shù)條。因此代碼修正會有非常大的工作量。這部分問題由于太消耗時間,我也僅僅是對arm下的 inline進(jìn)行研究性實現(xiàn),也就沒有管這個問題了。實際項目如果要用到hook,這個部分花費(fèi)的時間應(yīng)該比單純hook跳轉(zhuǎn)的實現(xiàn)要大得多。在不考慮并 發(fā)和效率的情況下,當(dāng)hook函數(shù)中要調(diào)用原函數(shù)時,可以考慮臨時恢復(fù)hook,并在調(diào)用完成后再次hook來解決。但是始終是相當(dāng)不優(yōu)雅的實現(xiàn)。

  • 關(guān)于線程處理

    修改hook目標(biāo)的指令時,和x86平臺下一樣,也需要注意有可能某些線程剛好執(zhí)行到被修改的指令中的問題。Win32下可以枚舉線程并修改 context到被搬遷的指令中去。但是Linux內(nèi)核系統(tǒng)下很難進(jìn)行線程的控制。估計可以采用接管信號處理,并向進(jìn)程內(nèi)所有線程調(diào)用 pthread_kill來實現(xiàn)。

轉(zhuǎn)載于:https://my.oschina.net/zhuzihasablog/blog/141872

總結(jié)

以上是生活随笔為你收集整理的Android inline hook手记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。