TaintDroid剖析之DVM變數級污點跟蹤(下篇)

来源:http://www.cnblogs.com/alisecurity/archive/2016/07/18/5681190.html
-Advertisement-
Play Games

在啟動篇中我們詳細分析了TaintDroid對DVM方法參數和方法變數的變數級污點跟蹤機制,現在我們將繼續分析TaintDroid對類的靜態域、實例域以及數組的污點跟蹤。 ...


TaintDroid剖析之DVM變數級污點跟蹤(下篇)
作者:簡行、走位@阿裡聚安全

1 回顧

上一章節中我們詳細分析了TaintDroid對DVM方法參數和方法變數的變數級污點跟蹤機制,現在我們將繼續分析TaintDroid對類的靜態域、實例域以及數組的污點跟蹤。

 

2 瞭解DVM中類的數據結構

由於DVM師從JVM,所以DVM中所有類的祖先也是Object類,該類定義在dalvik/vm/oo/Object.h中。其實不僅僅是Object類,DVM所有的基本類都定義在Object.h文件中。

眾所周知,Object類共分三種類型:

1)Class Objects,它是java.lang.Class的實例,此類object的公共基類是ClassObject;

2)Array Objects,由new Array指令創建,此類object的公共基類是ArrayObject;

3)Data Objects,除了上面兩種Object之外的所有object,公共基類是DataObject。

這裡有一個特例需要註意,那就是String Objects!String Objects當前等同於Data Objects,但鑒於該類在DVM中大量使用,因此DVM單獨定義了一個類StringObject,它直接繼承至Object。

 

瞭解了類的數據結構,再去分析TaintDroid對類的靜態域、實例域和數組的污點跟蹤就不會覺得無從下手了。

 

3 對各種數據結構的修改

要想實現對類的實例域和靜態域的污點跟蹤,最簡單粗暴的方式就是對類中相關的數據結構進行修改。TaintDroid就是這麼做的。

 

1)首先,修改了ClassObject::Object:

struct ClassObject : Object {

    /* leave space for instance data; we could access fields directly if we freeze the definition of java/lang/Class */

#ifdef WITH_TAINT_TRACKING

    // x2 space for interleaved taint tags

    u4              instanceData[CLASS_FIELD_SLOTS*2];

#else

    u4              instanceData[CLASS_FIELD_SLOTS];

#endif /*WITH_TAINT_TRACKING*/

TaintDroid將其中的u4 instanceData[CLASS_FILED_SLOTS]改為u4 instanceData[CLASS_FILED_SLOTS * 2]。這裡CLASS_FILED_SLOTS預設為4。倍增的空間用於交叉存儲各個實例域的污點。聯想到類的實例域有兩種類型:1)諸如int之類的基本類型;2)類對象的引用。所以我們可以知道,TaintDroid為每個引用也分配了一個tag,用於表示該引用的污點信息。充分理解這一點,對我們後續分析複雜污點傳播邏輯很有幫助。

 

2)其次,修改了靜態域StaticField:Field:

struct StaticField : Field {

    JValue          value;          /* initially set from DEX for primitives */

#ifdef WITH_TAINT_TRACKING

    Taint           taint;

#endif

};

在JValue之後添加了Taint tiant成員。Taint成員定義在vm/interp/Taint.h文件中定義如下:

  typedef struct Taint{ u4 tag}Taint;

 

通過這樣的修改,再對涉及到操作這些數據結構的方法進行修複就能實現類的實例域和靜態域的污點跟蹤了。這裡以computeFieldOffsets函數為例,此函數定義在dalvik/vm/oo/Class.cpp中,由於代碼較多,僅截取部分修複相關部分:

……

if (clazz->super != NULL)

        fieldOffset = clazz->super->objectSize;

    else

        fieldOffset = OFFSETOF_MEMBER(DataObject, instanceData);

……

/*Start by moving all reference fields to the front */

for (i = 0; i < clazz->ifieldCount; i++) {

        InstField* pField = &clazz->ifields[i];

        char c = pField->signature[0];

 

        if (c != '[' && c != 'L') {

            while (j > i) {

                InstField* refField = &clazz->ifields[j--];

                char rc = refField->signature[0];

                if (rc == '[' || rc == 'L'] {

                    swapField(pField, refField);

                    c = rc;

                    clazz->ifieldRefCount++;

                    break;

                }

            }

            /* We may or may not have swapped a field.*/

        } else {

            /* This is a reference field.*/

            clazz->ifieldRefCount++;

        }

        /*If we've hit the end of the reference fields, break.*/

        if (c != '[' && c != 'L')

            break;

 

        pField->byteOffset = fieldOffset;

#ifdef WITH_TAINT_TRACKING

        fieldOffset += sizeof(u4) + sizeof(u4); /* interleaved tag */

#else

        fieldOffset += sizeof(u4);

#endif

        LOGVV("  --- offset1 '%s'=%d", pField->name,pField->byteOffset);

}

……

 

/* Alignment is good, shuffle any double-wide fields forward, and finish assigning field offsets to all fields.*/

