全能Android HOOK框架 JNI NATIVE JAVA ART DALVIK
OneHook
目前比較流行的幾個(gè)安卓HOOK方案,都有功能上的欠缺,有的不支持art模式,有的不支持jni層,有的不支持侵入HOOK。
所以O(shè)neHook誕生了!
這是一個(gè)同時(shí)支持ART和Dalvik兩種模式,理論上支持安卓4.0.3以上所有版本,同時(shí)支持JAVA和NATIVE層,使用全局注入技術(shù)的侵入式HOOK框架。
本框架不需要額外的安裝,可以靜態(tài)編譯到自己的APP中。
首先感謝看雪論壇中很多大牛提供的技術(shù)資料,沒有你們的分享,就沒有目前的這個(gè)OneHook的誕生。
感謝ele7enxxh提供的Android Inline Hook模塊
項(xiàng)目地址:https://github.com/ele7enxxh/Android-Inline-Hook
項(xiàng)目博客: http://ele7enxxh.com/Android-Arm-Inline-Hook.html
討論帖: http://bbs.pediy.com/thread-205741.htm
感謝asLody提供的Legend模塊
項(xiàng)目地址:https://github.com/aslody/legend
還感謝其他貢獻(xiàn)知識(shí)的同學(xué)們。
功能實(shí)現(xiàn):
0x01
首先考慮如何進(jìn)入系統(tǒng),如何在合適的位置和時(shí)間啟動(dòng)我的模塊。之前做WIN32的時(shí)候就有人說過,如果在WINDOWS啟動(dòng)前前運(yùn)行我的代碼,那么我無所不能。理論上,這句話是成立的。
所以在安卓系統(tǒng),我也需要找一個(gè)相對(duì)足夠早的位置來啟動(dòng)我的模塊,這個(gè)位置我沒有選擇init進(jìn)程,而是libc.so。
為什么?
因?yàn)榘沧康牡讓邮荓INUX構(gòu)建的,LINUX的底層就是C語(yǔ)言,而libc.so就是C語(yǔ)言的具體實(shí)現(xiàn)庫(kù),在這個(gè)位置上插入代碼顯然是合適的。而且在libc.so中去執(zhí)行我們的代碼,就不需要去考慮如何注入模塊,因?yàn)榘沧康乃羞M(jìn)程都會(huì)主動(dòng)加載libc.so。這是一個(gè)一舉兩得的方案,首先解決了啟動(dòng)代碼,其次解決了注入問題。
原理/過程:
so文件的初始化工作 是在init_array段中定義的
.init_array段的起始位置為:0X000683C0
初始化時(shí) 會(huì)按照順序去執(zhí)行初始化函數(shù)
_ZL14....
_ZL30....
_ZL29....
_ZL31....
那么如果把_ZL14__libc_preinitv的指針重定向到一個(gè)物理地址,使之dlopen我們自己的so,就可以實(shí)現(xiàn)我們想要的功能。
修改init_array的段的第一個(gè)指針 _ZL14__libc_preinitv ---> 0x55D24
指向位置的機(jī)器碼
機(jī)器碼對(duì)應(yīng)的C語(yǔ)言代碼
| 1 2 3 4 5 | int?_fun() { ??dlopen((const?char?*)"libckis.so",?0); ??return?__libc_preinit(); } |
這樣就可以順利的在每個(gè)進(jìn)程中加載libckis.so文件
關(guān)于如何修改libc.so文件使之加載自定義庫(kù)文件的方法 可以參考我的另外一篇文章
http://bbs.pediy.com/thread-213043.htm
需要注意的是
1 在不同安卓版本中,libc.so是不一樣的。
2 自定義的代碼位置不一定必須在.text段中,在很多情況下.text段沒有足夠的空間讓你去插入代碼,我的解決方案是把這段代碼放在.rodata段,如果放在rodata段,在運(yùn)算地址偏移時(shí),需要+0x10000
3 libc.so修改后需要妥善的push到手機(jī)的/system/lib目錄下,要注意權(quán)限問題,否則手機(jī)會(huì)死機(jī)
0x02
現(xiàn)在我們已經(jīng)進(jìn)入了安卓的Native層,在這里,我們可以做很多事情,比如HOOK fopen來控制底層文件的訪問 也可以HOOK __system_property_get來修改ro屬性 等等....
文檔可以參考?https://github.com/ele7enxxh/Android-Inline-Hook
附一個(gè)簡(jiǎn)單的例子
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #include?<stdio.h> #include?<stdint.h> #include?<dlfcn.h> #include?"inlineHook.h" int?my_init(void)?__attribute__((constructor)); typedef?int?(*t_system_property_get)(const?char?*name,?char?*value); t_system_property_get?__system_property_get=NULL; int?(*old__system_property_get)(const?char?*name,?char?*value)=NULL; int?new__system_property_get(const?char?*name,?char?*value) { if(strstr(name,"ro.serialno"))?return?strlen(strcpy(value,"AABBCC")); ????else?return?old__system_property_get(name,value); } int?my_init(void) { void*?libc=dlopen("/system/lib/libc.so",0); __system_property_get=(t_system_property_get)dlsym(libc,"__system_property_get"); if(registerInlineHook((uint32_t)__system_property_get,(uint32_t)?new__system_property_get,(uint32_t?**)?&old__system_property_get)!=?ELE7EN_OK)?printf("error?find?__system_property_get?"); else?if?(inlineHook((uint32_t)?__system_property_get)?!=?ELE7EN_OK)?printf("error?hook?__system_property_get?"); return?0; } |
那么,我們現(xiàn)在已經(jīng)可以完整的實(shí)現(xiàn)Native/JNI層的HOOK了。
在adb shell下 輸入getprop ro.serialno 會(huì)得到返回值 AABBCC 如圖:
并且我們已經(jīng)完成了了進(jìn)入JAVA層的先決條件。
0x03
進(jìn)入JAVA世界
論壇中如何從native層進(jìn)入java層有很多種方案嗎,在這里 我使用了ADBI的解決方案,在libc.so庫(kù)中的epoll_wait函數(shù)掛鉤,進(jìn)而跳轉(zhuǎn)到APP進(jìn)程中去,然后使用DexClassLoader加載自己的dex文件,達(dá)到JAVA HOOK的目的
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | bool?IsInToJava=false; int?(*oldepoll_wait)(int?epfd,?int?events,?int?maxevents,?int?timeout)=NULL; int?newepoll_wait(int?epfd,?int?events,?int?maxevents,?int?timeout) { if(!IsInToJava) { IsInToJava=true; invoke_dex_method("/data/local/tmp/xxx.dex",path,"com.xxx.xxx.inject","main",AppName); return?oldepoll_wait(epfd,events,maxevents,timeout); } } void?my_init(void) { void*?libc?=?dlopen("/system/lib/libc.so",?0); void?*hookepoll_wait?=?dlsym(libc,?"epoll_wait"); if?(registerInlineHook((uint32_t)hookepoll_wait,?(uint32_t)newepoll_wait,?(uint32_t?**)&oldepoll_wait)?!=?ELE7EN_OK)?printf("error?find?epoll_wait\n"); else?if?(inlineHook((uint32_t)hookepoll_wait)?!=?ELE7EN_OK)?printf("error?hook?epoll_wait?"); } |
在APP進(jìn)程調(diào)用epoll_wait函數(shù)時(shí) 就會(huì)加載指定的dex文件,并且執(zhí)行HOOK的初始化方法。
注意epoll_wait可能會(huì)被多次調(diào)用,我們只需要執(zhí)行一次即可。
0x04
JAVA層HOOK
JAVA層的HOOK我使用了Legend的方案,因?yàn)橐呀?jīng)進(jìn)入了APP進(jìn)程內(nèi),就和熱補(bǔ)丁的流程是一樣的。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public?class?inject{ ????public?static?final?String?TAG?=?"CKIS_INJECT";???? ????public?static?Context?context;???? ????public?static?void?main(String?packageName) ????{ ????????Log.e(TAG,?"Dex?Inject?in?by:?"+packageName);???????? ????????HookManager.getDefault().applyHooks(inject.class);???????? ????????Log.e(TAG,?"DEX?called?success:"+packageName);???? ????} ????@Hook("android.telephony.TelephonyManager::getDeviceId") ????public?static?String?TelephonyManager_getDeviceId(TelephonyManager?thiz)? ????{ ????????return?"123456789012345";???? ????} } |
在這里 我們HOOK了TelephonyManager.getDeviceId方法,實(shí)現(xiàn)了系統(tǒng)的IMEI的修改。
在執(zhí)行IMEI獲取操作時(shí) 調(diào)用getDeviceID會(huì)獲得123456789012345
具體HOOK方案 也可以參考我另外一篇基于XPOSED框架的文章
http://bbs.pediy.com/thread-213042.htm
0x05
環(huán)境部署
本框架需要ROOT權(quán)限
1 首先讀取/system/lib/libs.so 并在本地解析elf文件格式 添加加載自定義庫(kù)的代碼 然后再回寫到/system/lib/libc.so目錄下
2 釋放DEXPOSED的運(yùn)行庫(kù) libdexposed.so libdexposed_l.so libdexposed_l51.so ?到\system\lib\或\vendor\lib目錄下
3 釋放libckis.so、libjava.so到/system/lib目錄下
4 釋放DEX文件到指定的目錄下 本例為 /data/local/tmp/xxx.dex
5 重啟生效
目前該框架的完成度已經(jīng)接近90%,支持ART、DALVIK,支持JAVA、JNI/NATIVE?
理論上此方案支持安卓4.0.3以上所有版本 但是Legend的HOOK模塊支持
- ?Dalvik & Android 4.2
- ?Dalvik & Android 4.3
- ?Art & Android 5.0
- ?Art & Android 5.0.1
- ?Art & Android 5.1
- ?Art & Android 6.0
- ?Art & Android 6.0.1
目前已測(cè)試的版本有
4.0.3
4.4.2
4.4.4
5.0
5.1
原文地址:?https://bbs.pediy.com/thread-217587.htm
總結(jié)
以上是生活随笔為你收集整理的全能Android HOOK框架 JNI NATIVE JAVA ART DALVIK的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【David Silver强化学习公开课
- 下一篇: Xposed注入实现分析及免重启定制