taintdroid源码分析 三之 解释器污点传播

来源:互联网 发布:js代码怎么用 编辑:程序博客网 时间:2024/04/28 02:10

通过研究Dalvik指令格式和类型,将可能产生信息流指令分为16大类,如表1所示。其中vx,vy,vz是寄存器,fy,fz是字段ID,T()表示污点值。

序号

指令类型

指令含义

污点传播逻辑

污点传播描述

1

Move vx,vy

移动vy的内容到vx

T(vy)→T(vx)

将T(vy)复制到T(vx)

2

Return vx

返回在vx的值

T(vx) →T(∑)

将T(vx)返回

3

Const vx, lit32

将lit32值存入vx

T(vx)→0

清空污点

4

Throw vx

将出错信息返回vx

T(vx)→T(E)

设置出错污点

5

Iput vx,vy,fz

根据fz将vx值存入实例vy的int型字段

T(vx)|T(vy)→T(fz)

将T(vx) 与T(vy)存入实例int字段

6

Iget vx,vy,fz

根据fz读取实例vy的int型字段到vx

T(fz)|T(vy)→T(vx)

将T(vy)与实例int字段相与存入T(vx)

7

Sput vx,fy

根据fy将vx存入int型字段

T(vx)→T(fy)

将T(vx)复制到T(fy)

8

Sget vx,fy

根据fy读取int型字段到vx

T(fy)→T(vx)

将T(fy)复制到T(vx)

9

Aput vx,vy,vz

将vx值存入位于vy的数组引用且索引位置为vz

T(vx)→T(vy)

将T(vx)复制数组污点

10

Aget vz,vy,vz

从位于vy的数组引用获取索引位置为vz的int型值存入vx

T(vy)→T(vx)

将数组污点复制到T(vx)

11

And vx,vy,vz

将vy|vz并存入vx

T(vy)|T(vz)→T(vx)

将T(vy)与T(vz)相与并存入T(vx)

12

Add vx,vy,vz

计算vy+vz并存入vx

T(vy)|T(vz)→T(vx)

将T(vy)与T(vz)相与并存入T(vx)

13

If-lt vx,vy,0080

如果vx<vy,跳转到目标0080

T(vx)|T(vy)→T(vy) ∪T(vx)

将T(vx)与T(vy)相与并更新各自污点

14

Int-to-long vx,vy

将vy中int值转换long并保存到vx,vx+1

T(vy)→T(vx)

将T(vy)复制到T(vx)

15

Neg vx,vy

计算vx=-vy并保存在vx

T(vy)→T(vx)

将T(vy)复制到T(vx)

16

Cmpl vx,vy,vz

比较vy和vz的值并在vz存入int型返回值

T(vy)|T(vz)→T(vz)∪T(vy) ∪T(vz)

将T(vy)与T(vz)相与更新各自污点并存入T(vz)


相对于taintdroid,其跟踪指令并没有13,15,16,所以聪明的人可能会通过这几类指令使得污点能够脱离跟踪,从而不能报告隐私泄露。

taintdroid是如何跟踪的呢,在此解释两种不同实现方式:

C 实现主要思想用C重写对栈的操作,定义如下宏:

# define GET_REGISTER_TAINT(_idx)     (fp[((_idx)<<1)+1])
# define SET_REGISTER_TAINT(_idx, _val)     (fp[((_idx)<<1)+1] = (u4)(_val))
# define GET_REGISTER_TAINT_WIDE(_idx)       (fp[((_idx)<<1)+1])
# define SET_REGISTER_TAINT_WIDE(_idx, _val) (fp[((_idx)<<1)+1] = \
                                     fp[((_idx)<<1)+3] = (u4)(_val))
/* Alternate interfaces to help dereference register width */
# define GET_REGISTER_TAINT_INT(_idx)          GET_REGISTER_TAINT(_idx)
# define SET_REGISTER_TAINT_INT(_idx, _val)       SET_REGISTER_TAINT(_idx, _val)
# define GET_REGISTER_TAINT_FLOAT(_idx)          GET_REGISTER_TAINT(_idx)
# define SET_REGISTER_TAINT_FLOAT(_idx, _val)     SET_REGISTER_TAINT(_idx, _val)
# define GET_REGISTER_TAINT_DOUBLE(_idx)          GET_REGISTER_TAINT_WIDE(_idx)
# define SET_REGISTER_TAINT_DOUBLE(_idx, _val)    SET_REGISTER_TAINT_WIDE(_idx, _val)
# define GET_REGISTER_TAINT_AS_OBJECT(_idx)       GET_REGISTER_TAINT(_idx)
# define SET_REGISTER_TAINT_AS_OBJECT(_idx, _val) SET_REGISTER_TAINT(_idx, _val)
/* Object Taint interface */
# define GET_ARRAY_TAINT(_arr)      ((_arr)->taint.tag)
# define SET_ARRAY_TAINT(_arr, _val)      ((_arr)->taint.tag = (u4)(_val))
/* Return value taint (assumes rtaint variable is in scope */
# define GET_RETURN_TAINT()      (rtaint.tag)
# define SET_RETURN_TAINT(_val)      (rtaint.tag = (u4)(_val))

