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层却只能实现方法级污点跟踪呢?

作者:简行、走位@阿里聚安全,更多技术文章,请访问阿里聚安全博客

TaintDroid剖析之DVM变量级污点跟踪(下篇)的更多相关文章

  1. TaintDroid剖析之Native方法级污点跟踪分析

    1.Native方法的污点传播 在前两篇文章中我们详细分析了TaintDroid对DVM栈帧的修改,以及它是如何在修改之后的栈帧中实现DVM变量级污点跟踪的.现在我们继续分析其第二个粒度的污点跟踪—— ...

  2. TaintDroid剖析之File & Memiry & Socket级污点传播

    TaintDroid剖析之File & Memiry & Socket级污点传播 作者:简行.走位@阿里聚安全 1.涉及到的代码文件 TaintDroid在File, Memory以及 ...

  3. TaintDroid剖析之IPC级污点传播

    TaintDroid剖析之IPC级污点传播 作者:简行.走位@阿里聚安全 前言 在前三篇文章中我们详细分析了TaintDroid对DVM栈帧的修改,以及它是如何在修改之后的栈帧中实现DVM变量级污点跟 ...

  4. TaintDroid:智能手机监控实时隐私信息流跟踪系统(一)

    1.1     摘要 现今,智能手机操作系统不能有效的提供给用户足够的控制权并且很清楚的了解到第三方的应用程序是如何使用其的隐私数据.我们使用了TaintDroid来阐明这个缺点,其是一个高效的,全系 ...

  5. TaintDroid:智能手机监控实时隐私信息流跟踪系统(三)

    4.3   原生代码标记传播 Native 代码是不受TaintDroid监控的.理想情况下,我们获得了相同的传播语义当使用相同的解释副本时.因此,为了精确的在Java层进行污点监控,我们定义了两个必 ...

  6. TaintDroid:智能手机监控实时隐私信息流跟踪系统(四)

    6      应用程序研究 款流行的应用程序是怎么使用用户敏感数据的.选取的应用程序可以根据相应的权限通过Internet获得各种各样的用户数据.我们研究发现三分之二的这些数据暴露了用户详细的地理位置 ...

  7. TaintDroid深入剖析之启动篇

    ​1 背景知识 1.1   Android平台软件动态分析现状 众所周知,在计算机领域中所有的软件分析方法都可以归为静态分析和动态分析两大类,在Android平台也不例外.而随着软件加固.混淆技术的不 ...

  8. 开始写Effective系列总结一些前端的心得

    确实是没有时间整理以及总结和发表自己的感慨.难得中秋银行的事情搞完了自己清闲3天,是时候总结一下从大公司做.NET PC 端网站的开发到现在做移动互联网的银行及政府微信公众号的开发的感触.当时自己的选 ...

  9. TaintDroid简介

    1.Information-Flow tracking,Realtime Privacy Monitoring.信息流动追踪,实时动态监控. 2.TaintDroid是一个全系统动态污点跟踪和分析系统 ...

随机推荐

  1. 【Java EE 学习 77 上】【数据采集系统第九天】【通过AOP实现日志管理】【通过Spring石英调度动态生成日志表】【日志分表和查询】

    一.需求分析 日志数据在很多行业中都是非常敏感的数据,它们不能删除只能保存和查看,这样日志表就会越来越大,我们不可能永远让它无限制的增长下去,必须采取一种手段将数据分散开来.假设现在整个数据库需要保存 ...

  2. Ext.js的store里放model,还是field?

    按别人的经验, 一般来说,如果通用性强的应用,STORE里存放MODEL,便于重用代码. 如果通用性较弱的(报告,图表),则考虑使用field进行定制.

  3. 3 3Sum closest_Leetcode

    Given an array S of n integers, find three integers in S such that the sum is closest to a given num ...

  4. DataGridView控件行标题显示序号

    Rectangle rectangle = new Rectangle(e.RowBounds.Location.X, e.RowBounds.Location.Y, dataGridViewX1.R ...

  5. centos配置虚拟主机

    首先注释掉 DocumentRoot /var/www/html 然后添加如下代码至文件底部:       NameVirtualHost 192.168.0.3     <virtualhos ...

  6. QT5之三大重要窗体

    当创建项目时,会发现编辑器提供三个基类,分别为:QMainWindow.QWidget.QDialog,三个基类的区别说明如下.1.QMainWindowQMainWindow类提供一个有菜单条.锚接 ...

  7. 写给Git初学者的7个建议

    [原文] - http://blog.jobbole.com/50603/ 当我刚刚开始使用Git的版本控制时,我根本不确定我付出那么多时间是不是会得到回报.Branch.Stage.Stash,这些 ...

  8. js中push(),pop(),unshift(),shift()的用法小结

    1.push().pop()和unshift().shift() 这两组同为对数组的操作,并且会改变数组的本身的长度及内容. 不同的是 push().pop() 是从数组的尾部进行增减,unshift ...

  9. strong,weak, retain, assign的区别

    strong,weak, retain, assign的区别 strong与weak是由ARC新引入的对象变量属性 xcode 4.2(ios sdk4.3和以下版本)和之前的版本使用的是retain ...

  10. android 常用URI

    关于联系人的一些URI: 管理联系人的Uri: ContactsContract.Contacts.CONTENT_URI 管理联系人的电话的Uri: ContactsContract.CommonD ...