Android奇淫run-as命令,呼叫系統受UID限制的API

也許每個人出生的時候都以為這世界都是為他一個人而存在的,當他發現自己錯的時候,他便開始長大

少走了彎路,也就錯過了風景,無論如何,感謝經歷

本篇文章遇到排版混亂的地方,可點選文末閱讀原文或前往該地址:https://orangey.blog.csdn.net/article/details/126219844

更多關於Android安全的知識,可前往:https://blog。csdn。net/ananasorangey/category11955914。html

Android奇淫run-as命令,呼叫系統受UID限制的API

Android奇淫run-as命令,呼叫系統受UID限制的API

0x01 前言

run-as是Android系統中的一個小應用,可以輔助我們進行Android程式的開發。

功能

:run-as命令,以root身份執行命令,可以在未root的情況下檢視某個(debug模式的)應用的內部資訊(沙盒資料夾),前提條件是應用需為debug模式,即AndroidManifest。xml檔案中,android:debugable需要為true

在開發Android應用的時候,有的時候希望能獲取到儲存到手機盤應用私有目錄/data/data/com。mwr。dz下的資料來驗證開發的應用是否達到預期結果,或者獲取寫到私有目錄的log日誌檔案來進行debug工作。

在沒有root過的手機中,我們是無法直接使用adb shell來獲取到/data/data/com。mwr。dz下的資料,此時的使用者許可權是無法檢視很多資訊的,包括各個應用的沙盒,而run-as就向開發者提供了未root情況下訪問沙盒資訊的許可權,執行run-as + 包名,就可以直接以root許可權進入該應用的沙盒中檢視包括資料庫、xml、各種資訊檔案

為什麼命令可以檢視到Android應用私有資料?

run-as程式就是透過s許可權使得普通使用者可以在滿足條件(應用為debug模式時、操作目錄僅在應用沙盒下)時具備root許可權

除了提權以外,s許可權還可以用來降權,root使用者可更改檔案的擁有者,以及透過s許可權任意更改程式執行時的許可權,在Linux中所有程序都是由zygote程序fork出來的,如果不降權的話則所有程序都與父程序相同、具備了root許可權,這顯然是不安全的,因此zygote透過forkAndSpecializeCommon函式來進行降權處理,使得子程序具備可控的許可權

注:1。使用run-as後,是無法使用cp命令將應用資料複製到sd卡的,沒有許可權2。apk已簽名,並且設定了android:debuggable=“false”,將無法使用run-as命令3。無法使用run-as來直接獲取應用資料的話,需在自己的應用裡實現讀取應用資料到sd卡的功能,應用本身對自己的資料是有訪問許可權的4。/data/data/com。packagename/lib目錄不需要執行run-as就擁有訪問許可權,為apk間共享so提供了便利

Java中的除錯系統jdb,其實Android中的除錯系統是gdb,透過gdb和gdbserver來除錯App。具體來說,就是gdbserver透過ptrace附加到目標App程序去,然後gdb再透過socket或者pipe來連結gdbserver,並且向它發出命令來對App程序進行除錯。需要注意以下關鍵點:

每一個需要除錯的apk在打包的時候都會帶上一個gdbserver,因為手機上面不帶有gdbserver工具。gdbserver用來透過ptrace附加到要排程的App程序去。

ptrace的呼叫。一般來說,只有root許可權的程序可以呼叫。例如,如果想透過ptrace向目標程序注入一個so,需要在root過的手機上向su申請root許可權。但是,這不是絕對的。如果一個程序與目標程序的uid是相同的,那麼該程序就具有呼叫ptrace的許可權。gdbserver在除錯一個App之前,先透過ptrace_attach來附加到該App程序去,ptrace_attach在執行實際操作之後,會呼叫__ptrace_may_access來檢查呼叫程序的許可權,如果呼叫程序與目標程序具有相同的uid和gid,那麼許可權檢查透過。否則的話,就要求呼叫者程序具有執行ptrace的能力,這是透過另外一個函式ptrace_has_cap來檢查的。如果呼叫程序的uid是root,那麼ptrace_has_cap一定會檢查透過。當然,通過了上述兩個許可權檢查之後,還要接受核心安全模組的檢查,這就不是透過uid或者capability這一套機制來控制的了

如何讓gdbserver程序的uid與要除錯的App程序的uid一樣?

在沒有root過的手機上要想獲得root許可權是不可能的,因此只能選擇以目標程序相同的uid執行這個方法,可使用run-as工具

0x02 呼叫系統受uid限制的API

眾所周知,Android P 引入了針對非 SDK 介面(俗稱為隱藏API)的使用限制,這是繼 Android N上針對 NDK 中私有庫的連結限制之後的又一次重大調整。從今以後,不論是native層的NDK還是 Java層的SDK,我們只能使用Google提供的、公開的標準介面。

