摘要:是否修改成功可以通過(guò)查看隨后我們需要確定目標(biāo)函數(shù)的地址,這個(gè)有兩種方法。如果目標(biāo)程序本身沒(méi)有被的話,那些都是存在的,因此可以使用和等方法來(lái)獲取目標(biāo)函數(shù)地址。
0x00 序
隨著移動(dòng)安全越來(lái)越火,各種調(diào)試工具也都層出不窮,但因?yàn)榄h(huán)境和需求的不同,并沒(méi)有工具是萬(wàn)能的。另外工具是死的,人是活的,如果能搞懂工具的原理再結(jié)合上自身的經(jīng)驗(yàn),你也可以創(chuàng)造出屬于自己的調(diào)試武器。因此,筆者將會(huì)在這一系列文章中分享一些自己經(jīng)常用或原創(chuàng)的調(diào)試工具以及手段,希望能對(duì)國(guó)內(nèi)移動(dòng)安全的研究起到一些催化劑的作用。
目錄如下:
安卓動(dòng)態(tài)調(diào)試七種武器之長(zhǎng)生劍 - Smali Instrumentation
安卓動(dòng)態(tài)調(diào)試七種武器之孔雀翎 – Ida Pro
安卓動(dòng)態(tài)調(diào)試七種武器之離別鉤 – Hooking (上)
安卓動(dòng)態(tài)調(diào)試七種武器之離別鉤 – Hooking (下)
安卓動(dòng)態(tài)調(diào)試七種武器之碧玉刀- Customized DVM
安卓動(dòng)態(tài)調(diào)試七種武器之多情環(huán)- Customized Kernel
安卓動(dòng)態(tài)調(diào)試七種武器之霸王槍 - Anti Anti-debugging
安卓動(dòng)態(tài)調(diào)試七種武器之拳頭 - Tricks & Summary
文章中所有提到的代碼和工具都可以在我的github下載到,地址是: https://github.com/zhengmin1989/TheSevenWeapons
0x01 利用函數(shù)掛鉤實(shí)現(xiàn)native層的hook我們?cè)陔x別鉤(上)中已經(jīng)可以做到動(dòng)態(tài)的加載自定義so文件并且運(yùn)行so文件中的函數(shù)了,但還不能做到hook目標(biāo)函數(shù),這里我們需要用到函數(shù)掛鉤的技術(shù)來(lái)做到這一點(diǎn)。函數(shù)掛鉤的基本原理是先用mprotect()將原代碼段改成可讀可寫(xiě)可執(zhí)行,然后修改原函數(shù)入口處的代碼,讓pc指針跳轉(zhuǎn)到動(dòng)態(tài)加載的so文件中的hook函數(shù)中,執(zhí)行完hook函數(shù)以后再讓pc指針跳轉(zhuǎn)回原本的函數(shù)中。
用來(lái)注入的程序hook5邏輯與之前的hook4相比并沒(méi)有太大變化,僅僅少了“調(diào)用 dlclose 卸載so文件”這一個(gè)步驟,因?yàn)槲覀兿胍獔?zhí)行的hook后的函數(shù)在so中,所以并不需要調(diào)用dlclose進(jìn)行卸載?;静襟E如下:
保存當(dāng)前寄存器的狀態(tài) -> 獲取目標(biāo)程序的mmap, dlopen, dlsym, dlclose 地址 -> 調(diào)用mmap分配一段內(nèi)存空間用來(lái)保存參數(shù)信息 –> 調(diào)用dlopen加載so文件 -> 調(diào)用dlsym找到目標(biāo)函數(shù)地址 -> 使用ptrace_call執(zhí)行目標(biāo)函數(shù) -> 恢復(fù)寄存器的狀態(tài)
hook5的主要代碼邏輯如下:
我們知道arm處理器支持兩種指令集,一種是arm指令集,另一種是thumb指令集。所以要hook的函數(shù)可能是被編譯成arm指令集的,也有可能是被編譯成thumb指令集的。Thumb指令集可以看作是arm指令壓縮形式的子集,它是為減小代碼量而提出,具有16bit的代碼密度。Thumb指令體系并不完整,只支持通用功能,必要時(shí)仍需要使用ARM指令,如進(jìn)入異常時(shí)。需要注意的一點(diǎn)是thumb指令的長(zhǎng)度是不固定的,但arm指令是固定的32位長(zhǎng)度。
為了讓大家更容易的理解hook的原理,我們先只考慮arm指令集,因?yàn)閍rm相比thumb要簡(jiǎn)單一點(diǎn),不需要考慮指令長(zhǎng)度的問(wèn)題。所以我們需要將target和hook的so編譯成arm指令集的形式。怎么做呢?很簡(jiǎn)單,只要在Android.mk中的文件名后面加上”.arm”即可 (真正的文件不用加)。
確定了指令集以后,我們來(lái)看實(shí)現(xiàn)掛鉤最重要的邏輯,這個(gè)邏輯是在注入后的so里實(shí)現(xiàn)的。首先我們需要一個(gè)結(jié)構(gòu)體保存匯編代碼和hook地址:
我們接著來(lái)看注入的邏輯,最重要的函數(shù)為hook_direct(),他有三個(gè)參數(shù),一個(gè)參數(shù)是我們最開(kāi)始定義的用來(lái)保存匯編代碼和hook地址的結(jié)構(gòu)體,第二個(gè)是我們要hook的原函數(shù)的地址,第三個(gè)是我們用來(lái)執(zhí)行hook的函數(shù)。函數(shù)的源碼如下:
雖然android有ASLR,但并沒(méi)有PIE,所以program image是固定在0x8000這個(gè)地址的,因此我們用mprotect()函數(shù)將整個(gè)target代碼段變成RWX,這樣我們就能修改函數(shù)入口處的代碼了。是否修改成功可以通過(guò)cat /proc/[pid]/maps查看:
隨后我們需要確定目標(biāo)函數(shù)的地址,這個(gè)有兩種方法。如果目標(biāo)程序本身沒(méi)有被strip的話,那些symbol都是存在的,因此可以使用dlopen()和dlsym()等方法來(lái)獲取目標(biāo)函數(shù)地址。但很多情況,目標(biāo)程序都會(huì)被strip,特別是可以直接運(yùn)行的二進(jìn)制文件默認(rèn)都會(huì)被直接strip。比如target中的sevenWeapons()這個(gè)函數(shù)名會(huì)在編譯的時(shí)候去掉,所以我們使用dlsym()的話是無(wú)法找到這個(gè)函數(shù)的。這時(shí)候我們就需要使用ida或者objdump來(lái)定位一下目標(biāo)函數(shù)的地址。比如我們用objdump找一下target程序里面sevenWeapons(int number)這個(gè)函數(shù)的地址:
雖然target這個(gè)binary被strip了,但還是可以找到sevenWeapons()這個(gè)函數(shù)的起始地址是在0x84f4。因?yàn)椤眒ov r2, r0”就是加載number這個(gè)參數(shù)的指令,隨后調(diào)用了
hook_direct(&eph,hookaddr,my_sevenWeapons);
接下來(lái)我們看如何修改函數(shù)入口(modify function entry),首先我們保存一下原函數(shù)的地址和那個(gè)函數(shù)的前三條指令。隨后我們把目標(biāo)函數(shù)的第一條指令修改為 LDR pc, [pc, #0],這條指令的意思是跳轉(zhuǎn)到PC指針?biāo)傅牡刂罚捎趐c寄存器讀出的值實(shí)際上是當(dāng)前指令地址加8,所以我們把后面兩處指令都保存為hook函數(shù)的地址,這樣的話,我們就能控制PC跳轉(zhuǎn)到hook函數(shù)的地址了。
最后我們?cè)僬{(diào)用hook_cacheflush()這個(gè)函數(shù)來(lái)刷新一下指令的緩存。因?yàn)殡m然前面的操作修改了內(nèi)存中的指令,但有可能被修改的指令已經(jīng)被緩存起來(lái)了,再執(zhí)行的話,CPU可能會(huì)優(yōu)先執(zhí)行緩存中的指令,使得修改的指令得不到執(zhí)行。所以我們需要使用一個(gè)隱藏的系統(tǒng)調(diào)用來(lái)刷新一下緩存。hook_cacheflush()代碼如下:
刷新完緩存后,再執(zhí)行到原函數(shù)的時(shí)候,pc指針就會(huì)跳轉(zhuǎn)到我們自定義的hook函數(shù)中了,hook函數(shù)里的代碼如下:
首先在hook函數(shù)中,我們可以獲得原函數(shù)的參數(shù),并且我們可以對(duì)原函數(shù)的參數(shù)進(jìn)行修改,比如說(shuō)將數(shù)字乘2。隨后我們使用hook_precall(&eph);將原本函數(shù)的內(nèi)容進(jìn)行還原。hook_precall()內(nèi)容如下:
在hook_precall()中,我們先對(duì)原本的三條指令進(jìn)行還原,然后使用hook_cacheflush()對(duì)內(nèi)存進(jìn)行刷新。經(jīng)過(guò)處理之后,我們就可以執(zhí)行原來(lái)的函數(shù)orig_sevenWeapons(number)了。執(zhí)行完后,如果我們還想再次hook這個(gè)函數(shù),就需要調(diào)用hook_postcall(&eph)將原本的三條指令再進(jìn)行一次修改。
下面我們來(lái)使用hook5和libinject2.so來(lái)注入一下target這個(gè)程序:
可以看到經(jīng)過(guò)注入后,我們成功的獲取了參數(shù)number的值,并且將”Hello,LiBieGou!”后面的數(shù)字變成了原來(lái)的兩倍。
0x02 使用adbi實(shí)現(xiàn)JNI層的hook我們?cè)谏弦还?jié)中介紹了如何hook native層的函數(shù)。下面我們?cè)賮?lái)講講如何利用adbi來(lái)hook JNI層的函數(shù)。Adbi是一個(gè)android平臺(tái)上的一個(gè)注入框架,本身是開(kāi)源的。Hook的原理和我們之前介紹的技術(shù)是一樣的,這個(gè)框架支持arm和thumb指令集,也支持通過(guò)字符串定位symbol函數(shù)的地址。
首先我們需要一個(gè)例子用來(lái)講解,所以我寫(xiě)了程序叫test2。
enter image description here
點(diǎn)擊程序中的button后,程序會(huì)調(diào)用so中的Java_com_mzheng_libiegou_test2_MainActivity_stringFromJNI(JNIEnv* env,jobject thiz,jint a,jint b)函數(shù)用來(lái)計(jì)算a+b的結(jié)果。我們默認(rèn)傳的參數(shù)是a=1, b=1。接下來(lái)我就來(lái)教你如何利用adbi來(lái)hook這個(gè)JNI函數(shù)。
因?yàn)閍dbi是一個(gè)注入框架,我們下載好源碼后,只要對(duì)應(yīng)著源碼中給的example照貓畫(huà)虎即可。Hijack那個(gè)文件夾是保存的用來(lái)注入的程序,和我們之前講的hook5.c的原理是一樣的,所以不用做任何修改。我們只需要修改example中的代碼,也就是將要注入的so文件的源碼。
首先,我們?cè)?adbi-master/instruments/example這個(gè)文件夾下新建兩個(gè)文件”hookjni.c”和” hookjni_arm.c”。“hookjni_arm.c”其實(shí)只是一個(gè)殼,用來(lái)將hook函數(shù)的入口編譯成arm指令集的,內(nèi)容如下:
這個(gè)文件的目的僅僅是為了用arm指令集進(jìn)行編譯,可以看到Android.mk中在”hookjni_arm.c”后面多了個(gè)”.arm”:
下面我們來(lái)看”hookjni.c”:
這段代碼和我上一節(jié)講的代碼非常像,my_init()用來(lái)進(jìn)行hook操作,我們需要提供想要hook的so文件名和函數(shù)名,然后再提供thumb指令集和arm指令集的hook函數(shù)地址。
my_Java_com_mzheng_libiegou_test2_MainActivity_stringFromJNI()就是我們提供的hook函數(shù)了。我們?cè)谶@個(gè)hook函數(shù)中把a(bǔ)和b都改成了10。除此之外,我們還使用counter這個(gè)全局變量來(lái)控制hook的次數(shù),這里我們把counter設(shè)置為3,當(dāng)hook了3次以后,就不再進(jìn)行hook操作了。
編輯好代碼后,我們只需要在adbi的根目錄下執(zhí)行” build.sh”進(jìn)行編譯:
編譯好后,我們把hijack和libexample.so拷貝到/data/local/tmp目錄下。然后使用hijack進(jìn)行注入:
然后我們?cè)冱c(diǎn)擊button就可以看到我們已經(jīng)成功的修改了a和b的值為10了,最后顯示1+1=20。
通過(guò)cat adbi_example.log我們可以看到hook過(guò)程中打印的log:
可以看到adbi是通過(guò)thumb指令集進(jìn)行hook的,原因是test2程序是用thumb指令集進(jìn)行編譯的。其實(shí)hook thumb指令集和arm指令集差不多,在”/adbi-master/instruments/base”中可以找到hook thumb指令集的邏輯:
其實(shí)h->jumpt[20]這個(gè)字符數(shù)組保存的就是thumb指令集下控制pc指針跳轉(zhuǎn)到hook函數(shù)地址的代碼。Hook完之后的流程就和arm指令集的hook一樣了。
0x03 使用Cydia或Xposed實(shí)現(xiàn)JAVA層的hook關(guān)于Cydia和Xposed的文章和例子已經(jīng)很多了,這里就不再重復(fù)的進(jìn)行介紹了。這里推薦一下瘦蛟舞和我寫(xiě)的文章,基本上就知道怎么使用這兩個(gè)框架了:
Android.Hook框架xposed篇(Http流量監(jiān)控) http://drops.wooyun.org/papers/7488
Android.Hook框架Cydia篇(脫殼機(jī)制作) http://drops.wooyun.org/tips/8084
手把手教你當(dāng)微信運(yùn)動(dòng)第一名 – 利用Android Hook進(jìn)行微信運(yùn)動(dòng)作弊 http://drops.wooyun.org/tips/8416
個(gè)人感覺(jué)Xposed框架要做的更好一些,主要原因是Cydia的作者已經(jīng)很久沒(méi)有更新過(guò)Cydia框架了,不光有很多bug還不支持ART。但是有很多不錯(cuò)的調(diào)試軟件/插件是基于兩個(gè)框架制作的,所以有時(shí)候還是需要用到Cyida的。
接下來(lái)就推薦幾個(gè)很實(shí)用的基于Cydia和Xposed的插件:
ZjDroid: ZjDroid是基于Xposed Framewrok的動(dòng)態(tài)逆向分析模塊,逆向分析者可以通過(guò)ZjDroid完成以下工作: 1、DEX文件的內(nèi)存dump 2、基于Dalvik關(guān)鍵指針的內(nèi)存BackSmali,有效破解主流加固方案 3、敏感API的動(dòng)態(tài)監(jiān)控 4、指定內(nèi)存區(qū)域數(shù)據(jù)dump 5、獲取應(yīng)用加載DEX信息。 6、獲取指定DEX文件加載類信息。 7、dump Dalvik java堆信息。 8、在目標(biāo)進(jìn)程動(dòng)態(tài)運(yùn)行l(wèi)ua腳本。 https://github.com/halfkiss/ZjDroid
XPrivacy: XPrivacy是一款基于Xposed框架的模塊應(yīng)用,可以對(duì)所有應(yīng)用可能泄露隱私的權(quán)限進(jìn)行管理,對(duì)禁止可能會(huì)導(dǎo)致崩潰的應(yīng)用采取欺騙策略,提供偽造信息,比如說(shuō)可以偽造手機(jī)的IMEI號(hào)碼等。 https://github.com/M66B/XPrivacy
Introspy: Introspy是一款可以追蹤分析移動(dòng)應(yīng)用的黑盒測(cè)試工具并且可以發(fā)現(xiàn)安全問(wèn)題。這個(gè)工具支持很多密碼庫(kù)的hook,還支持自定義hook。 https://github.com/iSECPartners/Introspy-Android
0x04 Introspy實(shí)戰(zhàn)我們使用alictf上的evilapk400作為例子講解如何利用introspy來(lái)調(diào)試程序。Evilapk400使用了比較復(fù)雜的dex加殼技術(shù),如果不利用基于自定義dalvik的脫殼工具來(lái)進(jìn)行脫殼的話做起來(lái)會(huì)非常麻煩。但我們?nèi)绻麚Q一種思路,直接通過(guò)動(dòng)態(tài)調(diào)試的方法來(lái)獲取加密算法的字符串,key和IV等信息就可以直接獲取答案了。
首先我們安裝cyida.apk,Introspy-Android Config.apk到手機(jī)上,然后用eclipse打開(kāi)“Introspy-Android Core”的源碼增加一個(gè)自定義的hook函數(shù)。雖然Introspy默認(rèn)對(duì)密碼庫(kù)進(jìn)行了hook,但卻沒(méi)有對(duì)一些strings的函數(shù)進(jìn)行hook。所以我們手動(dòng)添加一個(gè)對(duì)String.equals()的hook:
然后我們編譯,生成并安裝Introspy-Android Core.apk到手機(jī)上。然后我們安裝上EvilApk400。然后打開(kāi)Introspy-Android Config勾選com.ali.encryption。
接著打開(kāi)evilapk400,然后隨便輸入點(diǎn)內(nèi)容并點(diǎn)擊登陸。
然后我們使用adb logcat就能看到Introspy輸出的信息了:
通過(guò)log,很容易就能看出來(lái)evilapk400使用了DES加密。通過(guò)log我們獲取了密文,Key以及IV,所以我們可以寫(xiě)一個(gè)python程序來(lái)計(jì)算出最后的答案:
本篇介紹了native層,JNI層以及JAVA層的hook,基本上可以滿足我們平時(shí)對(duì)于android上hook的需求了。 另外文章中所有提到的代碼和工具都可以在我的github下載到,地址是: https://github.com/zhengmin1989/TheSevenWeapons
0x06 參考資料Android平臺(tái)下hook框架adbi的研究(下)http://blog.csdn.net/roland_sun/article/details/36049307
ALICTF Writeups from Dr. Mario
作者:蒸米@阿里聚安全,更多技術(shù)文章,請(qǐng)?jiān)L問(wèn)阿里聚安全博客
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/11179.html
摘要:月日,第六屆大會(huì)在深圳召開(kāi)。這是這次大會(huì)的第二站活動(dòng),第一站已在上海成功舉辦。深圳站視頻及,請(qǐng)?jiān)诠娞?hào)后臺(tái)回復(fù),獲取分享鏈接。據(jù)介紹,目前支持多種開(kāi)發(fā)庫(kù),如內(nèi)置和等。該協(xié)議的推出,是為了統(tǒng)一標(biāo)準(zhǔn),提高效率。 本文為 PyChina 和「編程派」聯(lián)合首發(fā),作者為 EarlGrey?!妇幊膛伞故且粋€(gè)專注 Python 學(xué)習(xí)交流的微信公眾號(hào)。 9 月 25 日,第六屆 PyCon China...
閱讀 1476·2023-04-25 19:00
閱讀 4185·2021-11-17 17:00
閱讀 1786·2021-11-11 16:55
閱讀 1551·2021-10-14 09:43
閱讀 3158·2021-09-30 09:58
閱讀 881·2021-09-02 15:11
閱讀 2146·2019-08-30 12:56
閱讀 1424·2019-08-30 11:12