1. 程式人生 > 其它 >修改Android10系統原始碼關閉selinux

修改Android10系統原始碼關閉selinux

技術標籤:Android系統核心ubuntuandroid作業系統app安全

一、seandroid簡介

SEAndroid是Google在Android4.4上正式推出的一套以SELinux為核心的系統安全機制。在Android原始碼中,系統預設的seandroid配置存放如下路徑:

/home/qiang/lineageOs/system/sepolicy

目錄中存放了比如adbd、system_server、系統app、第三方app等te配置檔案。

由於Android系統引進了seandroid策略。強化了app對資源的訪問限制。安全性大大提高。比如舉一個獲取wifi mac的例子為例說明:

在android app中很多app通過讀取/sys/class/net/wlan0/address來獲取手機的wifi mac地址。通過adb 命令檢視該檔案的許可權如下:

C:\Users\Qiang>adb shell ls -la  /sys/class/net/wlan0/address-r--r--r-- 1 root root 4096 2021-01-12 14:57 /sys/class/net/wlan0/address

以上說明手機的app都可以讀取訪問該檔案。但是在Android10中,系統配置了普通App不能讀取/sys/class/net/wlan0/address的seandroid策略許可權。導致Android 10 中讀取失敗,提示許可權拒絕。由於seandroid強化了系統安全性,要想一個App訪問訪問系統的某一個目錄或者路徑,需要專門去配置te檔案策略。對於不熟悉seandroid配置的開發者配置起來有點難度。那有沒有辦法不配置seandroid策略檔案,設定檔案或者目錄可讀許可權就能訪問的方法。答案就是全域性關閉seandroid

二、安卓中關閉seandroid的方式討論

1.使用setenforce命令臨時關閉

命令如下

adb shell setenforce 0

setenforce命令只能暫時關閉seandroid,如果手機重啟了會被恢復為正常狀態。

setenforce在安卓原始碼中的路徑如下:

external/toybox/toys/android/setenforce.c

setenforce實現程式碼如下:

#define FOR_setenforce

#include "toys.h"
void setenforce_main(void){  char *new = *toys.optargs;
int state, ret; if (!is_selinux_enabled()) error_exit("SELinux is disabled"); else if (!strcmp(new, "1") || !strcasecmp(new, "enforcing")) state = 1; else if (!strcmp(new, "0") || !strcasecmp(new, "permissive")) state = 0; else error_exit("Invalid state: %s", new); ret = security_setenforce(state); if (ret == -1) perror_msg("Couldn't set enforcing status to '%s'", new);}

從以上程式碼可知,setenforce最終呼叫的是函式security_setenforce完成selinux的控制。

2.在kernel 關閉 selinux

在核心中配置SECURITY_SELINUX設定為 false,重新編譯kernel刷機。可以永久關閉seandroid。

以下是測試的核心編譯中.config檔案中關閉selinux之後的配置資訊:

CONFIG_SECURITY_SELINUX=n

3.在init程序啟動的時候關閉selinux

安卓系統啟動過程中,init程序會進行selinux的初始化。通過讀取/proc/cmdline檔案,判斷androidboot.selinux的值是否需要開啟selinux。因此,我們可以init程序初始化selinux的時候強制執行關閉操作。

以下將討論第三種方案來實現全域性關閉selinux。

三、init程序中全域性關閉selinux

1.init程序中selinux的初始化流程分析

init程序中selinux初始化相關的檔案路徑如下:

system/core/init/selinux.cppsystem/core/init/main.cpp

大概的初始化流程如下:

a.main.cpp中的main函式呼叫selinux.cpp中的SetupSelinux:

intmain(intargc,char**argv){

...省略        if (!strcmp(argv[1], "selinux_setup")) {            return SetupSelinux(argv);}...省略}

b.selinux.cpp中SetupSelinux函式實現如下:

int SetupSelinux(char** argv) {

    ...省略    SelinuxInitialize();
    ...省略    return 1;}

c.SetupSelinux呼叫了SelinuxInitialize方法。SelinuxInitialize方法程式碼如下:

//SelinuxInitialize中可以看到呼叫了IsEnforcing方法判斷

voidSelinuxInitialize(){...省略    bool kernel_enforcing = (security_getenforce() == 1);//判斷是否強制模式boolis_enforcing=IsEnforcing();    if (kernel_enforcing != is_enforcing) {//呼叫security_setenforce函式,和setenforce原理一樣        if (security_setenforce(is_enforcing)) {            PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");        }}...省略}

d.IsEnforcing方法實現如下:

//判斷是否需要強制模式

bool IsEnforcing() {    if (ALLOW_PERMISSIVE_SELINUX) {        return StatusFromCmdline() == SELINUX_ENFORCING;    }    return true;}

從IsEnforcing中可以知道,如果一直返回false,那麼將會關閉selinux。

2.全域性強制關閉selinux修改

從以上init程序初始化selinux的流程可以提供兩種修改方案來全域性關閉。

  • 第一種修改IsEnforcing函式永遠返回false。修改如下:

  bool IsEnforcing() {///ADDSTART    if(1>0)    {//一直返回false       return false;    }///ADD END    if (ALLOW_PERMISSIVE_SELINUX) {        return StatusFromCmdline() == SELINUX_ENFORCING;    }    return true;}

  • 第二種修改SelinuxInitialize方法,在函式中主動呼叫security_setenforce(false)。修改之後如下:

void SelinuxInitialize() {    Timer t;
    LOG(INFO) << "Loading SELinux policy";    if (!LoadPolicy()) {        LOG(FATAL) << "Unable to load SELinux policy";    }
    bool kernel_enforcing = (security_getenforce() == 1);    bool is_enforcing = IsEnforcing();    if (kernel_enforcing != is_enforcing) {        if (security_setenforce(is_enforcing)) {            PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");        }}//直接呼叫security_setenforce方法來關閉///ADD STARTsecurity_setenforce(false);///ADD END    if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {        LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();    }
    // init's first stage can't set properties, so pass the time to the second stage.    setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);}

修改之後編譯原始碼刷機,開機之後生效。

玩轉Android10系統原始碼開發定製更多文章:

玩轉Android10原始碼開發定製(一)原始碼下載編譯

玩轉Android10原始碼開發定製(二)刷機操作

玩轉Android10原始碼開發定製(二)刷機操作之fastboot刷機演示

玩轉Android10原始碼開發定製(二)刷機操作之Recovery刷機演示

玩轉Android10原始碼開發定製(三)原始碼中編譯手機刷機包

玩轉Android10原始碼開發定製(四)原始碼開發環境搭建

玩轉Android10原始碼開發定製(五)原始碼編譯開發中常用命令

玩轉Android10原始碼開發定製(六)修改核心原始碼繞過反除錯檢測

玩轉Android10原始碼開發定製(七)修改ptrace繞過反除錯

玩轉Android10原始碼開發定製(八)內建Apk到系統

玩轉Android10原始碼開發定製(九)內建frida-gadget so檔案和frida-server可執行檔案到系統

玩轉Android10原始碼開發定製(十)增加獲取當前執行最頂層的Activity命令

玩轉Android10原始碼開發定製(11)核心篇之安卓核心模組開發編譯

玩轉Android10原始碼開發定製(12)核心篇之logcat輸出核心日誌

關注公眾號獲取更多最新文章圖片圖片圖片圖片

圖片