国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

這篇具有很好參考價(jià)值的文章主要介紹了[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。


也許每個(gè)人出生的時(shí)候都以為這世界都是為他一個(gè)人而存在的,當(dāng)他發(fā)現(xiàn)自己錯(cuò)的時(shí)候,他便開始長(zhǎng)大

少走了彎路,也就錯(cuò)過了風(fēng)景,無(wú)論如何,感謝經(jīng)歷


轉(zhuǎn)移發(fā)布平臺(tái)通知:將不再在CSDN博客發(fā)布新文章,敬請(qǐng)移步知識(shí)星球

感謝大家一直以來(lái)對(duì)我CSDN博客的關(guān)注和支持,但是我決定不再在這里發(fā)布新文章了。為了給大家提供更好的服務(wù)和更深入的交流,我開設(shè)了一個(gè)知識(shí)星球,內(nèi)部將會(huì)提供更深入、更實(shí)用的技術(shù)文章,這些文章將更有價(jià)值,并且能夠幫助你更好地解決實(shí)際問題。期待你加入我的知識(shí)星球,讓我們一起成長(zhǎng)和進(jìn)步


Android安全付費(fèi)專欄長(zhǎng)期更新,本篇最新內(nèi)容請(qǐng)前往:

  • [車聯(lián)網(wǎng)安全自學(xué)篇] Android安全之Root檢測(cè)與Root繞過(淺析)
  • 配合[車聯(lián)網(wǎng)安全自學(xué)篇] ATTACK安全之Android Root檢測(cè)文章,食用更佳

0x01 前言

Android 是基于 Linux 多用戶機(jī)制的訪問控制。應(yīng)用程序在默認(rèn)的情況下不可以執(zhí)行其他應(yīng)用程序,包括讀寫用戶的私有數(shù)據(jù)。一個(gè)應(yīng)用程序的進(jìn)程就是一個(gè)安全的沙盒(在受限的安全環(huán)境中運(yùn)行應(yīng)用程序,在沙盒中的所有改動(dòng)對(duì)操作系統(tǒng)不會(huì)造成任何危害)

每一個(gè)Android應(yīng)用程序都會(huì)在安裝時(shí)就分配一個(gè)獨(dú)有的Linux用戶ID,這就為它建立了一個(gè)沙盒,使其不能與其他應(yīng)用程序進(jìn)行接觸。這個(gè)用戶ID會(huì)在安裝時(shí)分配給它,并在該設(shè)備上一直保持同一個(gè)數(shù)值

所有的Android應(yīng)用程序必須用證書進(jìn)行簽名認(rèn)證,而這個(gè)證書的私鑰是由開發(fā)者保有的。該證書可以用以識(shí)別應(yīng)用程序的作者。簽名影響安全性的最重要的方式是通過決定誰(shuí)可以進(jìn)入基于簽名的permisssions,以及誰(shuí)可以share 用戶IDs。通過這樣的機(jī)制,在不考慮root用戶的情況下,每個(gè)應(yīng)用都是相互隔離的,實(shí)現(xiàn)了一定的安全

在Linux操作系統(tǒng)中,root的權(quán)限是最高的,也被稱為超級(jí)權(quán)限的擁有者。在系統(tǒng)中,每個(gè)文件、目錄和進(jìn)程,都?xì)w屬于某一個(gè)用戶,沒有用戶許可其它普通用戶是無(wú)法操作的,但對(duì)root除外

在滲透測(cè)試 Android 應(yīng)用程序時(shí)候,大多數(shù)技術(shù)都需要 root 權(quán)限才能安裝各種工具,從而危及應(yīng)用程序的安全性。就有了攻防雙方對(duì)抗的現(xiàn)象產(chǎn)生,Android 開發(fā)人員又是使用了哪些技術(shù)來(lái)檢測(cè)運(yùn)行應(yīng)用程序的設(shè)備是否已Root呢?接下來(lái)會(huì)介紹一些Android 開發(fā)人員在檢查設(shè)備是否已經(jīng)root的幾種常用方法和一些繞過技術(shù)

出于安全原因,多應(yīng)用程序不允許在已經(jīng)root的設(shè)備上運(yùn)行,因?yàn)槭謾C(jī)Root后給攻擊者(用戶)帶來(lái)了非常大的自主操作權(quán)利,讓攻擊者(用戶)可以刪除系統(tǒng)應(yīng)用、安全或刪除應(yīng)用程序、查看并修改程序的運(yùn)行信息,但與此同時(shí),也給惡意軟件打開方便之門,給設(shè)備信息安全帶來(lái)了極大的挑戰(zhàn)。目前許多APP在啟動(dòng)時(shí)會(huì)進(jìn)行Root環(huán)境監(jiān)測(cè),防止APP在已經(jīng)Root的手機(jī)環(huán)境中運(yùn)行,如果發(fā)現(xiàn)設(shè)備已被Root,會(huì)向用戶彈窗提示運(yùn)行環(huán)境存在安全風(fēng)險(xiǎn)不讓APP繼續(xù)運(yùn)行下一步操作或禁止安裝運(yùn)行(出現(xiàn)APK閃退現(xiàn)象)

上面說(shuō)的檢測(cè)到手機(jī)被Root,主要有兩種處置手段:

  • 第一種處置:發(fā)現(xiàn)即摧毀,顧名思義就是檢測(cè)到ROOT設(shè)備之后不允許應(yīng)用正常運(yùn)行
  • 第二種處置:允許應(yīng)用運(yùn)行,但是切換與后臺(tái)服務(wù)器的交互。

兩種Root處置手段進(jìn)行簡(jiǎn)單的比較:

  • 第一種處置:檢測(cè)到ROOT設(shè)備之后如何停止應(yīng)用的運(yùn)行?根據(jù)工信部的監(jiān)管要求還不能直接讓應(yīng)用直接退出,因此現(xiàn)在一般的做法就是通過彈窗、Toast等以文字描述提示用戶當(dāng)前手機(jī)被root了存在風(fēng)險(xiǎn),由用戶決定是否退出或者延時(shí)幾秒后退出。可以看出這種處置是將用戶體驗(yàn)放在了一個(gè)相對(duì)重要的位置,但是這同時(shí)也給攻擊者帶來(lái)了諸多便利。友好的文案提示方面攻擊者確認(rèn)是觸發(fā)了環(huán)境檢測(cè)機(jī)制,從而專心繞過。不立即停止應(yīng)用的運(yùn)行,留給攻擊者足夠的時(shí)間去進(jìn)行分析和注入,從而繞過應(yīng)用的Root檢測(cè)機(jī)制。
  • 第二種處置:對(duì)于攻擊者來(lái)說(shuō)無(wú)法直接定位到業(yè)務(wù)失敗的原因,可能需要通過抓包分析,甚至自己猜測(cè)來(lái)定位,在一定程度上提高了攻擊者的攻擊成本和難度。但是,這種處置也可能會(huì)誤殺一部分為了個(gè)性化而將手機(jī)Root的正常用戶,為了減少誤殺率,現(xiàn)在的應(yīng)用也會(huì)進(jìn)行一些特殊的處置