例如对于加法指令:

#define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv)               \
    HANDLE_OPCODE(_opcode /*vA, vB*/) 

其实现的C 代码如下:


 vdst = INST_A(inst);                                                \
        vsrc1 = INST_B(inst);                                               \
        ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1);             \
        if (_chkdiv != 0) {                                                 \
            s4 firstVal, secondVal, result;                                 \
            firstVal = GET_REGISTER(vdst);                                  \
            secondVal = GET_REGISTER(vsrc1);                                \
            if (secondVal == 0) {                                           \
                EXPORT_PC();                                                \
                dvmThrowArithmeticException("divide by zero");              \
                GOTO_exceptionThrown();                                     \
            }                                                               \
            if ((u4)firstVal == 0x80000000 && secondVal == -1) {            \
                if (_chkdiv == 1)                                           \
                    result = firstVal;  /* division */                      \
                else                                                        \
                    result = 0;         /* remainder */                     \
            } else {                                                        \
                result = firstVal _op secondVal;                            \
            }                                                               \
            SET_REGISTER(vdst, result);                                     \
        } else {                                                            \
            SET_REGISTER(vdst,                                              \
                (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1));      \
        } 

为完成相应的污点操作,则可依据定义的宏进行栈中污点位置的操作如下:


   SET_REGISTER_TAINT(vdst,                                            \
   (GET_REGISTER_TAINT(vdst)|GET_REGISTER_TAINT(vsrc1)) ); 

一目了然。



对于其用汇编语言实现,则较为复杂,难于理解一些,但如若对arm汇编比较了解,学习过编译原理的则能较好理解,毕竟汇编实现要快很多。

首先要了解的是汇编对于寄存器的分配:

在硬件上arm如下分配寄存器:

r0-r3 hold first 4 args to a method; they are not preserved across method calls
r4-r8 are available for general use
r9 is given special treatment in some situations, but not for us
r10 (sl) seems to be generally available
r11 (fp) is used by gcc (unless -fomit-frame-pointer is set)
r12 (ip) is scratch -- not preserved across method calls
r13 (sp) should be managed carefully in case a signal arrives
r14 (lr) must be preserved
r15 (pc) can be tinkered with directly

但dalvik则不这样进行分配,其如下分配和定义:

  reg nick      purpose
  r4  rPC       interpreted program counter, used for fetching instructions
  r5  rFP       interpreted frame pointer, used for accessing locals and args
  r6  rSELF     self (Thread) pointer
  r7  rINST     first 16-bit code unit of current instruction
  r8  rIBASE    interpreted instruction base pointer, used for computed goto

由此可以这样定义对栈污点的操作:

#define SET_TAINT_FP(_reg)      add     _reg, rFP, #4
#define SET_TAINT_CLEAR(_reg)   mov     _reg, #0
#define GET_VREG(_reg, _vreg)   ldr     _reg, [rFP, _vreg, lsl #3]
#define SET_VREG(_reg, _vreg)   str     _reg, [rFP, _vreg, lsl #3]
#define GET_VREG_TAINT(_reg, _vreg, _rFP)   ldr     _reg, [_rFP, _vreg, lsl #3]
#define SET_VREG_TAINT(_reg, _vreg, _rFP)   str     _reg, [_rFP, _vreg, lsl #3]
#else
#define GET_VREG(_reg, _vreg)   ldr     _reg, [rFP, _vreg, lsl #2]
#define SET_VREG(_reg, _vreg)   str     _reg, [rFP, _vreg, lsl #2]

其操作语义也比较好理解,不再多说。

由此对于加法指令:

 /* binop vAA, vBB, vCC */
    FETCH(r0, 1)                        @ r0<- CCBB
    mov     r9, rINST, lsr #8           @ r9<- AA
    mov     r3, r0, lsr #8              @ r3<- CC
    and     r2, r0, #255                @ r2<- BB
    GET_VREG(r1, r3)                    @ r1<- vCC
    GET_VREG(r0, r2)                    @ r0<- vBB
    .if 0
    cmp     r1, #0                      @ is second operand zero?
    beq     common_errDivideByZero
    .endif

    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
                               @ optional op; may set condition codes
    add     r0, r0, r1                              @ r0<- op, r0-r3 changed
    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
    SET_VREG(r0, r9)               @ vAA<- r0
    GOTO_OPCODE(ip)                     @ jump to next instruction
    /* 11-14 instructions */

即可在Fetch之前加入污点传播指令

 .LOP_ADD_INT_taint_prop


其定义为,

.LOP_ADD_INT_taint_prop:
    SET_TAINT_FP(r10)
    GET_VREG_TAINT(r3, r3, r10)
    GET_VREG_TAINT(r2, r2, r10)
    orr     r2, r3, r2     
    SET_VREG_TAINT(r2, r9, r10)
    bx      lr

这些结合前面定义都比较好理解:设置污点fp,取两源数据的污点,污点相与实现传播,然后将污点保存。

这样对于其它指令也可以很好理解,至此应该就了解了全部的程序变量级别的污点传播,和方法调用的污点传播过程

方法调用污点传播再附一图如下:










0 0
原创粉丝点击