摘要:回顧在上一章節(jié)中我們?cè)敿?xì)分析了對(duì)方法參數(shù)和方法變量的變量級(jí)污點(diǎn)跟蹤機(jī)制,現(xiàn)在我們將繼續(xù)分析對(duì)類的靜態(tài)域?qū)嵗蛞约皵?shù)組的污點(diǎn)跟蹤。充分理解這一點(diǎn),對(duì)我們后續(xù)分析復(fù)雜污點(diǎn)傳播邏輯很有幫助。對(duì)數(shù)組對(duì)象的修改在成員之后添加成員。
1 回顧
在上一章節(jié)中我們?cè)敿?xì)分析了TaintDroid對(duì)DVM方法參數(shù)和方法變量的變量級(jí)污點(diǎn)跟蹤機(jī)制,現(xiàn)在我們將繼續(xù)分析TaintDroid對(duì)類的靜態(tài)域、實(shí)例域以及數(shù)組的污點(diǎn)跟蹤。
2 了解DVM中類的數(shù)據(jù)結(jié)構(gòu)由于DVM師從JVM,所以DVM中所有類的祖先也是Object類,該類定義在dalvik/vm/oo/Object.h中。其實(shí)不僅僅是Object類,DVM所有的基本類都定義在Object.h文件中。
眾所周知,Object類共分三種類型:
Class Objects,它是java.lang.Class的實(shí)例,此類object的公共基類是ClassObject;
Array Objects,由new Array指令創(chuàng)建,此類object的公共基類是ArrayObject;
Data Objects,除了上面兩種Object之外的所有object,公共基類是DataObject。
這里有一個(gè)特例需要注意,那就是String Objects!String Objects當(dāng)前等同于Data Objects,但鑒于該類在DVM中大量使用,因此DVM多帶帶定義了一個(gè)類StringObject,它直接繼承至Object。
了解了類的數(shù)據(jù)結(jié)構(gòu),再去分析TaintDroid對(duì)類的靜態(tài)域、實(shí)例域和數(shù)組的污點(diǎn)跟蹤就不會(huì)覺(jué)得無(wú)從下手了。
3 對(duì)各種數(shù)據(jù)結(jié)構(gòu)的修改要想實(shí)現(xiàn)對(duì)類的實(shí)例域和靜態(tài)域的污點(diǎn)跟蹤,最簡(jiǎn)單粗暴的方式就是對(duì)類中相關(guān)的數(shù)據(jù)結(jié)構(gòu)進(jìn)行修改。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默認(rèn)為4。倍增的空間用于交叉存儲(chǔ)各個(gè)實(shí)例域的污點(diǎn)。聯(lián)想到類的實(shí)例域有兩種類型:1)諸如int之類的基本類型;2)類對(duì)象的引用。所以我們可以知道,TaintDroid為每個(gè)引用也分配了一個(gè)tag,用于表示該引用的污點(diǎn)信息。充分理解這一點(diǎn),對(duì)我們后續(xù)分析復(fù)雜污點(diǎn)傳播邏輯很有幫助。
2)其次,修改了靜態(tài)域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;
通過(guò)這樣的修改,再對(duì)涉及到操作這些數(shù)據(jù)結(jié)構(gòu)的方法進(jìn)行修復(fù)就能實(shí)現(xiàn)類的實(shí)例域和靜態(tài)域的污點(diǎn)跟蹤了。這里以computeFieldOffsets函數(shù)為例,此函數(shù)定義在dalvik/vm/oo/Class.cpp中,由于代碼較多,僅截取部分修復(fù)相關(guān)部分:
…… 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 */ }
顯然,在計(jì)算類中各個(gè)實(shí)例域的偏移值的時(shí)候,由于TaintDroid對(duì)實(shí)例域的空間進(jìn)行了倍增(交叉存儲(chǔ)污點(diǎn)),所以這里應(yīng)該加上2sizeof(u4)。另外需要注意的是對(duì)于Double和Long類型的數(shù)據(jù),要加上4sizeof(u4)!
至此類的實(shí)例域和靜態(tài)域的污點(diǎn)跟蹤分析完畢,下一步輪到數(shù)組了。
3)對(duì)數(shù)組對(duì)象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成員。之所以這樣做,是因?yàn)槌鲇谛阅艿目紤]:如果數(shù)組中每個(gè)成員都存儲(chǔ)一個(gè)tag的話,對(duì)性能的影響就太大了,所以TaintDroid對(duì)每個(gè)ArrayObject對(duì)象只分配一個(gè)tag。
同樣的,修改了ArrayObject的結(jié)構(gòu)體,就必須同步修改涉及到對(duì)ArrayObject進(jìn)行操作的函數(shù)。這里以oo/Array.cpp中的allocArray函數(shù)為例:
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); } }
在分配一個(gè)新的數(shù)組的時(shí)候,TaintDroid將它的taint成員賦值為TAINT_CLEAR(即清空污點(diǎn)信息)。
4)特殊類StringObject的結(jié)構(gòu)分析。它的結(jié)構(gòu)體如下:
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提供了一個(gè)方法array(),此方法返回一個(gè)ArrayObject型指針,所以在獲取和設(shè)置StringObject的污點(diǎn)信息的時(shí)候,需要通過(guò)StringObject.array()->taint.tag進(jìn)行操作。
4 進(jìn)一步分析DVM污點(diǎn)傳播邏輯在前一章節(jié)中,我們分析了兩參數(shù)相加的DVM opcode(OP_ADD_INT_2ADDR),這是因?yàn)槲覀儺?dāng)時(shí)對(duì)類的靜態(tài)域、實(shí)例域以及數(shù)組的污點(diǎn)存儲(chǔ)并不熟悉,所以也就僅僅能捏一捏這類軟柿子而已,現(xiàn)在我們挑戰(zhàn)一下更高難度的數(shù)組操作相關(guān)的opcode——OP_AGET_OBJECT(即aget-obj)。該opcode的匯編實(shí)現(xiàn)在dalvik/vm/mterp/armv*te_taint/OP_AGET_OBJECT.S文件中:
%verify "executed" %include "armv5te_taint/OP_AGET.S"
轉(zhuǎn)到OP_AGET.S:
%default { "load":"ldr", "shift":"2" } //表示移位基準(zhǔn)為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] @獲取數(shù)組對(duì)象vBB的taint,賦給r2 SET_TAINT_FP(r10) GET_VREG_TAINT(r3, r3, r10) @獲取索引數(shù)據(jù)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(即此時(shí)的污點(diǎn)信息)賦值給vAA的taint tag bx lr
顯然重點(diǎn)在*_taint_prop_1和*_taint_prop_2兩個(gè)代碼段。簡(jiǎn)要概括它們的功能:
1)taint_prop_1首先取得數(shù)組對(duì)象vBB的taint。注意這里offArrayObject_taint定義在dalvik/vm/common/asm-constants.h中:
#ifdef WITH_TAINT_TRACKING MTERP_OFFSET(offArrayObject_taint, ArrayObject, taint, 12) //結(jié)合ArrayObject數(shù)據(jù)結(jié)構(gòu),不難理解此代碼 #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,然后將兩者相或,最終結(jié)果賦給r2寄存器;
2)taint_prop_2再將此時(shí)的r2寄存器中的tag信息賦值給vAA的taint tag。這樣就完成了aget-object的污點(diǎn)傳播了。
至此整個(gè)DVM的變量級(jí)污點(diǎn)跟蹤機(jī)制我們都已經(jīng)分析完畢,下一步就是分析Native層的方法級(jí)污點(diǎn)跟蹤,這里給各位讀者預(yù)留一個(gè)問(wèn)題:為什么在DVM中可以實(shí)現(xiàn)變量街污點(diǎn)跟蹤,但是native層卻只能實(shí)現(xiàn)方法級(jí)污點(diǎn)跟蹤呢?
作者:簡(jiǎn)行、走位@阿里聚安全,更多技術(shù)文章,請(qǐng)?jiān)L問(wèn)阿里聚安全博客
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/11204.html
摘要:前言在前三篇文章中我們?cè)敿?xì)分析了對(duì)棧幀的修改,以及它是如何在修改之后的棧幀中實(shí)現(xiàn)變量級(jí)污點(diǎn)跟蹤方法級(jí)跟蹤。總結(jié)的污點(diǎn)跟蹤粒度是變量粒度的,因此大大提高了污點(diǎn)傳播的精準(zhǔn)度。下一步繼續(xù)分析下級(jí)污點(diǎn)傳播。 前言 在前三篇文章中我們?cè)敿?xì)分析了TaintDroid對(duì)DVM棧幀的修改,以及它是如何在修改之后的棧幀中實(shí)現(xiàn)DVM變量級(jí)污點(diǎn)跟蹤、Native方法級(jí)跟蹤。本篇文章我們來(lái)分析下IPC級(jí)污點(diǎn)傳...
摘要:后文將圍繞做一些介紹。盡管如此,的使用對(duì)新手而言仍然充滿了困難。本系列文章基本為個(gè)人見(jiàn)解,難免有錯(cuò)誤與誤解,如有客觀錯(cuò)誤歡迎提出。 前言 說(shuō)到Android的污點(diǎn)分析框架,網(wǎng)上的搜索結(jié)果大多指向靜態(tài)的FlowDroid與動(dòng)態(tài)的TaintDroid。盡管由于加固、混淆等技術(shù)使得針對(duì)Android的靜態(tài)分析越來(lái)越困難,但靜態(tài)分析的無(wú)先驗(yàn)分析能力無(wú)法被動(dòng)態(tài)分析取代,使得靜態(tài)分析仍有發(fā)揮空間。...
閱讀 2106·2023-05-11 16:55
閱讀 3504·2021-08-10 09:43
閱讀 2618·2019-08-30 15:44
閱讀 2440·2019-08-29 16:39
閱讀 583·2019-08-29 13:46
閱讀 2006·2019-08-29 13:29
閱讀 921·2019-08-29 13:05
閱讀 691·2019-08-26 13:51