Root:獲取手機(jī)超級(jí)管理員權(quán)限,android系統(tǒng)是基于linux內(nèi)核,默認(rèn)情況下并不提供超級(jí)管理員權(quán)限,所有獲取su的權(quán)限就是所謂root

Root用戶的特權(quán)性:root可以超越任何用戶和用戶組來(lái)對(duì)文件或目錄進(jìn)行讀取、修改或刪除(在系統(tǒng)正常的許可范圍內(nèi));對(duì)可執(zhí)行程序的執(zhí)行、終止;對(duì)硬件設(shè)備的添加、創(chuàng)建和移除等;也可以對(duì)文件和目錄進(jìn)行屬主和權(quán)限進(jìn)行修改,以適合系統(tǒng)管理的需要(因?yàn)閞oot是系統(tǒng)中權(quán)限最高的特權(quán)用戶);root是超越任何用戶和用戶組的,基于用戶ID的權(quán)限機(jī)制的沙盒是隔離不了它的

除了檢測(cè)(test-keys(測(cè)試版)、release-keys(發(fā)布版))系統(tǒng)是否測(cè)試版、檢測(cè)Root工具的安裝路徑,包名(特有刷root工具的包名稱)是否帶有su、activity、busybox、supersu或superuser等關(guān)鍵詞外,還有如下檢測(cè)方法:

  • 檢查su命令是否存在
  • 檢查常用目錄是否存在su(或檢測(cè)是否存在s權(quán)限的文件)
  • 使用which命令查看是否存在su
  • 主動(dòng)申請(qǐng)root權(quán)限
  • 執(zhí)行busybox
  • 檢查Android屬性(讀取build.prop中關(guān)鍵屬性,如ro.build.tags和ro.build.type)
  • 檢查特定路徑是否有寫權(quán)限(在Android系統(tǒng)中,有些目錄是普通用戶不能訪問的,例如/data、/system、/etc 等)
  • 檢查市面主流的模擬器
  • 檢測(cè)frida、xposed等Hook框架的特征

目前看來(lái)絕大多數(shù)的應(yīng)用都是對(duì)上面幾個(gè)檢測(cè)方法組合使用,甚至有很多只會(huì)實(shí)現(xiàn)其中的一項(xiàng)或者兩項(xiàng)。另外,上面的方法也沒有囊括所有的可能,比如有些應(yīng)用還會(huì)檢測(cè)“Magisk”或者"Superuser"等是否存在來(lái)進(jìn)行Root檢測(cè)??偨Y(jié)來(lái)說(shuō),目前主流的Root檢測(cè)就是對(duì)Root之后的手機(jī)獨(dú)有的一些特征進(jìn)行驗(yàn)證,如特征文件是否存在、是否存在越權(quán)、關(guān)鍵屬性是否被修改等等


補(bǔ)充知識(shí)
1)標(biāo)準(zhǔn)文件權(quán)限

普通文件權(quán)限是通過十位進(jìn)行表示的,如下圖

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

第一位代表的“ 文件” 類型,其可能的值有:-(文件)、d(目錄)、b(塊設(shè)備)、l (link文件)、c (字符設(shè)備,如串口)、s(socket套接字)。

  • 第2~4位表示文件屬于的權(quán)限
  • 第5~7位表示文件屬組的權(quán)限
  • 第8~10位表示其他用戶和組具有的權(quán)限

linux系統(tǒng)內(nèi)有檔案有三種身份

u:擁有者(user,文件的屬主)
g:群組 (group,文件的屬主所在的組,屬組)
o:其他人(other,其它的用戶)
a:包括屬主、屬組、其它用戶(all,以上所有人)

2)rwx權(quán)限設(shè)置

文件或目錄每三位用rwx表示相應(yīng)的權(quán)限值,其中r值為4、w值為2、x值為1 ,可以使用chmod 對(duì)文件或目錄進(jìn)行權(quán)限更改。對(duì)于文檔常用的有下面權(quán)限:

  • r:讀權(quán)限,用戶可以讀取文檔的內(nèi)容,如用cat,more查看
  • w:寫權(quán)限,用戶可以編輯文檔
  • x:該目錄具有可以被系統(tǒng)執(zhí)行的權(quán)限

權(quán)限的設(shè)置有兩種表示方式:

權(quán)限值表示法,如下:
# chmod 777 file1

字母值表示法,如下:
# chmod a+x file1
命令 結(jié)果 含義
chmod a-x myfile rw- rw- rw- 收回所有用戶執(zhí)行權(quán)限
chmod og-w myfile rw- r-- r– 收回同組用戶和其它用戶的寫權(quán)限
chmod g+w myfile rw- rw- r– 賦予同組用戶寫權(quán)限
chmod u+x myfile rwx rw- r– 賦予文件屬主執(zhí)行權(quán)限
chmod go+x myfile rwx rwx r-x 賦予同組用戶和其它用戶執(zhí)行權(quán)限

3)umask

在/etc/profile文件有umask值的默認(rèn)設(shè)置,默認(rèn)值為022,該值對(duì)應(yīng)的是默認(rèn)文件和目錄創(chuàng)建后的權(quán)限值:

目錄的默認(rèn)權(quán)限是:777-umask
文件的默認(rèn)權(quán)限是:666-umask 

所以u(píng)mask為022的情況下,默認(rèn)創(chuàng)建的目錄的權(quán)限是755 ,默認(rèn)創(chuàng)建的文件權(quán)限為644

4)特殊權(quán)限

除了上面的提到的rwx權(quán)限外,除了讀寫執(zhí)行權(quán)限外,系統(tǒng)還有三個(gè)特殊權(quán)限 s s t 權(quán)限(冒險(xiǎn)位與粘滯位) 【強(qiáng)制位(s權(quán)限)和粘滯位(t權(quán)限)】,具體描述如下:

權(quán)限 對(duì)文件的影響 對(duì)目錄的影響
suid 以文件的所屬目錄身份執(zhí)行,而非執(zhí)行文件的用戶 無(wú)
sgid 以文件所屬組身份執(zhí)行 該目錄中創(chuàng)建的任意新文件的所屬組與該目錄的所屬組相同
sticky 無(wú) 對(duì)目錄擁有寫入權(quán)限的用戶僅可以刪除其擁有的文件,無(wú)法刪除其它用戶所擁有的文件

這三個(gè)特殊權(quán)限也可以用字母和數(shù)字表示,具體如下:

設(shè)置suid:    chmodu+stestchmod  u+s  testchmodu+stest
設(shè)置sgid:設(shè)置sgid:設(shè)置sgid: chmod  g+s  test
設(shè)置sticky:  $ chmod  o+t  test
suid:4
sgid:2
sticky:1

s即(SUID,Set UID)設(shè)置使文件在執(zhí)行階段具有文件所有者的權(quán)限,相當(dāng)于臨時(shí)擁有文件所有者的身份. 典型的文件是passwd. 如果一般用戶執(zhí)行該文件, 則在執(zhí)行過程中, 該文件可以獲得root權(quán)限, 從而可以更改用戶的密碼

