<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ### **概述** Android應用程序是運行在一個沙箱中。這個沙箱是基于Linux內核提供的用戶ID(UID)和用戶組ID(GID)來實現的。Android應用程序在安裝的過程中,安裝服務PackageManagerService會為它們分配一個唯一的UID和GID,以及根據應用程序所申請的權限,賦予其它的GID。有了這些UID和GID之后,應用程序就只能限訪問特定的文件,一般就是只能訪問自己創建的文件。此外,Android應用程序在調用敏感的API時,系統檢查它在安裝的時候會沒有申請相應的權限。如果沒有申請的話,那么訪問也會被拒絕。對于有root權限的應用程序,則不受上述沙箱限制。此外,有root權限的應用程序,還可以通過Linux的ptrace注入到其它應用程序進程,以及系統進程,進行各種函數調用攔截。 本系列主要講代碼加殼、注入和攔截技術的,包括: 1. SO注入。也就是從一個進程向另外一個進程注入一個SO文件,通過該注入的SO文件就可以實現函數攔截功能。 2. SO加殼。加殼的目的自然就是加大別人對自己的C/C++代碼進行靜態逆向難度了,這個技術的關鍵是要實現一個能純內存操作的Linker了。也就是說,解密后的SO文件內容是保存在一個內存緩沖區的,然后再針對該內存緩沖區進行解析和鏈接,最終形成一段可執行的代碼。這個過程不會產生任何文件供別人做靜態分析。 3. C/C++函數GOT攔截。通過修改SO的GOT項來實現函數攔截。這個技術的特點是簡單和穩定,但是不足之處于它是針對函數的調用方進行攔截的,而不是針對函數本身的實現來進行攔截的。這樣當我們想對某一個函數進行攔截的時候,就必須要檢查進程內所有的模塊,然后對調用了目標函數的模塊的相關GOT 項進行修改。此外,如果某一個模塊是通過動態SO加載技術(dlopen、dlsym)來調用目標函數的話,GOT攔截就失效了,因為動態SO加載技術不會產生GOT項。 4. C/C++函數INLINE攔截。這種方法是直接對目標函數的前面幾條指令進行修改,用來實現攔截技術。INLINE攔截沒有上述GOT攔截的缺點,但是它的實現會復雜很多。由于絕大部分Android設備都是基于ARM架構,因此這里只討論ARM架構的C/C++函數INLINE攔截。ARMl架構主要分為ARM和THUMB兩種指令集,也就是在Android設備上運行的C/C++函數分為ARM和THUMB兩種類型。對于ARM指令集的函數,對它們進行攔截至少需要修改頭8個字節;對于THUMB指令集,對它們進行攔截至少需要修改頭12個字節。無論ARM指令還是THUMB指令函數,我們要修改的頭8個字節或者12個字節都很容易碰到跳轉或者PC相對尋址指令,這樣就需要對指令進行重定位。這個重定位工作相當于繁重和麻煩,得實現一個ARM和THUMB指令解析庫才行。不像X86的函數INLINE攔截,只需要函數的頭5個字節即可,而且這5個字節幾乎都是堆棧相關的操作,不會涉及到跳轉或者PC相對尋址指令。 5. DEX注入。在SO注入的基礎上,要對目標進程進行DEX注入是相當簡單的,通過DexClassLoader即可實現。 6. DEX加殼。DEX加殼與SO加殼一樣,都要求在解密之后,能夠進行純內存操作,中間不要產生任何和DEX或者ODEX文件,否則的話,就會給別提供靜態分析的機會,這樣就失去了加殼的目的。 7. Java函數攔截。與C/C++函數攔截相對,Java函數攔截要優雅得多,因為所有的Java函數都是通過虛擬機來執行的。Dalvik虛擬機執行的函數分為Java和Native兩種,它們都是使用Method結構體來描述。當一個Method結構體描述的是一個Java函數時,它有一個成員變量就指向該Java函數的方法區。而當一個Method結構體描述的是一個Native函數,它有一個成員變量指向該Native函數的地址。因此,主要我們能將一個用來描述Java函數的Method結構體修改為一個指向Native函數的Method結構體,就可以騙過Dalvik虛擬機來執行我們所指定的Native函數,從而實現攔截。 以上7個技術點涵蓋了Android安全的攻與防基礎。在這些基礎上不僅可以保護我們自己的代碼,還可以對別人的代碼進行攻擊。 * Android安全模型 * SO注入技術 * SO加殼技術 * C/C++函數攔截技術 * DEX注入技術 * DEX加殼技術 * Java函數攔截技術 #### **Android安全模型** ![](https://box.kancloud.cn/3f0d2b143607df6f07356a8b039f7263_394x217.png) ![](https://box.kancloud.cn/78b0f90cd60a9caa3b6dcba231347c41_619x372.png) **用戶** * 系統中可以存在多個用戶,每一個用戶都具有一個UID * 用戶按組劃分形成用戶組,每一個用戶組都具有一個GID * 一個用戶可以屬于多個用戶組 **文件** * 每一個文件都具有三種權限 Read、Write、Execute * 文件權限按用戶屬性分為三組 Owner、Group、Other ![](https://box.kancloud.cn/faced38fa41365815c90cc76f50fc0f1_827x544.png) **進程** * UID -- setuid * GID -- setgid * Supplementary GIDS – setgroups * Capabilities -- capset ![](https://box.kancloud.cn/68f5dbba5a1568e18ecd86b3b3ca1f90_795x537.png) * 系統中的第一個進程Init的UID是root * 子進程的UID默認與父進程相同,但可以通過setuid進行修改 * 子進程被fork之后exec了一個設置了SUID位的bin文件,那么子進程的UID變為該bin文件的Ower UID ![](https://box.kancloud.cn/c076c4303308e2baaa9f7f1199dfcb79_727x181.png) ![](https://box.kancloud.cn/3460d11085d6fde58a32b7bd323b88f9_612x275.png) **每一個APK在安裝的時候,PMS都會給它分配一個唯一的UID和GID** * 如果兩個APK具有相同的簽名,那么可以通過android:sharedUserId申請分配相同的UID和GID * 如果一個APK具有平臺簽名,那么可以通過android:sharedUserId=“android.uid.system”獲得System UID > **備注** > 通過Master Key漏洞獲得System UID > http://drops.wooyun.org/papers/219 > http://safe.baidu.com/2013-10/android-masterkey-9695860.html > http://safe.baidu.com/2013-11/masterkey-9950697.html > 打開文件/data/local.prop,設置以下屬性: > `ro.kernel.qemu=1` > 即可使得adb具有root權限 **每一個APK都可以通過<uses-permission android:name=“android.permission.XXX”/>申請若干個Permission** * 有些Permission需要具有平臺簽名才可以申請,如INSTALL_PACKAGES **每一個Permission都對應于一個Supplementary GID,因此,給APK分配Permission即為APK分配Supplementary GID** http://developer.android.com/reference/android/Manifest.permission.html **APK進程是由UID為root的Zygote進程fork出來的,fork之后**: ![](https://box.kancloud.cn/0023bc63d94db2a1bcc838123965dc26_800x482.png) http://man7.org/linux/man-pages/man2/capset.2.html **PMS記錄有每一個APK所申請的Permission,當APK調用敏感API時,相應的模塊就會通過PMS會驗證調用APK是否申請有相應的Permission** ![](https://box.kancloud.cn/834798c84859e17f646c1c85b2ea4b7d_774x305.png) **突破沙箱** ![](https://box.kancloud.cn/5af0468ae7e75ad25a8d716735f0db75_729x458.png) * **突破沙箱:創建其它APK也能訪問的文件** ![](https://box.kancloud.cn/c9ce31d3ded93d312900c02d50b28a3b_1036x165.png) * **突破沙箱:Binder IPC** ![](https://box.kancloud.cn/2de0c8df1c411f3bafa2f1fdd6b76ad9_781x450.png) * **突破沙箱:Content Provider** ![](https://box.kancloud.cn/d2ac0f1a190b62a13dd2ec6be4b3fce7_761x337.png) * **突破沙箱:黑客技術** * SO注入 - C/C++函數攔截 - DEX注入 - Java函數攔截 - …… #### **SO注入技術** **ptrace** ~~~ long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); ~~~ http://man7.org/linux/man-pages/man2/ptrace.2.html ![](https://box.kancloud.cn/09d5249854ddae50433a3362cc896f9e_457x361.png) * Step 1: PTRACE_ATTACH到目標進程,并且讓目標進程發生PTRACE_SYSCALL時停止 * Step 2: PTRACE_GETREGS保存目標進程的上下文 * Step 3: PTRACE_SETREGS改寫目標進程的PC寄存器,使得它指向函數mmap的地址 * Step 4: PTRACE_CONT讓目標進程恢復執行,這時候將會執行函數mmap * Step 5: PTRACE_GETREGS獲得目標進程的R0寄存器值,即為函數mmap的返回值,指向在目標進程地址空間分配的一塊內存 * Step 6: PTRACE_POKETEXT往在目標進程分配的地址寫入以下一段SHELL CODE ![](https://box.kancloud.cn/be4badc25d1590f051a2f94d806ef01f_813x444.png) * Step 7: PTRACE_SETREGS改寫目標進程的PC寄存器,使得它指向上述SHELL CODE的起始地址_inject_start_s * Step 8: PTRACE_DETTACH目標進程,目標進程恢復執行后,就會執行注入的 * Step 9: 注入的SHELL CODE在目標進程加載一個SO,并且找到這個SO的指定入口函數,進行調用 #### **SO加殼技術** **系統中的SO文件由一個叫Linker的加載器負責加載,即調用dlopen函數進行加載**: ~~~ void *dlopen(const char *filename, int?flag); ~~~ 如果能將第一個參數改為一個內存地址,就可以實現從內存加載SO的功能,進而可以對該內存進行加密處理 **dlopen** ![](https://box.kancloud.cn/e1d5d4523c41d7808cedcd50281e4d6d_491x287.png) **find_library** ![](https://box.kancloud.cn/158ec1e42211b5b99910794c52716654_591x350.png) **load_library** ![](https://box.kancloud.cn/ff95d6318446480d7ce76a0cd5060057_648x507.png) **Read Elf32_Ehdr** Elf32_Ehdr header[1]; read(fd.fd, (void*)header, sizeof(header)) http://man7.org/linux/man-pages/man5/elf.5.html **ReadElf32_Phdr** ![](https://box.kancloud.cn/06c02819506c1be5cbd1328b90d13c44_804x572.png) **Reserve Enough Memory** ![](https://box.kancloud.cn/3599579b0cfc31c2b003940b0afbda76_711x553.png) **Load Segments** ![](https://box.kancloud.cn/f0045c85294ad668e391d76572e640cc_716x666.png) **What data we need?** Elf32_Ehdr Elf32_Phdr Segments **How to fill above data? ** ![](https://box.kancloud.cn/dee65aff7e714622cfa6ddfa8ecfa17c_549x171.jpg) **struct elfinfo** ![](https://box.kancloud.cn/2136f001c8f856f3546c373ee924d3a7_332x177.png) **Open file and create elfinfo** ![](https://box.kancloud.cn/cf4dba1ac2298f57323fbde85ef492f3_512x220.png) **Read Elf32_Ehdr** ![](https://box.kancloud.cn/12ec737911227705d55e23f66fdcc08e_609x145.png) **Read Elf32_Phdr** ![](https://box.kancloud.cn/0246198dbe2a1449c4a5fc1e636c4b9e_762x183.png) **Read segments** ![](https://box.kancloud.cn/f5664493e5011e07da07970c21e24766_663x344.png) #### **C/C++函數攔截技術** * Got Hook * VTable Hook * Inline Hook **Got Hook** ![](https://box.kancloud.cn/7a29bba9054d7e599dd567bd24741dd3_888x543.png) * **Step 1: Find the address of eglSwapBuffers** ~~~ void * handle = dlopen(“/system/lib/libEGL.so”, RTLD_NOW) void* addr = dlsym(handle, “eglSwapBuffers”); ~~~ * **Step 2: Find the .got section ** ![](https://box.kancloud.cn/629714d0b4e95b381ff7713270b0bba5_740x278.png) * **Step 3: Find the address of eglSwapBuffers in .got section** ![](https://box.kancloud.cn/00d47b31d69f77abc5c6f37024cb6654_648x176.png) * **Step 4: Replace it** ![](https://box.kancloud.cn/cf46eaf7b5690340277f5ea60b6f217a_797x251.png) **VTable Hook** ![](https://box.kancloud.cn/2e28e9cdcfc42ebf07635fecb79b1594_896x562.png) * **Step 1: Find the address of Surface::unlockAndPost ** ~~~ void * handle = dlopen(“/system/lib/libgui.so”, RTLD_NOW) void* addr = dlsym(handle,“_ZN7android7Surface13unlockAndPostEv”); ~~~ * **Step 2: Find the .data.rel.ro section** ![](https://box.kancloud.cn/8ef459c80d2856362c353693fbbda594_759x265.png) * **Step 3: Find the address of Surface::unlockAndPost in .data.rel.ro section ** ![](https://box.kancloud.cn/5c65328ddf355cabefb5f1f3ed667b55_764x175.png)、 * **Step 4: Replace it** ![](https://box.kancloud.cn/cf46eaf7b5690340277f5ea60b6f217a_797x251.png) **Inline Hook** ![](https://box.kancloud.cn/809c5fc44df0208e984e1ea848549a0d_648x534.png) * **Problem** ![](https://box.kancloud.cn/8cd16754795b884afcca7451f41f2956_497x338.png)移動的指令可能包含: **普通指令** * PC相對尋址指令 * 跳轉指令 **對于PC相對尋址和跳轉指令**: * 需要進行重定位 **因此,實現Inline Hook要求**: * 動態的指令解析 * 動態的指令重定位 #### **DEX注入技術** ![](https://box.kancloud.cn/aec648f67b895c0f98d30e85a844b481_448x414.png) ![](https://box.kancloud.cn/47d375ffab1c3cabcb7e2ca74033e988_1190x712.png) #### **DEX加殼技術** * 通過DexClassLoader可以動態地加載DEX文件,但是它在加載DEX文件的過程會生成一個ODEX文件,給別人提供了靜態逆向的可能 * 通過分析DexClassLoader的實現可以知道,它是通過DexFile來實現動態加載DEX文件的 * 進一步分析DexFile的實現,發現它提供了兩個隱藏接口來實現加載內存DEX文件 ![](https://box.kancloud.cn/b92912095ecae222f452bd3f81ce806b_891x269.png) ![](https://box.kancloud.cn/efd4bf1705eb13d63cdccfb5bb26b238_764x706.png) * 但是,DexFile從Android 4.0開始才支持加載內存DEX文件,如何支持Android 4.0以下的版本呢? * 通過分析DexFile加載內存DEX文件的實現可以發現,里面用到的關鍵函數都可以從libdex.a和libdvm.so獲得 * 于是,可以模仿Android 4.0,實現DexFile加載內存DEX文件的功能 * 輔助數據結構和函數 ![](https://box.kancloud.cn/05c4442c3376dbe3783ca2f73b5a1bf8_737x407.png) * **Step 1: custome_load_class_from_memory** ![](https://box.kancloud.cn/41f7c8b0697298433d1a7002d9b0d4f7_1015x656.png) * **Step 2: open_dex_from_memory** ![](https://box.kancloud.cn/e15585307e794cb70d4a207cc2c76669_757x621.png) * **Step 3: raw_dex_file_open_array** ![](https://box.kancloud.cn/9a151f0b49a17c3787de87c74a8c9db7_773x309.png) * **Step 4: prepare_dex_in_memory** ![](https://box.kancloud.cn/3be6a7c817c52387dd6ec9dbeccc7fed_681x275.png) * **Step 5: rewrite_dex ** ![](https://box.kancloud.cn/51047ef47a51d0e13403c3e7c234c7fa_751x654.png) * **Step 6: dex_file_open_partial** ![](https://box.kancloud.cn/3d95f6be35110f409f567f32d92364e8_743x585.png) * **Step 7: allocate_aux_structures** ![](https://box.kancloud.cn/6af58febdd752660c13c9296a02a5dae_672x691.png) * **Step 8: add_to_dex_file_table** ![](https://box.kancloud.cn/b3080bd253a04fdbaa9331dec3acb140_711x469.png) * 上述過程用到的關鍵函數均可從libdex.a和libdvm.so獲得: * dexSwapAndVeriry * dexCreateClassLookup * dexFileParse * dvmAllocRegion * dvmAllocAtomicCache * dvmHashTableLock * dvmHashTableLookup * dvmHashTableUnlock #### **Java函數攔截技術** * 在Dalvik虛擬機中,無論是Java函數,還是Native函數,都是通過Method結構體來描述的 ![](https://box.kancloud.cn/52380063cc25e7063abb85a917feca2d_702x392.png) * Dalvik虛擬機通過dvmIsNativeMethod判斷一個函數是Java函數還是Native函數 ![](https://box.kancloud.cn/476c92786b73391740068e107e55712e_506x55.png) * Dalvik虛擬調用一個函數之前,首先判斷它是Java函數還是Native函數 ![](https://box.kancloud.cn/9b04b1597e470c5276aa6ff94e7a6f94_702x496.png) * Java函數攔截技術原理分析 * 對于Java函數,Davik虛擬機使用解釋器來執行 * 對于Native函數, Davik虛擬機找到它的函數指針nativeFunc,進行直接調用 * 如果我們能把一個Java函數修改為Native函數,并且將nativeFunc指針設置為自定義的函數,那么就可以實現攔截了 * 攔截完成之后,根據情況決定是否需要調用原來的Java函數,即可完成整個攔截過程 * libdvm導出了兩個函數dvmDecodeIndirectRef和dvmSlotToMethod,如果我們知道一個Java函數在它所屬的Class里面的位置Slot,那么就可以通過它們獲得該Java函數在Dalvik虛擬內部所對應的Method結構體: ![](https://box.kancloud.cn/812850146e131832da2197f1c68525b4_1078x140.png) * 得到一個Java函數在Dalvik虛擬內部所對應的Method結構體之后,就可以將它設置為Native函數: ![](https://box.kancloud.cn/ed432dc43769c8cf4b57b49e83cfe3a1_531x111.png) **如何獲得一個Java函數所屬的Class,以及它在該Class的位置Slot呢?** **假設我們知道:** * Java函數的名稱—methodName * Java函數的原型—prototype * Java函數的類名稱—className * 用來加載該Java類的ClassLoader--classLoader **Step 1: 獲得Class對象** ~~~ Class<?> clazz = classLoader.loadClass(className); ~~~ **Step 2: 獲得Method對象** ~~~ Method method = clazz.getDeclaredMethod(methodName, prototype); ~~~ **Step 3: 獲得clazz的Slot域描述** ~~~ Field field = clazz.getDeclaredField(“Slot”); ~~~ **Step 4: 獲得method的slot** ~~~ int slot= field.getInt(method); ~~~ **Step 5: 將clazz和slot通過JNI傳遞到C/C++層,調用dvmDecodeIndirectRef和dvmSlotToMethod** ~~~ ClassObject* declared_classs = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), clazz); Method* method = dvmSlotToMethod(declared_class, slot); ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看