iOS防護(hù)----越獄檢測(cè)

如何檢測(cè)越獄手機(jī)一直是iOS應(yīng)用安全防護(hù)的第一道門(mén)檻。
在應(yīng)用開(kāi)發(fā)過(guò)程中,我們希望知道設(shè)備是否越獄,正以什么權(quán)限運(yùn)行程序,好對(duì)應(yīng)采取一些防御和安全提示措施。
一般我們通過(guò)一些常規(guī)的防御性代碼,去做這種檢測(cè),當(dāng)然,這樣的檢測(cè)有一定的誤報(bào)概率,但是對(duì)于APP的開(kāi)發(fā)者來(lái)講,需要確定一個(gè)原則,哪怕是越獄手機(jī)檢測(cè)成未越獄,也不能將未越獄的手機(jī)檢測(cè)成越獄手機(jī)。
首先我們進(jìn)行常規(guī)的文件路徑檢測(cè):

- (void)isOk0 {
    NSString *cydiaPath = @"/Applications/Cydia.app";
    NSString *aptPath = @"/private/var/lib/apt/";
    NSString *applications = @"/User/Applications/";
    NSString *Mobile = @"/Library/MobileSubstrate/MobileSubstrate.dylib";
    NSString *bash = @"/bin/bash";
    NSString *sshd =@"/usr/sbin/sshd";
    NSString *sd = @"/etc/apt";
    if ([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
        exit(0);
    }
    if ([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
        exit(0);
    }
    if([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
        exit(0);
    }
    
    if([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
        exit(0);
    }
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:applications]){
        exit(0);
    }
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:Mobile]){
        exit(0);
    }
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:bash]){
        exit(0);
    }
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:sshd]){
        exit(0);
    }
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:sd]){
        exit(0);
    }
}

這里直接exit(0)是為了防止一些繞過(guò)策略,比如替換方法,導(dǎo)致檢測(cè)代碼被繞過(guò)。如果檢測(cè)到手機(jī)越獄,直接退出軟件。

當(dāng)然了,攻擊者可以直接通過(guò)替換系統(tǒng)的fileExistsAtPath函數(shù),讓他一直返回false,從而繞過(guò)軟件路徑的檢測(cè)。這時(shí)候就需要一些C語(yǔ)言的函數(shù)去做更加精確的檢測(cè)。
以下函數(shù)需要引用頭文件:

#import <sys/stat.h>
#import <dlfcn.h>
#import <stdlib.h>
#import <mach-o/dyld.h>