在一些特殊情況下會(huì)用到特殊權(quán)限位,如passwd命令,如果沒有s權(quán)限,其他用戶會(huì)無(wú)法使用passwd命令修改自己的密碼

# ls -l /usr/bin/passwd
-rwsr-xr-x. 1 root root 27832 Jun 10  2014 /usr/bin/passwd

給一個(gè)增加了s s t 權(quán)限的示例:

# touch test
# ll test
-rw-r--r--. 1 root root   0 Aug  5 01:03 test
# chmod 7777 test
# ll test
-rwsrwsrwt. 1 root root   0 Aug  5 01:03 test
# su - usera

上面由于增加了t權(quán)限,所以普通用戶usera,可以通文件寫入和更改,無(wú)法刪除文件

  • 在設(shè)置s權(quán)限時(shí)文件屬主、屬組必須先設(shè)置相應(yīng)的x權(quán)限,否則s權(quán)限并不能正真生效(c h m o d命令不進(jìn)行必要的完整性檢查,即使不設(shè)置x權(quán)限就設(shè)置s權(quán)限,chmod也不會(huì)報(bào)錯(cuò),當(dāng)我們ls -l時(shí)看到rwS,大寫S說(shuō)明s權(quán)限未生效)
  • 需要注意的是特殊權(quán)限是把雙刃劍,很多木馬提供也會(huì)利用到s 權(quán)限位,所以經(jīng)常在查找主機(jī)木馬時(shí),我們會(huì)用find查找所有4777 和 6777文件;
  • 假如本來(lái)在該位上有x, 則這些特別標(biāo)志 (suid, sgid, sticky) 顯示為小寫字母 (s, s, t) ,否則,顯示為大寫字母 (S, S, T)
  • 還有一個(gè)大X權(quán)限,后面在ACL時(shí)也會(huì)提到
  • s或S(SUID,Set UID):可執(zhí)行的文件搭配這個(gè)權(quán)限,便能得到特權(quán),任意存取該文件的所有者能使用的全部系統(tǒng)資源。請(qǐng)注意具備SUID權(quán)限的文件,黑客經(jīng)常利用這種權(quán)限,以SUID配上root帳號(hào)擁有者,無(wú)聲無(wú)息地在系統(tǒng)中開扇后門,供日后進(jìn)出使用。
  • T或T(Sticky):/tmp和 /var/tmp目錄供所有用戶暫時(shí)存取文件,亦即每位用戶皆擁有完整的權(quán)限進(jìn)入該目錄,去瀏覽、刪除和移動(dòng)文件

備注:BusyBox是很多標(biāo)準(zhǔn) Linux 工具的一個(gè)單個(gè)可執(zhí)行實(shí)現(xiàn)。BusyBox包含了一些簡(jiǎn)單的工具,例如 cat 和 echo,還包含了一些更大、更復(fù)雜的工具,例如 grep、find、moun)

root方式分為兩種:

  • 不完全 root
  • 完全 root

目前獲取Android root 權(quán)限常用方法是通過各種系統(tǒng)漏洞,替換或添加SU程序到設(shè)備,獲取Root權(quán)限,而在獲取root權(quán)限以后,會(huì)裝一個(gè)程序用以提醒用戶是否給予程序最高權(quán)限,可以一定程度上防止惡意軟件,通常會(huì)使用Superuser或者 SuperSU ,這種方法通常叫做“不完全Root”。

而 “完全Root”是指,替換設(shè)備原有的ROM,以實(shí)現(xiàn)取消secure設(shè)置

如何繞過Root檢測(cè)機(jī)制呢?這里提供兩個(gè)思路,其一是對(duì)應(yīng)用下手,干預(yù)應(yīng)用的Root檢測(cè)行為;另外一個(gè)思路則是對(duì)系統(tǒng)下手,隱藏系統(tǒng)自身Root相關(guān)的特征。我們可以借助jadx等逆向工具對(duì)應(yīng)用源碼進(jìn)行分析,Hook相關(guān)的實(shí)現(xiàn)函數(shù)繞過;也可以獲取AOSP源碼,通過定制ROM來(lái)隱藏Root的特征

  • Hook

目前主流的Hook框架有frida和xposed,可以用frida的可見框架RMS進(jìn)行注入。相對(duì)來(lái)說(shuō),通過Hook的方式來(lái)繞過Root檢測(cè)機(jī)制操作比較簡(jiǎn)單、方便,但Hook本身會(huì)受到很多的約束。一方面,受限于應(yīng)用自身的加固手段,可能難以定位ROOT檢測(cè)的實(shí)現(xiàn)函數(shù);另一方面,Hook框架自身也會(huì)具備一些易于被檢測(cè)到的特征,可能會(huì)受到這些特征的約束而難以完成工作。

  • 定制ROM

定制ROM的手段有很多種,可以通過對(duì)官方包進(jìn)行解包、修改后重打包。我推薦的方式是獲取AOSP源碼,自己編譯后制作ROM包。這樣可以實(shí)現(xiàn)更高程度的定制化,與基于現(xiàn)有包修改的方式相比該方式的操作空間更大,但是同樣的它會(huì)帶來(lái)更好的編譯成本、修改難度也更大

  • 熱修復(fù)

熱修復(fù)實(shí)現(xiàn)的本質(zhì)就是將修復(fù)bug后的代碼生成的dex放置在該數(shù)組的頭部

基于設(shè)備的作弊檢測(cè):

  • 檢測(cè)危險(xiǎn)的APP包名
    • 主要檢測(cè)hook框架,模擬點(diǎn)擊工具,magisk,supersu等root工具
  • 測(cè)是否存在root權(quán)限
    • 一般通過是否存在bin、sbin目錄里的su文件,kingroot權(quán)限管理apk
  • 檢測(cè)是否有調(diào)試狀態(tài)
    • default.prop文件的ro.secure=1、ro.debuggable=1狀態(tài),/proc/self/status文件的TracerPid值
  • 檢測(cè)是否設(shè)備是否出廠ROM
    • 一般通過android.os.Build的各類參數(shù)值來(lái)判斷,如Build.fingerprint
  • 一些設(shè)備常規(guī)信息,比如電量狀態(tài),usb狀態(tài),屏幕亮度,地理位置,wifi或者sim卡信息,ip、mac等
    • 一般批量操作或者抹機(jī)操作的時(shí)候這些值更改難度和成本比較大,所以這些指標(biāo)能偽造會(huì)大大降低被風(fēng)控