for ( ; i < clazz->ifieldCount; i++) {

        InstField* pField = &clazz->ifields[i];

        char c = pField->signature[0];

 

        if (c != 'D' && c != 'J') {

            while (j > i) {

                InstField* doubleField = &clazz->ifields[j--];

                char rc = doubleField->signature[0];

                if (rc == 'D' || rc == 'J') {

                    swapField(pField, doubleField);

                    c = rc;

                    break;

                }

            }

        } else {

        }

        pField->byteOffset = fieldOffset;

#ifdef WITH_TAINT_TRACKING

        fieldOffset += sizeof(u4) + sizeof(u4); /* room for tag */

        if (c == 'J' || c == 'D')

            fieldOffset += sizeof(u4) + sizeof(u4); /* keep 64-bit aligned */

#else

        fieldOffset += sizeof(u4);

        if (c == 'J' || c == 'D')

            fieldOffset += sizeof(u4);

#endif /* ndef WITH_TAINT_TRACKING */

    }

顯然,在計算類中各個實例域的偏移值的時候,由於TaintDroid對實例域的空間進行了倍增(交叉存儲污點),所以這裡應該加上2*sizeof(u4)。另外需要註意的是對於Double和Long類型的數據,要加上4*sizeof(u4)!

至此類的實例域和靜態域的污點跟蹤分析完畢,下一步輪到數組了。

 

3)對數組對象ArrayObject:Object的修改:

struct ArrayObject : Object {

    /* number of elements; immutable after init */

    u4              length;

#ifdef WITH_TAINT_TRACKING

    Taint           taint;

#endif

    u8              contents[1];

};

在length成員之後添加Taint tiant成員。之所以這樣做,是因為出於性能的考慮:如果數組中每個成員都存儲一個tag的話,對性能的影響就太大了,所以TaintDroid對每個ArrayObject對象只分配一個tag。

 

同樣的,修改了ArrayObject的結構體,就必須同步修改涉及到對ArrayObject進行操作的函數。這裡以oo/Array.cpp中的allocArray函數為例:

static ArrayObject* allocArray(ClassObject* arrayClass, size_t length,

    size_t elemWidth, int allocFlags)

{

    ……

    ArrayObject* newArray = (ArrayObject*)dvmMalloc(totalSize, allocFlags);

    if (newArray != NULL) {

        DVM_OBJECT_INIT(newArray, arrayClass);

        newArray->length = length;

#ifdef WITH_TAINT_TRACKING

        newArray->taint.tag = TAINT_CLEAR;

#endif

        dvmTrackAllocation(arrayClass, totalSize);

    }

}

在分配一個新的數組的時候,TaintDroid將它的taint成員賦值為TAINT_CLEAR(即清空污點信息)。

 

4)特殊類StringObject的結構分析。它的結構體如下:

struct StringObject : Object {

    /* variable #of u4 slots; u8 uses 2 slots */

    u4              instanceData[1];

    /** Returns this string's length in characters. */

    int length() const;

    /**

     * Returns this string's length in bytes when encoded as modified UTF-8.

     * Does not include a terminating NUL byte.

     */

    int utfLength() const;

    /** Returns this string's char[] as an ArrayObject. */

    ArrayObject* array() const;

    /** Returns this string's char[] as a u2*. */

    const u2* chars() const;

};

由於StringObject提供了一個方法array(),此方法返回一個ArrayObject型指針,所以在獲取和設置StringObject的污點信息的時候,需要通過StringObject.array()->taint.tag進行操作。

 

4 進一步分析DVM污點傳播邏輯

在前一章節中,我們分析了兩參數相加的DVM opcode(OP_ADD_INT_2ADDR),這是因為我們當時對類的靜態域、實例域以及數組的污點存儲並不熟悉,所以也就僅僅能捏一捏這類軟柿子而已,現在我們挑戰一下更高難度的數組操作相關的opcode——OP_AGET_OBJECT(即aget-obj)。該opcode的彙編實現在dalvik/vm/mterp/armv*te_taint/OP_AGET_OBJECT.S文件中:

%verify "executed"

%include "armv5te_taint/OP_AGET.S"

 

轉到OP_AGET.S:

%default { "load":"ldr", "shift":"2" }   //表示移位基準為2位,即乘以4

%verify "executed"

    /*

     * Array get, 32 bits or less.  vAA <- vBB[vCC].

     *

     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17

     * instructions.  We use a pair of FETCH_Bs instead.

     *

     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short

     */

    /* op vAA, vBB, vCC */

    FETCH_B(r2, 1, 0)                   @ r2<- BB

    mov     r9, rINST, lsr #8           @ r9<- AA

    FETCH_B(r3, 1, 1)                   @ r3<- CC

    GET_VREG(r0, r2)                    @ r0<- vBB (array object)

    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)

    cmp     r0, #0                      @ null array object?

    beq     common_errNullObject        @ yes, bail

// begin WITH_TAINT_TRACKING

    bl                .L${opcode}_taint_prop_1

// end WITH_TAINT_TRACKING

    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length

    add     r0, r0, r1, lsl #$shift     @ r0<- arrayObj + index*width

    cmp     r1, r3                      @ compare unsigned index, length