- (void)isOK1 {
    //可能存在hook了NSFileManager方法,此處用底層C stat去檢測(cè)
    //    /Library/MobileSubstrate/MobileSubstrate.dylib 最重要的越獄文件,幾乎所有的越獄機(jī)都會(huì)安裝MobileSubstrate
    //    /Applications/Cydia.app/ /var/lib/cydia/絕大多數(shù)越獄機(jī)都會(huì)安裝
    struct stat stat_info;
    if (0 == stat("/Library/MobileSubstrate/MobileSubstrate.dylib", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/Applications/Cydia.app", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/var/lib/cydia/", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/var/cache/apt", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/var/lib/apt", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/etc/apt", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/bin/bash", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/bin/sh", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/usr/sbin/sshd", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/usr/libexec/ssh-keysign", &stat_info)) {
        exit(0);
    }
    if (0 == stat("/etc/ssh/sshd_config", &stat_info)) {
        exit(0);
    }
}

可能存在stat也被hook了,可以看stat是不是出自系統(tǒng)庫(kù),有沒(méi)有被攻擊者換掉,這種情況出現(xiàn)的可能性不大,如果結(jié)果不是 /usr/lib/system/libsystem_kernel.dylib 的話(huà),那就100%被攻擊了。

- (void)isOK2 {
    //可能存在stat也被hook了,可以看stat是不是出自系統(tǒng)庫(kù),有沒(méi)有被攻擊者換掉
    //這種情況出現(xiàn)的可能性很小
    int ret;
    Dl_info dylib_info;
    int (*func_stat)(const char *,struct stat *) = stat;
    if ((ret = dladdr(&func_stat, &dylib_info))) {
        NSLog(@"lib:%s",dylib_info.dli_fname);      //如果不是系統(tǒng)庫(kù),肯定被攻擊了
        if (strcmp(dylib_info.dli_fname, "/usr/lib/system/libsystem_kernel.dylib")) {   //不相等,肯定被攻擊了,相等為0
            exit(0);
        }
    }
}

可以檢索自己的應(yīng)用程序是否被鏈接了異常動(dòng)態(tài)庫(kù),列出所有已鏈接的動(dòng)態(tài)庫(kù),通常情況下,會(huì)包含越獄機(jī)的輸出結(jié)果會(huì)包含字符串: Library/MobileSubstrate/MobileSubstrate.dylib :

- (void)isOK3 {
    //列出所有已鏈接的動(dòng)態(tài)庫(kù):
    //通常情況下,會(huì)包含越獄機(jī)的輸出結(jié)果會(huì)包含字符串: Library/MobileSubstrate/MobileSubstrate.dylib 。
    uint32_t count = _dyld_image_count();
    for (uint32_t i = 0 ; i < count; ++i) {
        NSString *name = [[NSString alloc]initWithUTF8String:_dyld_get_image_name(i)];
        if ([name containsString:@"Library/MobileSubstrate/MobileSubstrate.dylib"]) {
            exit(0);
        }
    }
}

如果攻擊者給MobileSubstrate改名,但是原理都是通過(guò)DYLD_INSERT_LIBRARIES注入動(dòng)態(tài)庫(kù),我們可以查看一下環(huán)境變量:

- (void)isOK4 {
    //如果攻擊者給MobileSubstrate改名,但是原理都是通過(guò)DYLD_INSERT_LIBRARIES注入動(dòng)態(tài)庫(kù)
    //那么可以,檢測(cè)當(dāng)前程序運(yùn)行的環(huán)境變量
    char *env = getenv("DYLD_INSERT_LIBRARIES");
    if (env != NULL) {
        exit(0);
    }
}

雖然這里用到的是C語(yǔ)言檢測(cè)函數(shù),但這些函數(shù)被hook的可能性也是存在的,比如fishhook。。
如果真有大佬手動(dòng)hook這些函數(shù)或者直接修改二進(jìn)制的話(huà),那也沒(méi)啥好防的,大佬們隨便吧。。

所以也印證了那句話(huà):沒(méi)有絕對(duì)的安全,你唯一能做的就是拖延攻擊者的腳步。

對(duì)于這些函數(shù),不建議單獨(dú)寫(xiě)方法,容易被hook掉,所以最好是寫(xiě)在不能被hook的函數(shù)里,比如application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions。。。

誰(shuí)TM會(huì)hook程序的初始化函數(shù)。。

另外越獄檢測(cè)函數(shù)最好不要出現(xiàn)Jailbreak,或者canijailbreak,或者AntiJailbreak這種字段,很容易被定位到。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在應(yīng)用開(kāi)發(fā)過(guò)程中,我們希望知道設(shè)備是否越獄,正以什么權(quán)限運(yùn)行程序,好對(duì)應(yīng)采取一些防御和安全提示措施。 那么,到底應(yīng)...
    無(wú)灃閱讀 1,302評(píng)論 0 3
  • 在應(yīng)用開(kāi)發(fā)過(guò)程中,我們希望知道設(shè)備是否越獄,正以什么權(quán)限運(yùn)行程序,好對(duì)應(yīng)采取一些防御和安全提示措施。iOS7相比之...
    SuperRoot閱讀 1,021評(píng)論 1 0
  • 注:原文---念茜的博客 在應(yīng)用開(kāi)發(fā)過(guò)程中,我們希望知道設(shè)備是否越獄,正以什么權(quán)限運(yùn)行程序,好對(duì)應(yīng)采取一些防御和安...
    richar_閱讀 353評(píng)論 0 0
  • 如何檢測(cè)越獄手機(jī)一直是iOS應(yīng)用安全防護(hù)的第一道門(mén)檻。早在2018年的時(shí)候就寫(xiě)過(guò)一篇文章來(lái)介紹越獄檢測(cè),但是由于時(shí)...
    撿書(shū)閱讀 7,462評(píng)論 11 6
  • 判斷手機(jī)越獄的幾種方式: 1. 通過(guò)手機(jī)越獄后增加的越獄文件判斷 2. 根據(jù)是否能打開(kāi)cydia判斷 3.根據(jù)是否...
    6ffd6634d577閱讀 3,722評(píng)論 1 6

友情鏈接更多精彩內(nèi)容