基于行為的作弊檢測(cè):

  • Log日志搜集
    • android開發(fā)時(shí)有Log.i、Log.e等運(yùn)行日志,大部分APP用這個(gè)來(lái)調(diào)試或者檢測(cè)APP的運(yùn)行情況,并且release版本一般通過boolean值來(lái)開關(guān),如果能hook掉這個(gè)開關(guān)就容易檢測(cè)APP
  • Exception棧信息搜集
    • 大部分APP的日志會(huì)搜集Exception,如果棧里有hook框架的包路徑就會(huì)把自己給殺死,讓hook難以長(zhǎng)久執(zhí)行,怕APP變成一個(gè)微型服務(wù)器抓包工具
  • 統(tǒng)計(jì)sdk的信息,如talkingdata、umeng等
    • 一般阿里系的會(huì)用umeng來(lái)做統(tǒng)計(jì)工具,一般這些sdk都有自己的唯一編號(hào),有些app引用這個(gè)編號(hào)來(lái)做一個(gè)指標(biāo)去判斷app的安裝唯一性,有的會(huì)通過統(tǒng)計(jì)數(shù)據(jù)來(lái)判斷批量作弊行為,因?yàn)檫@些sdk會(huì)搜集一些設(shè)備指紋并且技術(shù)和破解還原難度比較大的
  • 異常上報(bào)sdk,比如buggly,友盟sdk等等
    • 異常上報(bào)sdk一般記錄運(yùn)行時(shí)所有的異常情況,并且會(huì)記錄設(shè)備指紋,通過這些也能檢測(cè)到作弊的一些設(shè)備

APP的反作弊策略和思路:

  • 設(shè)備指紋的手機(jī)
    • 如數(shù)美、易盾或一些大廠的app都會(huì)內(nèi)嵌搜集設(shè)備指紋的模塊,通過設(shè)備指紋來(lái)確定設(shè)備的唯一性,如imei、android_id、mac、其他設(shè)備信息結(jié)合起來(lái)就能變成一個(gè)唯一的標(biāo)志
  • 搜集IP、MAC地址、藍(lán)牙MAC、WIFI等網(wǎng)絡(luò)指紋
    • 大量的搜集后跟其他搜集的信息結(jié)合并且不斷地完善代理ip或黑ip、mac庫(kù),就能不斷地能識(shí)別作弊源頭
  • 地理位置、下載渠道、授權(quán)登錄
    • 地理位置和ip是否對(duì)應(yīng)、基站信息是否對(duì)應(yīng)、或者設(shè)備型號(hào)跟下載渠道對(duì)應(yīng)、一般小米手機(jī)的軟件大部分應(yīng)該小米商城下載的,比如微信授權(quán)登錄,QQ授權(quán)登錄等、如果模擬授權(quán)登錄需要破解其他內(nèi)嵌到APP的一些協(xié)議
  • 參數(shù)簽名、參數(shù)加密
    • 一般APP會(huì)把get或者post的參數(shù)通過某種算法去簽名,并且這個(gè)簽名難還原。比如抖音的x-gorgon,有的把post或者get參數(shù)直接加密,一般通過aes、rsa、des等
  • 私有網(wǎng)絡(luò)協(xié)議、protobuf等協(xié)議、私有網(wǎng)絡(luò)證書、反代理抓包
    • 目前流行protobuf協(xié)議替代json,還有一些私有TCP/Socket協(xié)議,這些協(xié)議不可直接讀,需要一個(gè)解析工具或者分析還原。私有網(wǎng)絡(luò)證書需要證書密鑰配合代理抓包工具才能抓包分析,這種其實(shí)難度在于找到證書密鑰和判斷是否用了私有證書,一般聊天APP的IM協(xié)議常用。還有反代理抓包,比如集成OkHttp框架等的時(shí)候用Proxy.NO_Proxy來(lái)防止抓包
  • dex代碼混淆,native層ollvm編譯、webview的js混淆
    • 對(duì)應(yīng)dex代碼混淆還原或者分析難度比較容易,并且各種反編譯軟件來(lái)分析難度不是那么大,主要難度在于rxjava等異步框架,接口實(shí)現(xiàn)類查找上。native層的話主要難度是還原基于ollvm的各種混淆的代碼,其他還原或者理解難度其實(shí)并不大,并且大部分APP把一些加解密和簽名等算法用native方式實(shí)現(xiàn)并用ollvm混淆,其他的native層的都是一些媒體或者網(wǎng)絡(luò)等庫(kù)。webview一般用在驗(yàn)證碼上,并且用js的java層接口一起使用,把滑動(dòng)或者圖片順序識(shí)別之類的路徑日志通過賈母方式網(wǎng)絡(luò)提交的,javascript代碼一般混淆的比較厲害,不過AST反混淆等方法或者下載后nginx本地搭建并chrome自行調(diào)試歸納后通過腳本也能還原,如極驗(yàn)、易盾等驗(yàn)證碼插件
  • APP加殼、安全sdk、私有安全插件
    • 加殼更多是為了過合規(guī),安卓里dex文件總能運(yùn)行內(nèi)存中dump出來(lái)的,除非操作系統(tǒng)從底層設(shè)計(jì)上更改了,所有hook或者fart等修改的ROM都能搞定。360,騰訊,梆梆等等
    • 安全sdk也可以紙老虎這么說(shuō),不過安全sdk一般跟機(jī)器學(xué)習(xí),大數(shù)據(jù)匹配等相關(guān),越來(lái)越有難度去應(yīng)付,不過一般在社交電商類的反虛擬登錄時(shí)用,這些SDK搜集指紋設(shè)備,并保存到自己的服務(wù)器,會(huì)識(shí)別代理IP,打碼平臺(tái)的卡號(hào),風(fēng)險(xiǎn)設(shè)備,不過把加解密算法還原后可以偽造設(shè)備和其他數(shù)據(jù),能繞過
    • 還有一些大APP有自己開發(fā)的安全相關(guān)的模塊,這些其實(shí)跟安全sdk類似,主要還是設(shè)備信息偽造和加解密算法破解后都能繞過。數(shù)美、易盾等

