Android 5.0 之前的版本,對(duì) @ interface 注解操作處理的并不好,效率完全不能和 jvm 相比,所以注重運(yùn)行流暢的框架基本都拋棄了 注解 的使用。而 ButterKnife 的注入依賴注解,其運(yùn)行效率必然不高。另外,在一些場景下,比如視圖注入的過程中,你并不能優(yōu)化 ButterKnife 的查找。比如一個(gè)我們需要找到一個(gè)父視圖中的數(shù)個(gè)子視圖,如果純手工寫,我們可以先找到父視圖,在從父視圖中查找子視圖。而 ButterKnife 卻要每次重新從根視圖去查找,效率也是有所下降的。想了解更多請關(guān)注扣丁學(xué)堂。
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),福鼎企業(yè)網(wǎng)站建設(shè),福鼎品牌網(wǎng)站建設(shè),網(wǎng)站定制,福鼎網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,福鼎網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競爭力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
1. 首先要明白 不要采用IMEI的方式。模擬器的IMEI可以修改的。而且平板是沒有IMEI的,可以檢測設(shè)備的MAC地址,模擬器的MAC地址是固定的幾種。
2.通過調(diào)用公開或者隱藏的系統(tǒng)API判斷并不靠譜,因?yàn)檎{(diào)用結(jié)果可以輕易被修改,比如直接修改Android的源代碼或者借助Xposed Framework進(jìn)行修改。
3.有基于模擬器特征和api返回值的檢測方法都可以通過修改安卓源碼的方式輕松繞過。模擬器與真機(jī)的本質(zhì)區(qū)別在于運(yùn)行載體。鑒于大多數(shù)的安卓模擬器基于qemu,qemu在執(zhí)行程序時(shí)實(shí)際上是將其翻譯成宿主機(jī)的指令,比如將安卓的arm指令翻譯成PC的x86指令。為了效率上的考慮,qemu在翻譯執(zhí)行arm指令時(shí)并沒有實(shí)時(shí)更新模擬的pc寄存器值,只會(huì)在一段代碼翻譯執(zhí)行完之后再更新,而真機(jī)中pc寄存器是一直在更新的。基于這一點(diǎn),可以設(shè)計(jì)一段CPU任務(wù)調(diào)度程序來檢測模擬器 。具體的你可以參鑒DexLab上的一篇文章。當(dāng)然,這個(gè)方法也是可以被繞過的,可以在理解qemu源碼的基礎(chǔ)上,修改qemu源碼,但很明顯這個(gè)門檻很高 。
Android下so注入是基于ptrace系統(tǒng)調(diào)用,因此要想學(xué)會(huì)android下的so注入,首先需要了解ptrace的用法。
ptrace用法可以參考博客:,也可以在ubuntu下輸入man ptrace命令,查看具體描述。
android中進(jìn)程系統(tǒng)調(diào)用劫持可參考博客:,這是一個(gè)android簡單的ptrace監(jiān)控遠(yuǎn)程進(jìn)程監(jiān)控調(diào)用的例子。
Android系統(tǒng)是基于Linux系統(tǒng),在linux系統(tǒng)中可以通過ptrace系統(tǒng)調(diào)用實(shí)現(xiàn)進(jìn)程注入。ptrace注入過程大致過程如下:
(1)基于shellcode加載
[1]編寫shellcode,shellcode是使用匯編語言寫一段匯編程序,該程序?qū)崿F(xiàn)so庫的加載、so庫函數(shù)查找以及執(zhí)行庫中的函數(shù)。
[2]通過遠(yuǎn)程進(jìn)程pid,ATTACH到遠(yuǎn)程進(jìn)程。
[3]獲取遠(yuǎn)程進(jìn)程寄存器值,并保存,以便注入完成后恢復(fù)進(jìn)程原有狀態(tài)。
[4]獲取遠(yuǎn)程進(jìn)程系統(tǒng)調(diào)用mmap、dlopen、dlsym調(diào)用地址。
[5]調(diào)用遠(yuǎn)程進(jìn)程mmap分配一段存儲(chǔ)空間,并在空間中寫入shellcode、so庫路徑以及函數(shù)調(diào)用參數(shù)。
[6]執(zhí)行遠(yuǎn)程進(jìn)程shellcode代碼。
[7]恢復(fù)遠(yuǎn)程進(jìn)程寄存器。
[8]detach遠(yuǎn)程進(jìn)程。
基于shellcode注入可看雪古河大哥寫的libInject,網(wǎng)址:
(2)直接加載
[1]通過遠(yuǎn)程進(jìn)程pid,ATTACH到遠(yuǎn)程進(jìn)程。
[2]獲取遠(yuǎn)程進(jìn)程寄存器值,并保存,以便注入完成后恢復(fù)進(jìn)程原有狀態(tài)。
[3]獲取遠(yuǎn)程進(jìn)程系統(tǒng)調(diào)用mmap、dlopen、dlsym調(diào)用地址。
[4]調(diào)用遠(yuǎn)程進(jìn)程mmap分配一段存儲(chǔ)空間,并在空間中寫入so庫路徑以及函數(shù)調(diào)用參數(shù)。
[5]執(zhí)行遠(yuǎn)程進(jìn)程dlopen,加載so庫。
[6]執(zhí)行遠(yuǎn)程進(jìn)程dlsym,獲取so庫中需要執(zhí)行的函數(shù)地址。
[7]執(zhí)行遠(yuǎn)程進(jìn)程中的函數(shù)。
[7]恢復(fù)遠(yuǎn)程進(jìn)程寄存器。
[8]DETACH遠(yuǎn)程進(jìn)程。
目前android so注入的版本基本上都是基于古河大哥的libInject修改而來。關(guān)于so注入的項(xiàng)目,還可以參考洗大師的一個(gè)開源項(xiàng)目,網(wǎng)址:。洗大師注入需要修改elf文件。
提供一個(gè)方便測試so注入成功與否的小測試庫,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include unstd.h
#include stdio.h
#include android/log.h
#define LOG_TAG "test"
__attribute__((constructor))
void
inject
()
{
__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,"Hello,I
am injected.");
}
說明:若函數(shù)被設(shè)定為constructor屬性,則該函數(shù)會(huì)在main()函數(shù)執(zhí)行之前被自動(dòng)的執(zhí)行。因此,so注入測試中,只需注入以上代碼編譯的so庫,無需調(diào)用注入so的相關(guān)函數(shù),即可測試是否注入到遠(yuǎn)程進(jìn)程。