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

歡迎訪問 生活随笔!

生活随笔

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

Android

利用cache特性检测Android模拟器

發(fā)布時間:2025/3/15 Android 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用cache特性检测Android模拟器 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Author:leonnewton

0x00 序


目前對Android模擬器的檢測,主要是從特定的系統(tǒng)值來進(jìn)行區(qū)分的。例如,getDeviceId()、getLine1Number()這類函數(shù),還有android.os.Build類記錄的一系列值等等。但是偶然發(fā)現(xiàn)有位老外提出了用cache來區(qū)分模擬器和真機(jī)的idea,但是這位老外可能當(dāng)時比較懶,沒有具體的細(xì)節(jié),寫了個簡單的PoC后把Evaluation空著了,也沒有實驗,所以并不知道這個方法是否真的有效。因此,本文就把檢測的整個方法從原理到實現(xiàn)完整地展現(xiàn)出來。

0x01 ARM和x86


由于現(xiàn)在大部分的Android手機(jī)都是ARM架構(gòu)的,因此首先看一下ARM架構(gòu)和x86架構(gòu)在cache上的區(qū)別。兩者簡明的區(qū)別如下圖所示。

圖1:ARM和x86 cache區(qū)別

從圖中我們可以看出,在CPU和內(nèi)存之間,可以存在幾級cache,這里是L1和L2。cache的作用是加速,把指令緩存起來,就不用到低速的內(nèi)存中去取了。x86的cache都是連續(xù)的,但是ARM把L1 cache分成了平行的2塊,也就是I-Cache和D-Cache。這種將程序指令儲存和數(shù)據(jù)儲存分開的存儲器結(jié)構(gòu)叫哈佛架構(gòu)(Harvard architecture),而把程序指令存儲器和數(shù)據(jù)存儲器合并在一起的叫馮·諾伊曼結(jié)構(gòu)(von Neumann architecture)。

那么問題就來了,在指令和數(shù)據(jù)分開存儲的結(jié)構(gòu)中,這兩個cache不是同步的,因此一個特定地址的數(shù)據(jù)值在一個cache中更新了,但是在另一個cache就沒有更新。比如往數(shù)據(jù)cache中寫了數(shù)據(jù),指令cache中是不會寫入這個數(shù)據(jù)的。

而目前Android SDK提供的模擬器是基于QEMU的,QEMU是一個開源的模擬處理器的軟件,詳細(xì)可以看維基QEMU。所以模擬器是沒有分開的cache,模擬器只有一個整塊的cache。

于是就有了下面利用cache來檢測模擬器的思路。

0x02 思路


先看下思路的流程圖:

圖2:檢測思路

左邊的是真機(jī)上發(fā)生的情況,右邊是模擬器發(fā)生的情況,下面詳述一下操作和后果。

第一步:
執(zhí)行一個地址上的指令,假設(shè)就是$address這個地址。那么在真機(jī)上,指令會寫到I-Cache上,模擬器直接寫到cache上(因為模擬器就一個整塊的cache)。

第二步:
向$address寫入一個新指令。注意,這就有區(qū)別了,真機(jī)上的新指令會寫入D-Cache,而在模擬器直接寫到cache上。

第三步:
執(zhí)行$address的指令。那么此時,在真機(jī)上,會從I-Cache讀指令,也就是會執(zhí)行第一步的指令。模擬器直接從cache上讀指令,會執(zhí)行第二步的新指令。

當(dāng)然有可能發(fā)生在真機(jī)上的指令cache被洗掉了,但是實驗下來可能性還是比較小的。

0x03 show me the code