APP的反作弊工具和策略:

  • 逆向工具
    • java:dex2jar、jadx、jeb、android-killer等等
    • so文件:IDA、jeb、Gidra
    • js:其實(shí)nodejs加谷歌或者火狐就能搞定
    • 其他:unicorn、unidibug等基于qemu虛擬機(jī)的工具
  • 抓包工具
    • Charles、Fillder:這兩個(gè)其實(shí)差不多,用于http、websocket等應(yīng)用層抓包
    • WireShark:各種協(xié)議都能支持,需要更深入的網(wǎng)絡(luò)協(xié)議技術(shù)基礎(chǔ)
    • BurpSuite:可以開發(fā)一些插件,會(huì)開發(fā)就各種神操作把
  • hook框架
    • xposed:用戶比較多,尤其云控、群控、那些化妝品,教育類、保險(xiǎn)等銷售類的都在用,市場(chǎng)規(guī)模大
    • frida:一般開發(fā)者使用的多,快,無(wú)需重啟,會(huì)js就會(huì)玩吧
    • cydia:hook Native層的時(shí)候多一點(diǎn),老開發(fā)者用的多
    • inlinehook,xhook:這兩個(gè)類似,inlinehook多用于hook b跳轉(zhuǎn)的,xhook多用于系統(tǒng)函數(shù)
    • magisk:安卓8以上xposed或者其他一些證書安裝等工具都基于這個(gè),這個(gè)其實(shí)未來(lái)深入研究的東西
  • 模擬點(diǎn)擊
    • uiautomator:很多模擬點(diǎn)擊軟件基于這個(gè),跟xposed結(jié)合開發(fā)比較合適,理解安卓開發(fā)的入門比較簡(jiǎn)單
    • 還有按鍵精靈,節(jié)點(diǎn)精靈,觸摸精靈等等
  • 行業(yè)難度
    • ollvm混淆:逆向行業(yè)目前應(yīng)該最頭疼的就這個(gè)吧,主要原理時(shí)if-else改成while(true){switch() case:}了,但是逆向成本變高了,并且各種延申的東西越來(lái)越多,需要經(jīng)驗(yàn)和技術(shù)積累才能100%還原或破解
    • 機(jī)器學(xué)習(xí)風(fēng)控策略:這個(gè)沒有多年經(jīng)驗(yàn)或者沒有相當(dāng)長(zhǎng)的時(shí)間去摸索或者沒跟班一個(gè)APP的成長(zhǎng)的話很難對(duì)應(yīng),并且大部分都是通過養(yǎng)號(hào),養(yǎng)設(shè)備等方式去對(duì)應(yīng),還有的是破解協(xié)議,并且偽造大量的設(shè)備信息,通過IP代理池,卡商和打碼平臺(tái)等第三方服務(wù)來(lái)維持。不過隨著法律的完善和APP自身的風(fēng)控體系健全對(duì)應(yīng)成本越來(lái)越高,現(xiàn)在很難實(shí)現(xiàn)大批量賬號(hào)登錄注冊(cè)

0x02 繞過root檢測(cè)實(shí)驗(yàn)

1)檢查su命令是否存在

通常要獲取Root權(quán)限,是使用su命令來(lái)實(shí)現(xiàn)的,因此可以通過檢查這個(gè)命令是否存在,來(lái)判斷運(yùn)行環(huán)境是否Root

2)檢查Android屬性

檢查ro.debuggable、ro.secure 兩個(gè)屬性是否為true,為true的話APP所運(yùn)行環(huán)境很可能是Root環(huán)境

3)檢查特定路徑是否有寫權(quán)限

具體路徑包括:/system、/system/bin、/system/sbin、/system/xbin、/vendor/bin、/sys、/sbin、/etc、/proc、/dev

通過mount命令確認(rèn)對(duì)應(yīng)分區(qū)的權(quán)限是否為"rw"

adb shell mount | grep -w /sysfs on /sys type sysfs (rw,seclabel,relatime)

下面從幾種被應(yīng)用程序廣泛使用的檢測(cè)技術(shù)開始說(shuō)起,如果設(shè)備已經(jīng)root,會(huì)增加一些新的文件,所以可以通過檢測(cè)這些文件是否存在來(lái)判斷,還有一些開發(fā)者通過檢查能否執(zhí)行只有root權(quán)限下才能運(yùn)行的命令來(lái)判斷,當(dāng)然還有一些其他的手段

  1. 之前幾年最流行(現(xiàn)在已停止維護(hù)許久了)的root工具是Superuser.apk,是一個(gè)被廣泛使用的用來(lái)root安卓設(shè)備的軟件,所以可以檢查這個(gè)app是否存在,但在檢測(cè)之前,我們先解決安裝包錯(cuò)的情況

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

解決方案

SuperSU 包含一個(gè) su 可執(zhí)行文件和一個(gè) Superuser.apk,只需要把 SuperSU 提供的 su 可執(zhí)行文件替換系統(tǒng)的 su 文件,并且給予權(quán)限 -rwsr-sr-x (6755) 即可。

一般在實(shí)際設(shè)備上有兩種方式替換文件:

手動(dòng)將 SuperSU 的 su 文件替換系統(tǒng)文件,需要 Root 權(quán)限;
通過 Recovery 模式直接將 su 文件已補(bǔ)丁包的形式刷入。
對(duì)于模擬器來(lái)說(shuō),它沒有 Recovery 模式,
是直接使用 img 鏡像啟動(dòng)的,所以只能使用第一種方法

官網(wǎng)下載:https://supersuroot.org/download/,選擇 Recovery V2.82 Flashable.zip 進(jìn)行下載,里面包含各個(gè)架構(gòu)所需的 su 文件,以及 Superuser.apk 安裝包

  • 查看模擬器的 su 命令所在的路徑
adb shell
which su
  • 打開一個(gè)cmd窗口,執(zhí)行如下命令adb remount 是為了將 /system 掛載為可寫,然后我們將su進(jìn)行替換
adb root
adb remount
adb push su /system/bin/su

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

備注:對(duì)于 Android 5.0 版本及之上的設(shè)備來(lái)說(shuō),需要使用 su.pie 文件,它是使用 -fPIE 標(biāo)記編譯的位置無(wú)關(guān)的可執(zhí)行文件,具有地址空間隨機(jī)化特性

  • 再次打開一個(gè)cmd窗口執(zhí)行如下命令
adb shell
chmod 6755 /system/bin/su
ls -al /system/bin/su
su --install
su --daemon&
setenforce 0