Android P 和 Android Q

:https://blog。csdn。net/github_34402358/article/details/94399343

用一個例子來詳細介紹Android中如何降權,這個例子是模擬一個系統的API,但是這個API只允許system使用者呼叫,程式碼如下:

在Android平臺執行Java程式需要依賴dalvik虛擬機器,因此需要將jar包轉換為對應的位元組碼檔案,操作步驟如下: 1、生成java jar包 同Pc執行

java -jar E:\test。jar

2、java jar包轉dex包,執行如下命令

dx ——dex ——output=test。dex E:\test。jar

3、連線Android手機,並將dex執行程式推入Android裝置路徑下:

adb push E:\test。dex /data/local/tmp/

開啟 IDEA 軟體,點選介面上的 Create New Project

出現以下介面,選中 Java,然後選擇 JDK,最後點選 Next,進行下一步(我的是 jdk1。8)

這裡是選擇生成專案時是否建立 Java 檔案,勾選上 Java Hello World 後會生成一個預設的 Hello world 檔案,點選 Next 進行下一步

給專案命名,預設是 untiled,自己填個名字吧,最後點選 finish

專案建立完成,建立 Java 檔案:點選 src——>new——>package,建立一個檔案包,並給包命名,與 Eclipse 的包類似

在包下面建立 Java 類檔案,點選包名——>New——>Java Class;給類檔案命名

進入手機shell

adb shell

進入sdcard目錄

cd sdcard

設定將要執行的jar包的classpass,不設定將無法執行

export CLASSPATH=/sdcard/hello。jar

執行jar包

app_process hello。jar com。lyh。hello。Hello aaa bbb ccc

建立一個IDA 來編寫Android 中的程式

0x03 案例1

run-as 命令可以獲取debug應用的私有資料,在除錯debug包的時候,可以使用該命令將使用者切換到系統分配給debug應用的使用者上,之後就可以訪問其私有資料

adb shell

whoami

Android奇淫run-as命令,呼叫系統受UID限制的API

run-as /data/data/com。mwr。dz

whoami

Android奇淫run-as命令,呼叫系統受UID限制的API

:在預設的shell環境下,使用者身份是root(假設當前是普通使用者,無法檢視應用的私有資料),執行 run-as 後,身份切換了 u0_a40, 這個使用者其實是測試應用的uid,也可以自由的訪問其私有目錄

Android中每一個應用都有一個uid,可以透過以下方式獲取:

PS命令:

ps | grep com。mwr。dz

每個Android應用程式的u0_axx都是不一樣的,同時uid是從10000開始,u0_a後面的數字加上10000所得的值,既是uid,這個和測試應用的輸出也非常的吻合,即u0_a40 和 10040。

:0_a後面的數字就是該應用的UID值減去FIRST_APPLICATION_UID所得的值,40 + FIRST_APPLICATION_UID = 10040

android2。3。3_r1中run-as。c中主要程式碼:

/* 沒有傳入包名則退出 */if (argc < 2) usage();/* 非‘shell’使用者或‘root’使用者則退出 */myuid = getuid();if (myuid != AID_SHELL && myuid != AID_ROOT) { panic(“only ‘shell’ or ‘root’ users can run this program\n”);}/* 根據傳入包名獲取應用資訊,失敗則退出 */pkgname = argv[1];if (get_package_info(pkgname, &info) < 0) { panic(“Package ‘%s’ is unknown\n”, pkgname); return 1;}/* reject system packages */if (info。uid < AID_APP) { panic(“Package ‘%s’ is not an application\n”, pkgname); return 1;}/* 如果設定了android:debuggable=“false”,則退出 */if (!info。isDebuggable) { panic(“Package ‘%s’ is not debuggable\n”, pkgname); return 1;}/* 檢查/data/data/com。packagename目錄是否可用 */if (check_data_path(info。dataDir, info。uid) < 0) { panic(“Package ‘%s’ has corrupt installation\n”, pkgname); return 1;}/* 切換當前工作目錄為/data/data/com。packagename,失敗則退出 */{ int ret; do { ret = chdir(info。dataDir); } while (ret < 0 && errno == EINTR); if (ret < 0) { panic(“Could not cd to package‘s data directory: %s\n”, strerror(errno)); return 1; }}/* Ensure that we change all real/effective/saved IDs at the * same time to avoid nasty surprises。 *//* 切換真實/有效/saved 使用者ID和組ID*/uid = gid = info。uid;if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) { panic(“Permission denied\n”); return 1;}/* 使用者在包名引數後指定了要執行的命令,就執行這個命令 */if (argc >= 3 ) { if (execvp(argv[2], argv+2) < 0) { panic(“exec failed for %s Error:%s\n”, argv[2], strerror(errno)); return -errno; }}/* 使用者沒有傳入要執行的命令,執行預設的shell命令子程序,此時可以執行exit命令退出 */execlp(“/system/bin/sh”, “sh”, NULL);panic(“exec failed\n”);return 1;

