<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/mobile/15794

            0x00 前言


            目前,在iOS中很多dylib是通過DYLDINSERTLIBRARIES來動態注入的,關于這種注入的防范方式最好的方法是在程序編譯時,添加一個空的restict區段,因為dyld在load動態庫時會檢查區段中是否存在restict,如果存在那么就跳過加載。詳情參見:防止tweak依附,App有高招;破解App保護,tweak留一手

            前段時間,發現自己寫的一個demo加了restict之后,仍然能夠被cycript掛載,順勢分析了cycript的注入原理。

            0x01 cycript簡介


            cycript是大神saurik開發的一個非常強大的工具,可以讓開發者在命令行下和應用交互,在運行時查看和修改應用。其中的底層實現,是通過蘋果的JavaScriptCore.framework來打通iOS與javascript的橋梁。具體詳解,參考

            0x02 cycript結構


            在安裝cycript過后,通過cydia可以看到安裝cycript之后影響的目錄結構

            雖然只提到這幾個文件,但是在/usr/bin下,還有一個cynject的可執行文件和cycript相關,后面分析會發現,這個程序才是注入的核心文件。我這里,通過scp把這些文件都下載到本地,方便分析。

            0x03 cycript主程序


            分析Cycript主程序時,觀察到里面有一個InjectLibrary的函數被調用

            #!c
            void InjectLibrary(int pid, int argc, const char *argv[]) {
                auto cynject(LibraryFor(reinterpret_cast<void *>(&main)));
                auto slash(cynject.rfind('/'));
                _assert(slash != std::string::npos);
                cynject = cynject.substr(0, slash) + "/cynject";
                auto library(LibraryFor(reinterpret_cast<void *>(&MSmain0)));
                bool ios(false);
                for (decltype(header->ncmds) i(0); i != header->ncmds; ++i) {
                    if (command->cmd == LC_VERSION_MIN_IPHONEOS)
                        ios = true;
                    command = shift(command, command->cmdsize);
                }
                _syscall(munmap(map, size)); // XXX: _scope
                auto length(library.size());
                _assert(length >= 6);
                length -= 6;
                _assert(library.substr(length) == ".dylib");
                library = library.substr(0, length);
                library += ios ? "-sim" : "-sys";
                library += ".dylib";
            #endif
                std::ostringstream inject;
                inject << cynject << " " << std::dec << pid << " " << library;
                for (decltype(argc) i(0); i != argc; ++i)
                    inject << " " << argv[i];   
            
                _assert(system(inject.str().c_str()) == 0);
            }
            

            程序在解析過程中,注入代碼前會對會環境進行檢查,并且進行字符串格式化拼接,構造一個shell命令,用來做調用system函數的參數,來執行cynject注入功能。

            0x04 cynject注入程序


            接下來分析cynject,在函數subb308的位置可以看到,通過調用taskfor_pid獲取到進程句柄結構。通過該結構,可以對進程能夠有訪問權限。

            舉個栗子:

            #!c
            mach_port_t rtask;
            task_for_pid(mach_task_self(), pid, &rtask);
            

            程序為了讓內存中的dylib有執行能力,把dylib通過線程的方式來加載。繼續往下看,就發現進程創建一個被掛起的線程

            拿到句柄結構,在進程的空間中申請內存,將dylib映射之后,寫入到這片申請的空間里面。

            所以,代碼邏輯大概是這樣的:

            #!c
            vm_size_t codeSize = 124;
            vm_address_t rAddress;
            vm_allocate(rtask, &rAddress, codeSize, TRUE);
            vm_write(rtask, rAddress, &code, (mach_msg_type_number_t)codeSize);
            vm_protect(rtask, rAddress, codeSize, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
            

            最后,等dylib加載完全后,為dylib恢復啟動并執行使其開始運行

            梳理一下大體的流程:

            ( 1 )獲取 PID 的進程句柄
            ( 2 )在 PID 中創建一個被掛起的線程
            ( 3 )在 PID 進程中申請一片用于加載 DYLIB 的內存
            ( 4 )調用 RESUME ,恢復線程

            OVER~

            說到這里,流程差不多梳理完了,拿一個dylib測試一下

            通過lldb連上程序,看一下內存加載模塊:

            可以發現,我們惡意的dylib已經注入到進程中了。

            0x05 后記


            cycript里面還有一些比較有意思的東西,大家可以深挖一下。另外,上面的內容不要用到自己企業的app產品中,按照蘋果appStore原則,調用私有api以及動態注入代碼的操作,是會被下架的。

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线