// begin WITH_TAINT_TRACKING

//    bcs     common_errArrayIndex        @ index >= length, bail        // in subroutine

//    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST // in subroutine

    bl                .L${opcode}_taint_prop_2

// end WITH_TAINT_TRACKING

    $load   r2, [r0, #offArrayObject_contents]  @ r2<- vBB[vCC]

    GET_INST_OPCODE(ip)                 @ extract opcode from rINST

    SET_VREG(r2, r9)                    @ vAA<- r2

    GOTO_OPCODE(ip)                     @ jump to next instruction

 

%break

 

.L${opcode}_taint_prop_1:

    ldr            r2, [r0, #offArrayObject_taint]   @獲取數組對象vBB的taint,賦給r2

    SET_TAINT_FP(r10)

    GET_VREG_TAINT(r3, r3, r10)                  @獲取索引數據vCC的taint,賦給r3

    orr            r2, r3, r2                  @ r2<- r2 | r1

    bx            lr

 

.L${opcode}_taint_prop_2:

    bcs     common_errArrayIndex        @ index >= length, bail

    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST

    SET_TAINT_FP(r3)

    SET_VREG_TAINT(r2, r9, r3)            @將r2(即此時的污點信息)賦值給vAA的taint tag

    bx      lr

 

顯然重點在*_taint_prop_1和*_taint_prop_2兩個代碼段。簡要概括它們的功能:

1)taint_prop_1首先取得數組對象vBB的taint。註意這裡offArrayObject_taint定義在dalvik/vm/common/asm-constants.h中:

#ifdef WITH_TAINT_TRACKING

MTERP_OFFSET(offArrayObject_taint,        ArrayObject, taint, 12) //結合ArrayObject數據結構,不難理解此代碼

#endif

 

MTERP_OFFSET巨集的定義如下:

# define MTERP_OFFSET(_name, _type, _field, _offset)                        \

    if (OFFSETOF_MEMBER(_type, _field) != _offset) {                        \

        ALOGE("Bad asm offset %s (%d), should be %d",                        \

            #_name, _offset, OFFSETOF_MEMBER(_type, _field));               \

        failed = true;                                                      \

    }

獲取了vBB的taint tag之後,再獲取索引vCC的taint tag,然後將兩者相或,最終結果賦給r2寄存器;

 

2)taint_prop_2再將此時的r2寄存器中的tag信息賦值給vAA的taint tag。這樣就完成了aget-object的污點傳播了。

 

至此整個DVM的變數級污點跟蹤機制我們都已經分析完畢,下一步就是分析Native層的方法級污點跟蹤,這裡給各位讀者預留一個問題:為什麼在DVM中可以實現變數街污點跟蹤,但是native層卻只能實現方法級污點跟蹤呢?

 

 作者:簡行、走位@阿裡聚安全,更多技術文章,請訪問阿裡聚安全博客

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 剛剛請教了一個php高手。就hao123.com 來舉例。因為要考慮到一個公司的多個app。所以 如下樣式,如果公司名稱簡稱xtz,app的 名稱簡稱cht xtz.hao123.com xtzcht.hao123.com 如果是測試的話:test_xtzcht.hao123.com baiduap ...
  • Mac下載並編譯Google安卓AOSP項目代碼 參考 這兩天用Mac下載安卓AOSP源碼,且把遇到的問題記下來。當然作為一個菜鳥,難免會有錯誤或者描述不對的地方,歡迎各路大神小神批評指正。轉載請註明出處。 一、準備環境 (請提前安裝好xcode或command line tools) Instal ...
  • If your unit test has no dependencies or only has simple dependencies on Android, you should run your test on a local development machine. This testin ...
  • 廢話不多說,直接進入主題: 這裡要說的方式有6種:1、屬性傳值 2、block 3、delegate 4、UserDefault 5、單例 6、通知(篇幅原因我只寫核心代碼,如果看不懂可以直接在最下麵去github 看demo) 1、block(個人覺得最常用的場景下最好用的) 先說我最常用的blo ...
  • Android tests are based on JUnit, and you can run them either as local unit tests on the JVM or as instrumented tests on an Android device. This page ...
  • 我的情況:模擬器 可以返回數據 。真機不可以。我手機連接的同事的共用,我以為他的網段和後臺的網段在同一個網段。一直在找錯誤,打開手機網路設置一看 ,原來不在同一網段。手機的網路必須要跟PC的在同一個網段才行。 ...
  • 電話撥號器(重點) 1.產品經理: 需求分析文檔,設計原型圖 2.UI工程師: 設計UI界面 3.架構師: 寫架構,介面文檔 4.碼農: 服務端,客戶端 1.寫佈局界面 2.寫業務邏輯 1.通過佈局文件中對控制項配置的id,在activity中可以獲取控制項的對象,Edittext Button fin ...
  • 1.線性佈局 LinearLayout orientation:方向;vertical,垂直;horizontal,水平 gravity:對齊方式,子控制項相對於當前控制項的對齊方式 layout_gravity:當前控制項相對於父控制項的對齊方式 margin:當前控制項相對於四周的間距。 padding: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...