上面命令解釋如下:

  • 設(shè)置權(quán)限,使 SuperSU 提供的 su 可執(zhí)行文件能夠被所有應(yīng)用執(zhí)行;
  • 初始化安裝 su;
  • 設(shè)置 su 守護(hù)進(jìn)程;
  • 關(guān)閉 SELinux 安全策略,解除 Root 權(quán)限的限制

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)
[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)
[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)
[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)
[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

點(diǎn)擊重啟按鈕可能會(huì)卡住,直接關(guān)閉模擬器重啟即可,再次打開不會(huì)再提示su被占用的情況

adb shell
ls -l /system/app/ | grep 'Super'

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

SuperSU 工作原理:

  • daemonsu 為 su 啟動(dòng)的守護(hù)進(jìn)程
  • 現(xiàn)在第三方應(yīng)用開始調(diào)用 su 命令,請(qǐng)求申請(qǐng) Root 權(quán)限
  • su 是一個(gè)可執(zhí)行文件,內(nèi)部與 daemonsu 進(jìn)行通信,發(fā)送執(zhí)行命令請(qǐng)求
  • daemonsu 創(chuàng)建 sush 子進(jìn)程,sush 進(jìn)程使用 am(Activity Manager)命令啟動(dòng) Superuser 應(yīng)用,請(qǐng)求授權(quán),出現(xiàn)用戶授權(quán)界面
  • 授權(quán)通過,Superuser 應(yīng)用通過 socket 返回給 sush 用戶授權(quán)結(jié)果,通過授權(quán),則 sush 選擇是否執(zhí)行請(qǐng)求的命令

SuperSU 工作原理時(shí)序圖如下:

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

SuperSu,通過recovery將其文件刷入系統(tǒng)即可使用。然而現(xiàn)在安卓會(huì)對(duì)系統(tǒng)的完整性進(jìn)行驗(yàn)證,這一方法就未必行得通了。更何況很多廠商會(huì)對(duì)bootloader進(jìn)行封鎖,這意味著安卓各分區(qū)無(wú)法被私自修改,不能通過fastboot來(lái)刷入Su文件,也無(wú)法使用第三方的recovery,su的刷入也就無(wú)從談起,root權(quán)限成為了遙不可及的傳說(shuō)。

大家可以嘗試Magisk工具,跟SuperSu一樣的,但比SuperSu要香多了,而且SuperSu在2021年時(shí)已經(jīng)不在進(jìn)行維護(hù)了。

下載地址:https://github.com/topjohnwu/Magisk

Magisk 是一套用于定制 Android 的開源軟件,支持高于 Android 5.0 的設(shè)備。
一些突出特點(diǎn):

  • MagiskSU:為應(yīng)用程序提供 root 訪問權(quán)限
  • Magisk Modules:通過安裝模塊修改只讀分區(qū)
  • MagiskBoot:最完整的安卓啟動(dòng)鏡像解包和重新打包工具
  • Zygisk:在每個(gè) Android 應(yīng)用程序的進(jìn)程中運(yùn)行代碼
  1. 還可以搜索一些特殊的package,比如下圖所展示的
pm list packages | grep 'shell'

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

  1. 有一些應(yīng)用程序只能在root的設(shè)備上運(yùn)行,所以檢查他們是否存在也是一個(gè)不錯(cuò)的方法。比如眾所周知的Busybox:
busybox pwd

運(yùn)行“su”和“id”,然后查看uid來(lái)檢查

su
id

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

  1. 正式繞過root檢測(cè)

安裝了SuperSU的檢測(cè):
[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)
[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)
[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

沒安裝SuperSU的檢測(cè):
[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

  • 測(cè)試代碼如下
  1. CheckRoot.java代碼

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

package com.example.testpoc4;

import android.util.Log;
import java.io.File;

public class CheckRoot {
    // 定義TAG常量
    private  static String TAG = CheckRoot.class.getName();


    // 檢查判斷是否存在SuperSU.apk文件,存在的話就是root,并在日志里打印一行信息,若不是返回false
    public  static boolean checkSuperuserApk() {
        try{
            File file = new File("/system/app/SuperSU/SuperSU.apk");
            if (file.exists()){
                Log.w(TAG, "/system/app/SuperSU/SuperSU.apk exist");
                return  true;
            }
        }catch (Exception e){
        }
        return false;
    }

}

  1. MainActivity.java代碼

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

package com.example.testpoc4;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        boolean root = CheckRoot.checkSuperuserApk();
        ((TextView) findViewById(R.id.text)).setText("Device Root:"+root);
    }
}
  1. activity_main.xm代碼

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

為了繞過這個(gè)檢查,讓我們將應(yīng)用程序“Superuser.apk”重命名為“Superuser0.apk”,先將/system目錄從可讀變成可寫先使用remout,如下圖所示

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

將其名稱改變即可繞過,再次運(yùn)行檢測(cè)該軟件的程序時(shí)已不再提示為true

[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)

0x03 常用root檢測(cè)方法

常規(guī)檢測(cè)方法:檢測(cè)(test-keys(測(cè)試版)、release-keys(發(fā)布版))系統(tǒng)是否測(cè)試版、檢測(cè)提權(quán)為root的應(yīng)用包名、檢測(cè)常用或非常用su存在的目錄、檢測(cè)是否使用which 查找su、檢測(cè)Busybox是否存在、檢測(cè)/data目錄,是否有讀寫權(quán)限等,下面列出常用的一些檢測(cè)方法的介紹:

  • 查看系統(tǒng)是否測(cè)試版

可以查看發(fā)布的系統(tǒng)版本,是test-keys(測(cè)試版),還是release-keys(發(fā)布版)。

    public static boolean checkDeviceDebuggable() {
        String buildTags = android.os.Build.TAGS;
        if (buildTags != null && buildTags.contains("test-keys")) {
            Log.i(TAG, "buildTags=" + buildTags);
            return true;
        }
        return false;
    }

實(shí)際情況下,某些廠家的正式發(fā)布版本,也是test-keys,可能大家對(duì)這個(gè)標(biāo)識(shí)也不是特別注意吧。所以具體是否使用,要多考慮考慮。

  • 檢查是否存在Superuser.apk

Superuser.apk是一個(gè)被廣泛使用的用來(lái)root安卓設(shè)備的軟件,所以可以檢查這個(gè)app是否存在。

檢測(cè)方法如下:

    public  static boolean checkSuperuserApk() {
        try{
            File file = new File("/system/app/SuperSU/SuperSU.apk");
            if (file.exists()){
                Log.w(TAG, "/system/app/SuperSU/SuperSU.apk exist");
                return  true;
            }
        }catch (Exception e){
        }
        return false;
    }
  • 檢查su命令

su是Linux下切換用戶的命令,在使用時(shí)不帶參數(shù),就是切換到超級(jí)用戶。通常我們獲取root權(quán)限,就是使用su命令來(lái)實(shí)現(xiàn)的,所以可以檢查這個(gè)命令是否存在。

檢測(cè)在常用目錄下是否存在su:

    public static boolean checkRootPathSU() {
        File f = null;
        final String kSuSearchPaths[] = {"/system/bin/", "/system/xbin/", "/system/sbin/", "/sbin/", "/vendor/bin/"};
        try {
            for (int i = 0; i < kSuSearchPaths.length; i++) {
                f = new File(kSuSearchPaths[i] + "su");
                if (f != null && f.exists()) {
                    Log.i(TAG, "find su in : " + kSuSearchPaths[i]);
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
  • 執(zhí)行su,看能否獲取到root權(quán)限

執(zhí)行這個(gè)命令su。這樣,系統(tǒng)就會(huì)在PATH路徑中搜索su,如果找到,就會(huì)執(zhí)行,執(zhí)行成功后,就是獲取到真正的超級(jí)權(quán)限了。

    public static synchronized boolean checkGetRootAuth() {
        Process process = null;
        DataOutputStream os = null;
        try {
            Log.i(TAG, "to exec su");
            process = Runtime.getRuntime().exec("su");
            os = new DataOutputStream(process.getOutputStream());
            os.writeBytes("exit\n");
            os.flush();
            int exitValue = process.waitFor();
            Log.i(TAG, "exitValue=" + exitValue);
            if (exitValue == 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            Log.i(TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                process.destroy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
  • 訪問/data目錄,查看讀寫權(quán)限

在Android系統(tǒng)中,有些目錄是普通用戶不能訪問的,例如 /data、/system、/etc 等。
我們就已/data為例,來(lái)進(jìn)行讀寫訪問。本著謹(jǐn)慎的態(tài)度,我是先寫入一個(gè)文件,然后讀出,查看內(nèi)容是否匹配,若匹配,才認(rèn)為系統(tǒng)已經(jīng)root了。

    public static synchronized boolean checkAccessRootData() {
        try {
            Log.i(TAG, "to write /data");
            String fileContent = "test_ok";
            Boolean writeFlag = writeFile("/data/su_test", fileContent);
            if (writeFlag) {
                Log.i(TAG, "write ok");
            } else {
                Log.i(TAG, "write failed");
            }

            Log.i(TAG, "to read /data");
            String strRead = readFile("/data/su_test");
            Log.i(TAG, "strRead=" + strRead);
            if (fileContent.equals(strRead)) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            Log.i(TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        }
    }

    //寫文件
    public static Boolean writeFile(String fileName, String message) {
        try {
            FileOutputStream fout = new FileOutputStream(fileName);
            byte[] bytes = message.getBytes();
            fout.write(bytes);
            fout.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    //讀文件
    public static String readFile(String fileName) {
        File file = new File(fileName);
        try {
            FileInputStream fis = new FileInputStream(file);
            byte[] bytes = new byte[1024];
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len;
            while ((len = fis.read(bytes)) > 0) {
                bos.write(bytes, 0, len);
            }
            String result = new String(bos.toByteArray());
            Log.i(TAG, result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

將上述說(shuō)的檢測(cè)弄成代碼做為檢測(cè),此處就不演示了,大家自行操作:

CheckRoot.java代碼:

package com.example.testpoc4;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;

import android.util.Log;


public class CheckRoot {
    // 定義TAG常量
    private  static String TAG = CheckRoot.class.getName();

    public static boolean isDeviceRooted() {
        if (checkDeviceDebuggable()) {
            return true;
        }//check buildTags
        if (checkSuperuserApk()) {
            return true;
        }//Superuser.apk
        if (checkRootPathSU()) {
            return true;
        }//find su in some path
        if (checkRootWhichSU()) {
            return true;
        }//find su use 'which'
        if (checkBusybox()) {
            return true;
        }//find su use 'which'
        if (checkAccessRootData()) {
            return true;
        }//find su use 'which'
        if (checkGetRootAuth()) {
            return true;
        }//exec su

        return false;
    }


    // 檢查判斷是否存在SuperSU.apk文件,存在的話就是root
    public  static boolean checkSuperuserApk() {
        try{
            File file = new File("/system/app/SuperSU/SuperSU.apk");
            if (file.exists()){
                Log.w(TAG, "/system/app/SuperSU/SuperSU.apk exist");
                return  true;
            }
        }catch (Exception e){
        }
        return false;
    }


    public static boolean checkDeviceDebuggable() {
        String buildTags = android.os.Build.TAGS;
        if (buildTags != null && buildTags.contains("test-keys")) {
            Log.i(TAG, "buildTags=" + buildTags);
            return true;
        }
        return false;
    }

    public static boolean checkRootPathSU() {
        File f = null;
        final String kSuSearchPaths[] = {"/system/bin/", "/system/xbin/", "/system/sbin/", "/sbin/", "/vendor/bin/"};
        try {
            for (int i = 0; i < kSuSearchPaths.length; i++) {
                f = new File(kSuSearchPaths[i] + "su");
                if (f != null && f.exists()) {
                    Log.i(TAG, "find su in : " + kSuSearchPaths[i]);
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static boolean checkRootWhichSU() {
        String[] strCmd = new String[]{"/system/xbin/which", "su"};
        ArrayList<String> execResult = executeCommand(strCmd);
        if (execResult != null) {
            Log.i(TAG, "execResult=" + execResult.toString());
            return true;
        } else {
            Log.i(TAG, "execResult=null");
            return false;
        }
    }

    public static ArrayList<String> executeCommand(String[] shellCmd) {
        String line = null;
        ArrayList<String> fullResponse = new ArrayList<String>();
        Process localProcess = null;
        try {
            Log.i(TAG, "to shell exec which for find su :");
            localProcess = Runtime.getRuntime().exec(shellCmd);
        } catch (Exception e) {
            return null;
        }
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(localProcess.getOutputStream()));
        BufferedReader in = new BufferedReader(new InputStreamReader(localProcess.getInputStream()));
        try {
            while ((line = in.readLine()) != null) {
                Log.i(TAG, "–> Line received: " + line);
                fullResponse.add(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Log.i(TAG, "–> Full response was: " + fullResponse);
        return fullResponse;
    }

    public static synchronized boolean checkGetRootAuth() {
        Process process = null;
        DataOutputStream os = null;
        try {
            Log.i(TAG, "to exec su");
            process = Runtime.getRuntime().exec("su");
            os = new DataOutputStream(process.getOutputStream());
            os.writeBytes("exit\n");
            os.flush();
            int exitValue = process.waitFor();
            Log.i(TAG, "exitValue=" + exitValue);
            if (exitValue == 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            Log.i(TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                process.destroy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static synchronized boolean checkBusybox() {
        try {
            Log.i(TAG, "to exec busybox df");
            String[] strCmd = new String[]{"busybox", "df"};
            ArrayList<String> execResult = executeCommand(strCmd);
            if (execResult != null) {
                Log.i(TAG, "execResult=" + execResult.toString());
                return true;
            } else {
                Log.i(TAG, "execResult=null");
                return false;
            }
        } catch (Exception e) {
            Log.i(TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        }
    }

    public static synchronized boolean checkAccessRootData() {
        try {
            Log.i(TAG, "to write /data");
            String fileContent = "test_ok";
            Boolean writeFlag = writeFile("/data/su_test", fileContent);
            if (writeFlag) {
                Log.i(TAG, "write ok");
            } else {
                Log.i(TAG, "write failed");
            }

            Log.i(TAG, "to read /data");
            String strRead = readFile("/data/su_test");
            Log.i(TAG, "strRead=" + strRead);
            if (fileContent.equals(strRead)) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            Log.i(TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        }
    }

    //寫文件
    public static Boolean writeFile(String fileName, String message) {
        try {
            FileOutputStream fout = new FileOutputStream(fileName);
            byte[] bytes = message.getBytes();
            fout.write(bytes);
            fout.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    //讀文件
    public static String readFile(String fileName) {
        File file = new File(fileName);
        try {
            FileInputStream fis = new FileInputStream(file);
            byte[] bytes = new byte[1024];
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len;
            while ((len = fis.read(bytes)) > 0) {
                bos.write(bytes, 0, len);
            }
            String result = new String(bos.toByteArray());
            Log.i(TAG, result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

MainActivity.java代碼

package com.example.testpoc4;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        boolean deviceRoot = CheckRoot.isDeviceRooted();
        ((TextView) findViewById(R.id.text)).setText("Device Root:" +deviceRoot);
    }
}

參考鏈接

https://blog.csdn.net/weixin_47883636/article/details/108687059

https://www.jianshu.com/p/8a9b84df5018

https://blog.chrxw.com/archives/2020/07/18/1301.html

https://bbs.pediy.com/thread-263203.htm

https://github.com/yunshuipiao/Potato/issues/53

https://juejin.cn/post/6844903733248131079

https://github.com/DeFuture/Superuser

https://blog.csdn.net/quanshui540/article/details/48242459

https://github.com/Labmem003/anti-counterfeit-android

https://github.com/t0thkr1s/allsafe


你以為你有很多路可以選擇,其實(shí)你只有一條路可以走文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-481620.html


到了這里,關(guān)于[免費(fèi)專欄] Android安全之Root檢測(cè)與Root繞過(淺析)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Android安全】小米8刷機(jī)、救磚、root教程

    【Android安全】小米8刷機(jī)、救磚、root教程

    線刷 :通過計(jì)算機(jī)上的刷機(jī)軟件把ROM 通過數(shù)據(jù)線傳輸 并安裝到手機(jī)內(nèi)存中。ROM包以tgz為后綴。 卡刷 :把所需要的ROM下載或者復(fù)制到 內(nèi)存/SD卡根目錄 中。 按照https://www.mi.com/service/support即可 刷機(jī)工具:http://bigota.d.miui.com/tools/MiFlash2018-5-28-0.zip BL解鎖工具:http://www.miui.com/u

    2024年02月05日
    瀏覽(58)
  • 【Android安全】手機(jī)Root、刷機(jī)、救磚常用命令

    【Android安全】手機(jī)Root、刷機(jī)、救磚常用命令

    手機(jī)進(jìn)入recovery模式 adb reboot recovery 手機(jī)進(jìn)入bootloader模式 adb reboot bootloader 手機(jī)解鎖 adb reboot bootloader fastboot oem unlock 之后通過音量加減鍵選中Yes,通過電源鍵確認(rèn) 刷入TWRP recovery adb reboot bootloader fastboot flash recovery twrp-3.2.3-1-dumpling-pie.img 而后操作手機(jī)(例如,通過音量加減號(hào))

    2024年02月09日
    瀏覽(33)
  • [全解] 刷機(jī), BL 鎖, Bootloader, Recovery, Magisk, Root, ADB, 線刷, 卡刷, 9008, 繞過 FRP

    這篇文章講解手機(jī)刷機(jī), Root 的教程, 以及過程中可能遇到的大多數(shù)問題. 你可能需要對(duì)電腦重裝系統(tǒng)有些了解, 知道分區(qū), 設(shè)備, 驅(qū)動(dòng)是什么東西, 并且能夠熟悉使用電腦, 以及在命令窗口中執(zhí)行命令 手機(jī)刷機(jī), 當(dāng)然也可以說(shuō)成重裝系統(tǒng). 一般我們使用電腦重裝系統(tǒng)的時(shí)候, 都是通

    2024年02月04日
    瀏覽(46)
  • selenium繞過檢測(cè),規(guī)避檢測(cè)

    我們?cè)谑褂肞ython Selenium進(jìn)行自動(dòng)化測(cè)試或爬蟲時(shí),有時(shí)會(huì)遇到被網(wǎng)站檢測(cè)到并阻止的情況。這些網(wǎng)站通常會(huì)使用各種技術(shù)手段來(lái)檢測(cè)和阻止自動(dòng)化腳本,例如檢測(cè)瀏覽器指紋、檢查頁(yè)面元素是否被自動(dòng)化程序操作、檢測(cè)用戶行為模式等。本文將介紹一些常見的技術(shù)手段,以及

    2024年04月12日
    瀏覽(18)
  • 海康威視監(jiān)控視頻,螢石云免費(fèi)版四路并發(fā)訪問限制繞過

    ??低暠O(jiān)控視頻,螢石云免費(fèi)版四路并發(fā)訪問限制繞過

    公司新裝了不少??低晹z像頭,通過NVR連接到了螢石云,由于螢石云免費(fèi)版限制了單個(gè)攝像頭的并發(fā)訪問數(shù)(每個(gè)攝像頭同時(shí)只允許4個(gè)用戶進(jìn)行查看實(shí)時(shí)視頻),但是又不想付費(fèi)購(gòu)買企業(yè)版,于是著手思考如何解決這個(gè)問題。 需求 需求很明確,每個(gè)攝像頭需要支持多用戶

    2023年04月08日
    瀏覽(132)
  • Webshell 及檢測(cè)繞過

    webshell 概念 web指的是在web服務(wù)器上,而shell是用腳本語(yǔ)言編寫的腳本程序,WebShell是一種用來(lái)進(jìn)行網(wǎng)站和服務(wù)器管理的腳本程序,webshell一般是被網(wǎng)站管理員用于網(wǎng)站管理、服務(wù)器管理等等一些用途,但是由于webshell的功能比較強(qiáng)大,可以上傳下載文件,查看數(shù)據(jù)庫(kù),甚至可以調(diào)

    2024年02月12日
    瀏覽(15)
  • so層檢測(cè)frida繞過

    如果是在so層里開一個(gè)線程檢測(cè)frida; 我們思路是可以frida加載那個(gè)so, 然后打印出檢測(cè)線程的偏移; 然后干掉這個(gè)線程,完成!

    2024年02月12日
    瀏覽(16)
  • 淺析美業(yè)皮膚檢測(cè)儀圖像算法

    淺析美業(yè)皮膚檢測(cè)儀圖像算法

    ????????做為美容院的入口設(shè)備,檢測(cè)儀有著至關(guān)重要的角色。它不僅要幫助咨詢師講解皮膚問題,還要智能地推薦解決方案和護(hù)理方案。小編從事美業(yè)儀器研發(fā)多年,每次看到新的算法和設(shè)備出現(xiàn),都會(huì)非常地高興,一方面是可以學(xué)習(xí)借鑒,讓自己少走彎路;另一方面也

    2024年02月10日
    瀏覽(128)
  • 簡(jiǎn)單繞過EAC反作弊檢測(cè)分析【1】

    Easy Anti Cheat,嗯,眾所周知! EAC 是一個(gè)內(nèi)核反作弊 “系統(tǒng)”,它可以檢測(cè)任何東西。 想要欺騙它,你必須先加載一個(gè)內(nèi)核驅(qū)動(dòng)程序,然后才能防止它。 以下是它的常用手段: 阻止與游戲進(jìn)程的所有交互 掃描所有進(jìn)程與模塊 掃描已知的可疑DLL模塊 掃描已知的可疑驅(qū)動(dòng)程序

    2024年02月05日
    瀏覽(19)
  • Selenium自動(dòng)化繞過Cloudflare檢測(cè)的方法

    Selenium自動(dòng)化繞過Cloudflare檢測(cè)的方法

    運(yùn)營(yíng)多賬號(hào)的“老手”們,應(yīng)該對(duì)Selenium工具并不陌生,它可以直接在瀏覽器中運(yùn)行,模擬真實(shí)的用戶操作環(huán)境。 但是Selenium也有難以繞過檢測(cè)、無(wú)法使用的平臺(tái)——Cloudflare 那么有什么方法能繞過Cloudflare的檢測(cè)呢,今天大白就給大家分享幾個(gè)妙招! 01Cloudflare的概述 Cloudfla

    2023年04月11日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包