首先是設(shè)計一段代碼,會向一個特定的地址重新寫一個指令。然后由于要重新回到原來的地址再執(zhí)行一遍,因此可以用一個循環(huán)來實現(xiàn)。代碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 __asm __volatile ( 1 "stmfd sp!,{r4-r8,lr}\n" 2 "mov r6,#0\n"? 用來統(tǒng)計循環(huán)次數(shù),debug用的 3 "mov r7,#0\n"? 為r7賦初值 4 "mov r8,pc\n"? 4、7行用來獲得覆蓋$address“新指令”的地址 5 "mov r4,#0\n"? 為r4賦初值 6 "add r7,#1\n"? 用來覆蓋$address的“新指令” 7 "ldr r5,[r8]\n" 8 "code:\n" 9 "add r4,#1\n"? 這就是$address,是對r4加1 10 "mov r8,pc\n"? 10,11,12行的作用就是把第6行的指令寫到第9行 11 "sub r8,#12\n" 12 "str r5,[r8]\n" 13 "add r6,#1\n"?? r6用來計數(shù) 14 "cmp r4,#10\n"? 控制循環(huán)次數(shù) 15 "bge out\n" 16 "cmp r7,#10\n"?? 控制循環(huán)次數(shù) 17 "bge out\n" 18 "b code\n"????? 10次內(nèi)的循環(huán)調(diào)回去 19 "out:\n" 20 "mov r0,r4\n"??? 把r4的值作為返回值 21 "ldmfd sp!,{r4-r8,pc}\n" );

注釋已經(jīng)解釋得比較清晰了。也就是說,r4如果是10,那么就是執(zhí)行的是舊指令,是在真機(jī)上。如果r4等于1,那就是執(zhí)行了舊指令,是在模擬器上。

這里會遇到一個問題,就是我們是沒有寫代碼段的權(quán)限的,解決方案是mmap一段可寫的,把編譯好的機(jī)器碼復(fù)制進(jìn)去,再跳過去執(zhí)行。

1 2 3 4 5 6 7 8 9 10 11 12 13 void (*call)(void); #define PROT PROT_EXEC|PROT_WRITE|PROT_READ #define FLAGS MAP_ANONYMOUS| MAP_FIXED |MAP_SHARED char code[]= "\xF0\x41\x2D\xE9\x00\x60\xA0\xE3\x00\x70\xA0\xE3\x0F\x80\xA0\xE1" "\x00\x40\xA0\xE3\x01\x70\x87\xE2\x00\x50\x98\xE5\x01\x40\x84\xE2" "\x0F\x80\xA0\xE1\x0C\x80\x48\xE2\x00\x50\x88\xE5\x01\x60\x86\xE2" "\x0A\x00\x54\xE3\x02\x00\x00\xAA\x0A\x00\x57\xE3\x00\x00\x00\xAA" "\xF5\xFF\xFF\xEA\x04\x00\xA0\xE1\xF0\x81\xBD\xE8"; void *exec = mmap((void*)0x10000000,(size_t)4096 ,PROT ,FLAGS,-1,(off_t)0); memcpy(exec ,code,sizeof(code)+1); call=(void*)0x10000000; call();

申請了一段內(nèi)存,然后把匯編代碼的機(jī)器碼復(fù)制過去,接著跳到這塊內(nèi)存執(zhí)行。然后我們在后面取r4的值即可。

1 2 3 4 5 6 __asm __volatile ( "mov %0,r0\n" :"=r"(a) : : );

把r0,也就是r4的值放到a變量中。然后根據(jù)a的值返回不同的值就可以了。方便在應(yīng)用里判斷結(jié)果。

0x04 調(diào)試


調(diào)試的方法可以見鄭博士的文章安卓動態(tài)調(diào)試七種武器之孔雀翎 – Ida Pro。

整個調(diào)試的過程是,把上一節(jié)的代碼編譯成一個so共享庫,返回值是r0也就是r4的值(a變量),然后在應(yīng)用中根據(jù)返回值來判斷在什么環(huán)境中運行。

在進(jìn)入10000000前下斷點,然后F7進(jìn)去。

進(jìn)入以后,在mov r0,r4的時候下斷,F9執(zhí)行,這時候看到r4的值是10,這是在真機(jī)上測試的結(jié)果。可以看到原先add r4,#1 已經(jīng)變成了add r7,#1,但是實際執(zhí)行的還是add r4,#1。

在模擬器執(zhí)行的結(jié)果如下,可以看到r4的值是1,r7是10,所以執(zhí)行的是新指令,是在模擬器上:

0x05 測試


不知道在其他機(jī)器上是否可行,大家可以從https://github.com/leonnewton/cache_test下載進(jìn)行測試。


原文地址: http://drops.wooyun.org/tips/13245

總結(jié)

以上是生活随笔為你收集整理的利用cache特性检测Android模拟器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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