9 8 7 6 5 4 3 2 1 0- r w x r - x r - x

第9位表示檔案型別,可以為p、d、l、s、c、b和-:

p表示命名管道檔案

d表示目錄檔案

l表示符號連線檔案

s表示socket檔案

c表示字元裝置檔案

b表示塊裝置檔案

-表示普通檔案

第8~6位、5~3位、2~0位分別表示檔案所有者的許可權、同組使用者的許可權、其他使用者的許可權,其形式為rwx:

r表示可讀,可以讀出檔案的內容,對應的數字是4

w表示可寫,可以修改檔案的內容,對應的數字是2

x表示可執行,可執行這個程式,對應的數字是1

執行的話,分別表現在所有者或同組使用者許可權的可執行位上,例如:

1)-rwsr-xr-x 表示SUID和所有者許可權中可執行位被設定

2)-rwsr——r—— 表示SUID被設定,但所有者許可權中可執行位沒有被設定

3)-rwxr-sr-x 表示SGID和同組使用者許可權中可執行位被設定

4)-rw-r-sr—— 表示SGID被設定,但同組使用者許可權中可執行位沒有被設定

0x04 Android中setuid和setgid

Android系統程序Zygote啟動過程的原始碼分析:http://blog。csdn。net/luoshengyang/article/details/6768304

Android的APK都是執行在獨立的應用程式程序裡面的,Android中的所有的應用程序和SystemServer程序都是Zygote程序fork出來的。Zygote程序又是由init程序fork出來的,並且它被init程序fork出來後,沒有被setuid降權,也就是它的uid仍然是root。

應用程式程序被Zygote程序fork出來的時候,它的UID也應當是root。但是,它們的UID會被setuid修改為所載入的APK被分配的UID。

Android 2。2 以及之前版本的Zygote沒有對降權時setuid呼叫的返回值進行檢查。同樣,在耗盡目標程式uid的最大程序數之後,Zygote就無法降低它的許可權,然後就以root許可權啟動應用了

雖然Zygote程序相當於Android系統的根程序,但它也是由Linux系統的init程序啟動的。各個程序的先後順序為:

init程序 –-> Zygote程序 -–> SystemServer程序 -–>應用程序

所有Android應用程序都是zygote fork出來的,新fork出來的應用程序還保持著root許可權,這顯然是不被允許的,所以這個fork出來的子程序的許可權需要被降級,本文說的就是Android原始碼在什麼地方執行了許可權降級的操作

zygote降權處理

Zygote啟動流程:

1)初始化DDMS

2)註冊Zygote程序的Socket

3)載入class、resource、OpenGL、WebView等各種資源

4)fork出SystemServer程序

5)啟動SystemServer程序

6)呼叫runSelectLoop()一直監聽Socket資訊

7)收到建立應用程式Socket訊息,呼叫ZygoteConnection#runOnce()。在runOnce()中呼叫Zygote#forkAndSpecialize()建立應用程序

8)啟動應用程序

su工具原理

Android手機的root原理:一個普通的程序透過執行su,從而獲得一個具有root許可權的程序

su所做的事情其實很簡單,它再fork另外一個子程序來做真正的事情,也就是在執行su的時候後面所跟的那些引數。由於執行su的程序的uid是root,因此由它fork出來的子程序的uid也是root,於是子程序也可以達到跟root一樣的許可權操作穩健。不過,用來root手機的su還會配合另外一個稱為superuser的App來使用。su在fork子程序來做真正的事情之前,會先啟動superuser,詢問使用者是否允許fork一個uid是root的子程序,對root許可權進行控制,避免被惡意應用偷偷地使用

chmod修改setuid和setgid場景:run-as命令

在Android中也有類似的場景,例如run-as命令本生的uid是root,gid是shell,輸入 run-as 命令的使用者就會立馬升級到root使用者,root使用者可以進入到任何應用的data/data/目錄下面

chmod 6755 run-as

ll /system/bin/run-as

Android奇淫run-as命令,呼叫系統受UID限制的API

參考連結

https://blog。csdn。net/whklhhhh/article/details/81177455

https://blog。csdn。net/moonshine2016/article/details/53422082

https://daemon369。github。io/android/2013/09/03/use-run-as-get-android-private-data

https://www。codeboy。me/2019/09/10/android-run-as/

https://blog。csdn。net/qq_17250009/article/details/52061171

http://www。520monkey。com/archives/607

你以為你有很多路可以選擇,其實你只有一條路可以走