DalvikBytecodeAnalysis/src/main/scala/analysis/InstructionAnalyzer.scala

843 lines
26 KiB
Scala

package analysis
import com.microsoft.z3._
import com.typesafe.scalalogging.StrictLogging
import constraints.Z3Constraint
import dex.DexType.{PrimitiveType, ObjectType, VoidType}
import dex.{DexClass, DexMethod, DexType}
import org.jf.dexlib2.dexbacked.reference.{
DexBackedStringReference,
DexBackedTypeReference
}
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.formats._
import org.jf.dexlib2.iface.reference.MethodReference
import utils.Utils
object InstructionAnalyzer extends StrictLogging {
/**
* Do nothing. All registers at pp+ approximates the registers at pp.
*/
def nop(i: Instruction, pp: PP, env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val rPlus = env.R(pp +)
Seq(
Z3Constraint(
env.ctx.mkAnd(r <= rPlus: _*),
s"R($pp) <= R(${pp +})",
pp
)
)
}
def const4(i: Instruction11n, pp: PP, env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val rPlus = env.R(pp +)
val rApprox = r.<=(i.getRegisterA)(rPlus)
Seq(
Z3Constraint(
env.domains.primitiveDomain.approx(
env.domains.primitiveDomain.toElement(i.getWideLiteral.toInt),
rPlus.numbers(i.getRegisterA)
),
s"${i.getWideLiteral} <= R(${pp +})(${i.getRegisterA})",
pp
),
Z3Constraint(
env.ctx.mkAnd(rApprox: _*),
s"R($pp) <={${i.getRegisterA}} R(${pp +})",
pp
)
)
}
def constString(i: Instruction21c,
pp: PP,
env: Environment): Seq[Z3Constraint] = {
constString(
i.getRegisterA,
i.getReference.asInstanceOf[DexBackedStringReference].getString,
pp,
env
)
}
def constStringJumbo(i: Instruction31c,
pp: PP,
env: Environment): Seq[Z3Constraint] = {
constString(
i.getRegisterA,
i.getReference.asInstanceOf[DexBackedStringReference].getString,
pp,
env
)
}
/**
* Make the register A approximates str.
* Constant strings are treated like instances of Ljava/lang/String;
*/
private def constString(registerA: Int,
str: String,
pp: PP,
env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val rPlus = env.R(pp +)
Seq(
Z3Constraint(
env.domains.referenceDomain.approx(
env.domains.referenceDomain.toElement(pp.toString),
rPlus.references(registerA)
),
s"($pp) <= R(${pp +})($registerA)",
pp
),
Z3Constraint(
env.ctx.mkAnd(r.<=(registerA)(rPlus): _*),
s"R($pp) <={$registerA} R(${pp +})",
pp
)
)
}
def iput(i: Instruction22c, pp: PP, env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val rPlus = env.R(pp +)
val rApprox = r.<=(rPlus)
val fieldRef = i.getReference.toString
val cName = Utils.classPrefix(fieldRef)
val fieldName = Utils.removeClassPrefix(fieldRef)
val fieldType = DexType(fieldName.substring(fieldName.indexOf(":") + 1))
val classes = classAndSubclasses(env)(cName)
val obj: FuncDecl = env.H.obj()
val objApp = env.ctx.mkApp(obj, env.ctx.mkString(pp.toString))
val accessor: FuncDecl = fieldType match {
case PrimitiveType() =>
env.z3Obj.primAccessor
}
val objFields =
env.ctx.mkApp(accessor, objApp).asInstanceOf[ArrayExpr]
val constraints: Seq[Z3Constraint] = classes.flatMap(
c =>
env.preAnalysisResult.objectCreation
.filter(p => p._2 == c.name)
.map(objPP => {
Z3Constraint(
env.ctx.mkImplies(
env.ctx.mkAnd(
env.domains.referenceDomain.approx(
env.domains.referenceDomain.toElement(objPP._1.toString),
r.references(i.getRegisterB)
)
),
fieldType match {
case PrimitiveType() =>
env.domains.primitiveDomain.approx(
r.numbers(i.getRegisterA),
env.ctx
.mkSelect(objFields, env.ctx.mkString(fieldName))
.asInstanceOf[env.domains.primitiveDomain.Element]
)
}
),
s"${objPP._1.toString} <= R($pp)(${i.getRegisterB}) => " +
s"R($pp)(${i.getRegisterA}) <= H($objPP).$fieldName",
pp
)
})
)
constraints ++ Seq(
Z3Constraint(
env.ctx.mkAnd(rApprox: _*),
s"R($pp) <= R(${pp +})",
pp
)
)
}
def sgetObject(i: Instruction21c,
pp: PP,
env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val rPlus = env.R(pp +)
val sFieldRef = i.getReference.toString
val cName = Utils.classPrefix(sFieldRef)
val sFieldName = Utils.removeClassPrefix(sFieldRef)
val sFieldType = DexType(sFieldName.substring(sFieldName.indexOf(":") + 1))
val dexClass = env.app.classes.find(c => c.name == cName)
val (sFieldVal, sFieldTaint): (Expr, Expr) = dexClass match {
case Some(c) =>
val f = c.fields.find(dexField => dexField.name == sFieldName).get
env.SH(c, f)
case None =>
// Unknown class, use top as value.
sFieldType match {
case PrimitiveType() =>
(env.domains.primitiveDomain.top, env.domains.taintDomain.top)
case ObjectType(_) =>
(env.domains.referenceDomain.top, env.domains.taintDomain.top)
}
}
Seq(
Z3Constraint(
sFieldType match {
case PrimitiveType() =>
env.domains.primitiveDomain.approx(
sFieldVal.asInstanceOf[env.domains.primitiveDomain.Element],
rPlus.numbers(i.getRegisterA)
)
case ObjectType(_) =>
env.domains.referenceDomain.approx(
sFieldVal.asInstanceOf[env.domains.referenceDomain.Element],
rPlus.references(i.getRegisterA)
)
},
s"SH($cName,$sFieldName) <= R(${pp +})(${i.getRegisterA})",
pp
),
Z3Constraint(
env.domains.taintDomain.approx(
sFieldTaint.asInstanceOf[env.domains.taintDomain.Element],
rPlus.taints(i.getRegisterA)
),
s"Taint R($pp)(${i.getRegisterA}) if SH($cName,$sFieldName) is tainted",
pp
),
Z3Constraint(
env.ctx.mkAnd(r.<=(i.getRegisterA)(rPlus): _*),
s"R($pp) <={${i.getRegisterA}} R(${pp +})",
pp
)
)
}
def sputObject(i: Instruction21c,
pp: PP,
env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val rPlus = env.R(pp +)
val sFieldRef = i.getReference.toString
val cName = Utils.classPrefix(sFieldRef)
val sFieldName = Utils.removeClassPrefix(sFieldRef)
val sFieldType = DexType(sFieldName.substring(sFieldName.indexOf(":") + 1))
val dexClass = env.app.classes.find(c => c.name == cName)
val (sFieldVal, sFieldTaint): (Expr, Expr) = dexClass match {
case Some(c) =>
val f = c.fields.find(dexField => dexField.name == sFieldName).get
env.SH(c, f)
case None =>
// Unknown class, use top as value.
sFieldType match {
case PrimitiveType() =>
(env.domains.primitiveDomain.top, env.domains.taintDomain.top)
case ObjectType(_) =>
(env.domains.referenceDomain.top, env.domains.taintDomain.top)
}
}
Seq(
Z3Constraint(
sFieldType match {
case PrimitiveType() =>
env.domains.primitiveDomain.approx(
r.numbers(i.getRegisterA),
sFieldVal.asInstanceOf[env.domains.primitiveDomain.Element]
)
case ObjectType(_) =>
env.domains.referenceDomain.approx(
r.references(i.getRegisterA),
sFieldVal.asInstanceOf[env.domains.referenceDomain.Element]
)
},
s"R($pp)(${i.getRegisterA}) <= SH($cName,$sFieldName)",
pp
),
Z3Constraint(
env.domains.taintDomain.approx(
r.taints(i.getRegisterA),
sFieldTaint.asInstanceOf[env.domains.taintDomain.Element]
),
s"Taint SH($cName,$sFieldName) if R($pp)(${i.getRegisterA}) is tainted",
pp
),
Z3Constraint(
env.ctx.mkAnd(r <= rPlus: _*),
s"R($pp) <= R(${pp +})",
pp
)
)
}
def move(i: Instruction12x, pp: PP, env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val rPlus = env.R(pp +)
val rApprox = r.<=(i.getRegisterA)(rPlus)
Seq(
Z3Constraint(
env.ctx.mkAnd(
r.<=(i.getRegisterB, i.getRegisterA)(rPlus): _*
),
s"R($pp)(${i.getRegisterB}) <= R(${pp +})(${i.getRegisterA})",
pp
),
Z3Constraint(
env.ctx.mkAnd(rApprox: _*),
s"R($pp) <={${i.getRegisterA}} R(${pp +})",
pp
)
)
}
def moveResult(i: Instruction11x,
pp: PP,
env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val rPlus = env.R(pp +)
val rApprox = r.<=(i.getRegisterA)(rPlus)
Seq(
Z3Constraint(
env.ctx.mkAnd(
r.<=(env.R.retIdx, i.getRegisterA)(rPlus): _*
),
s"R($pp)(ret) <= R(${pp +})(${i.getRegisterA})",
pp
),
Z3Constraint(
env.ctx.mkAnd(rApprox: _*),
s"R($pp) <={${i.getRegisterA}} R(${pp +})",
pp
)
)
}
def goto(i: Instruction10t, pp: PP, env: Environment): Seq[Z3Constraint] = {
val ppGoto = pp.copy(pc = pp.pc + i.getCodeOffset)
Seq(
Z3Constraint(
env.ctx.mkAnd(env.R(pp) <= env.R(ppGoto): _*),
s"$pp: R($pp) <= R($ppGoto)",
pp
)
)
}
def retVoid(i: Instruction10x,
pp: PP,
env: Environment): Seq[Z3Constraint] = {
Seq()
}
def ret(i: Instruction11x, pp: PP, env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val mResult = env.M(pp.c, pp.m).get
pp.m.returnType match {
case PrimitiveType() =>
Seq(
Z3Constraint(
env.domains.primitiveDomain.approx(
r.numbers(i.getRegisterA),
mResult.asInstanceOf[env.domains.primitiveDomain.Element]
),
s"$pp: R($pp)(${i.getRegisterA}) <= M(${pp.c.name}, ${pp.m.name})",
pp
)
)
}
}
def ifEq(i: Instruction22t, pp: PP, env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val ppGoto = pp.copy(pc = pp.pc + i.getCodeOffset)
Seq(
Z3Constraint(
env.ctx.mkAnd(r <= env.R(ppGoto): _*),
s"$pp: R($pp) <= R(${pp +})",
pp
),
Z3Constraint(
env.ctx.mkAnd(r <= env.R(pp +): _*),
s"$pp: R($pp) <= R($ppGoto)",
pp
)
)
}
def newInstance(i: Instruction21c,
pp: PP,
env: Environment): Seq[Z3Constraint] = {
val r = env.R(pp)
val objType = i.getReference.asInstanceOf[DexBackedTypeReference].getType
val obj: FuncDecl = env.H.obj()
val objApp = env.ctx.mkApp(obj, env.ctx.mkString(pp.toString))
val objName =
env.ctx.mkApp(env.z3Obj.nameAccessor, objApp).asInstanceOf[SeqExpr]
val primFields =
env.ctx.mkApp(env.z3Obj.primAccessor, objApp).asInstanceOf[ArrayExpr]
val fieldsInitialization: List[Z3Constraint] =
env.app.classes.find(c => c.name == objType) match {
case Some(dexClass) =>
dexClass.fields
.map(dexField =>
dexField.dexType match {
case PrimitiveType() =>
Z3Constraint(
env.domains.primitiveDomain.approx(
env.domains.primitiveDomain.toElement(0),
env.ctx
.mkSelect(primFields, env.ctx.mkString(dexField.name))
.asInstanceOf[env.domains.primitiveDomain.Element]
),
s"0 <= H($pp).${dexField.name}",
pp
)
case ObjectType(_) =>
Z3Constraint(
env.ctx.mkTrue(),
"true",
pp
)
})
.toList
case None => List()
}
val instanceClass = Z3Constraint(
env.ctx.mkEq(objName, env.ctx.mkString(objType)),
s"H($pp) = {'$objType',(f->_)^*}",
pp
)
val rPlus = env.R(pp +)
// Register A of pp+ contains the object pointer (pp).
val storeReference =
Z3Constraint(
env.domains.referenceDomain.approx(
env.domains.referenceDomain.toElement(pp.toString),
rPlus.references(i.getRegisterA)
),
s"($pp) <= R(${pp +})(${i.getRegisterA})",
pp
)
val regApprox = Z3Constraint(
env.ctx.mkAnd(r.<=(i.getRegisterA)(rPlus): _*),
s"R($pp) <={${i.getRegisterA}} R(${pp +})",
pp
)
Seq(
instanceClass,
storeReference,
regApprox
) ++ fieldsInitialization
}
private def approxParam(env: Environment)(
pp: PP,
register: Int,
dexClass: DexClass,
dexMethod: DexMethod,
paramIdx: Int
): Z3Constraint = {
val r = env.R(pp)
val ppMethod = PP(dexClass, dexMethod, 0)
val rMethod = env.R(ppMethod)
val methodParamIdx = dexMethod.localRegistersCount + paramIdx
Z3Constraint(
env.ctx.mkAnd(
r.<=(register, methodParamIdx)(rMethod): _*
),
s"R($pp)($register) <= R($ppMethod)($methodParamIdx)",
pp
)
}
private def approxParameters(env: Environment)(
i: Instruction35c,
pp: PP,
dexClass: DexClass,
dexMethod: DexMethod): List[Z3Constraint] = {
var paramApprox: List[Z3Constraint] = List()
val regCount = i.getRegisterCount
if (regCount > 1) {
paramApprox = approxParam(env)(pp, i.getRegisterD, dexClass, dexMethod, 0) :: paramApprox
if (regCount > 2) {
paramApprox = approxParam(env)(
pp,
i.getRegisterE,
dexClass,
dexMethod,
1
) :: paramApprox
if (regCount > 3) {
paramApprox = approxParam(env)(
pp,
i.getRegisterF,
dexClass,
dexMethod,
2
) :: paramApprox
if (regCount > 4) {
paramApprox = approxParam(env)(
pp,
i.getRegisterG,
dexClass,
dexMethod,
3
) :: paramApprox
}
}
}
}
paramApprox.reverse
}
private def checkParamLeak(env: Environment)(pp: PP,
register: Int): Z3Constraint = {
val r = env.R(pp)
Z3Constraint(
env.ctx.mkNot(
env.domains.taintDomain.approx(
env.domains.taintDomain.top,
r.taints(register)
)
),
s"Check R($pp)($register) LEAK",
pp
)
}
private def checkParametersLeak(env: Environment)(
i: Instruction35c,
pp: PP
): List[Z3Constraint] = {
var paramsLeak: List[Z3Constraint] = List()
val regCount = i.getRegisterCount
if (regCount > 1) {
paramsLeak = checkParamLeak(env)(pp, i.getRegisterD) :: paramsLeak
if (regCount > 2) {
paramsLeak = checkParamLeak(env)(pp, i.getRegisterE) :: paramsLeak
if (regCount > 3) {
paramsLeak = checkParamLeak(env)(pp, i.getRegisterF) :: paramsLeak
if (regCount > 4) {
paramsLeak = checkParamLeak(env)(pp, i.getRegisterG) :: paramsLeak
}
}
}
}
paramsLeak.reverse
}
private def taintRegisterBasedOnParam(env: Environment)(
pp: PP,
register: Int,
paramRegister: Int): Z3Constraint = {
val r = env.R(pp)
val rPlus = env.R(pp +)
Z3Constraint(
env.domains.taintDomain.approx(
r.taints(paramRegister),
rPlus.taints(register)
),
s"Taint R(${pp +})($register) if R($pp)($paramRegister) is tainted",
pp
)
}
private def taintRegisterBasedOnParameters(env: Environment)(
i: Instruction35c,
pp: PP,
register: Int
): List[Z3Constraint] = {
var registerTaint: List[Z3Constraint] = List()
val paramsCount = i.getRegisterCount
if (paramsCount > 1) {
registerTaint = taintRegisterBasedOnParam(env)(
pp,
register,
i.getRegisterD) :: registerTaint
if (paramsCount > 2) {
registerTaint = taintRegisterBasedOnParam(env)(
pp,
register,
i.getRegisterE) :: registerTaint
if (paramsCount > 3) {
registerTaint = taintRegisterBasedOnParam(env)(
pp,
register,
i.getRegisterF) :: registerTaint
if (paramsCount > 4) {
registerTaint = taintRegisterBasedOnParam(env)(
pp,
register,
i.getRegisterG) :: registerTaint
}
}
}
}
registerTaint.reverse
}
private def taintResBasedOnParam(
env: Environment)(pp: PP, register: Int): Z3Constraint = {
val r = env.R(pp)
val rPlus = env.R(pp +)
Z3Constraint(
env.domains.taintDomain.approx(
r.taints(register),
rPlus.taints(env.R.retIdx)
),
s"Taint R(${pp +})(ret) if R($pp)($register) is tainted",
pp
)
}
private def taintResultBasedOnParameters(env: Environment)(
i: Instruction35c,
pp: PP
): List[Z3Constraint] = {
var resultTaint: List[Z3Constraint] = List()
val paramsCount = i.getRegisterCount
if (paramsCount > 1) {
resultTaint = taintResBasedOnParam(env)(pp, i.getRegisterD) :: resultTaint
if (paramsCount > 2) {
resultTaint = taintResBasedOnParam(env)(pp, i.getRegisterE) :: resultTaint
if (paramsCount > 3) {
resultTaint = taintResBasedOnParam(env)(pp, i.getRegisterF) :: resultTaint
if (paramsCount > 4) {
resultTaint = taintResBasedOnParam(env)(pp, i.getRegisterG) :: resultTaint
}
}
}
}
resultTaint.reverse
}
def invokeDirect(
i: Instruction35c,
pp: PP,
env: Environment,
addMethodToAnalyze: (DexClass, DexMethod) => Unit): Seq[Z3Constraint] = {
val mRef = i.getReference.asInstanceOf[MethodReference]
// RegisterD: parameter
val r = env.R(pp)
val rPlus = env.R(pp +)
val constraints: Seq[Z3Constraint] =
env.app.classes.find(c => c.name == mRef.getDefiningClass) match {
case Some(dexClass) =>
val method =
dexClass.methods
.find(m => m.name == Utils.removeClassPrefix(mRef.toString))
.get
addMethodToAnalyze(dexClass, method)
val ppMethod = PP(dexClass, method, 0)
val thisApprox = Z3Constraint(
env.ctx.mkAnd(
r.<=(
i.getRegisterC,
method.registersCount
)(env.R(ppMethod)): _*
),
s"R($pp)(${i.getRegisterC}) <= R($ppMethod)(${method.registersCount})",
pp
)
val paramApprox = approxParameters(env)(i, pp, dexClass, method)
val returnApprox: Z3Constraint =
Z3Constraint(
env.ctx.mkAnd(
env
.M(dexClass, method)
.map(mResult => {
method.returnType match {
case PrimitiveType() =>
env.domains.primitiveDomain.approx(
mResult.asInstanceOf[env.domains.primitiveDomain.Element],
rPlus
.numbers(env.R.retIdx)
)
}
})
.getOrElse(env.ctx.mkTrue())
),
s"M(${dexClass.name},${method.name}) <= R(${pp +})(ret)",
pp
)
(thisApprox :: paramApprox) ++ Seq(returnApprox)
case None =>
taintRegisterBasedOnParameters(env)(i, pp, i.getRegisterC) ++
taintResultBasedOnParameters(env)(i, pp)
}
constraints ++ Seq(
Z3Constraint(
env.ctx.mkAnd(
r.<=(env.R.retIdx)(rPlus): _*
),
s"R($pp) <={ret} R(${pp +})",
pp
)
)
}
def invokeVirtual(
i: Instruction35c,
pp: PP,
env: Environment,
addMethodToAnalyze: (DexClass, DexMethod) => Unit): Seq[Z3Constraint] = {
val mRef = i.getReference.asInstanceOf[MethodReference]
val r = env.R(pp)
val rPlus = env.R(pp +)
val cName = Utils.classPrefix(mRef.toString)
val mName = Utils.removeClassPrefix(mRef.toString)
val impls: Map[DexClass, DexClass] =
env.Dispatch(mName, mRef.getDefiningClass)
val constraints: Seq[Z3Constraint] =
if (impls.isEmpty) {
val returnApprox: Z3Constraint =
Z3Constraint(
DexType(mName.substring(mName.indexOf(")") + 1)) match {
case PrimitiveType() =>
env.domains.primitiveDomain.approx(
env.domains.primitiveDomain.top,
rPlus
.numbers(env.R.retIdx)
.asInstanceOf[env.domains.primitiveDomain.Element]
)
case ObjectType(_) =>
env.domains.referenceDomain.approx(
env.domains.referenceDomain.top,
rPlus
.references(env.R.retIdx)
.asInstanceOf[env.domains.referenceDomain.Element]
)
case VoidType() =>
env.ctx.mkTrue()
},
s"T <= R(${pp +})(ret)",
pp
)
Seq(returnApprox) ++ taintResultBasedOnParameters(env)(i, pp)
} else
impls
.flatMap(impl => {
val dexClass = impl._2
env.preAnalysisResult.objectCreation
.filter(p => p._2 == impl._1.name)
.map(objPP => {
val method = dexClass.methods
.find(m => m.name == Utils.removeClassPrefix(mRef.toString))
.get
addMethodToAnalyze(dexClass, method)
val ppMethod = PP(dexClass, method, 0)
val thisApprox = Z3Constraint(
env.ctx.mkAnd(
r.<=(
i.getRegisterC,
method.registersCount
)(env.R(ppMethod)): _*
),
s"R($pp)(${i.getRegisterC}) <= R($ppMethod)(${method.registersCount})",
pp
)
val paramApprox = approxParameters(env)(i, pp, dexClass, method)
val returnApprox: Z3Constraint =
Z3Constraint(
env.ctx.mkAnd(
env
.M(dexClass, method)
.map(mResult => {
method.returnType match {
case PrimitiveType() =>
env.domains.primitiveDomain.approx(
mResult.asInstanceOf[env.domains.primitiveDomain.Element],
rPlus
.numbers(env.R.retIdx)
)
}
})
.getOrElse(env.ctx.mkTrue())
),
s"M(${dexClass.name},${method.name}) <= R(${pp +})(ret)",
pp
)
Z3Constraint(
env.ctx.mkImplies(
env.ctx.mkAnd(
env.domains.referenceDomain.approx(
env.domains.referenceDomain.toElement(
objPP._1.toString),
r.references(i.getRegisterC)
)
),
env.ctx.mkAnd(
env.ctx.mkAnd(
paramApprox.map(c => c.boolExpr): _*
),
env.ctx.mkAnd(
thisApprox.boolExpr
),
returnApprox.boolExpr
)
),
s"${objPP._1.toString} <= R($pp)(${i.getRegisterC}) => " +
(if (paramApprox.isEmpty) ""
else
paramApprox
.map(c => c.description)
.mkString(" ∧ ") + " ∧ ") + thisApprox.description +
" ∧ " + returnApprox.description,
pp
)
})
})
.toList
var taintConstraints = List[Z3Constraint]()
if (env.app.sourcesSinks.isSource(cName, mName)) {
taintConstraints = Z3Constraint(
env.domains.taintDomain.approx(
env.domains.taintDomain.top,
rPlus.taints(env.R.retIdx)
),
s"Taint R(${pp +})(ret)",
pp
) :: taintConstraints
}
if (env.app.sourcesSinks.isSink(cName, mName)) {
taintConstraints = taintConstraints ++ (
Z3Constraint(
env.ctx.mkNot(
env.domains.taintDomain.approx(
env.domains.taintDomain.top,
r.taints(i.getRegisterC)
)
),
s"Check R($pp)(${i.getRegisterC}) LEAK",
pp
) :: checkParametersLeak(env)(i, pp)
)
}
constraints ++ taintConstraints ++ Seq(
Z3Constraint(
env.ctx.mkAnd(
r.<=(env.R.retIdx)(rPlus): _*
),
s"R($pp) <={ret} R(${pp +})",
pp
)
)
}
private def classAndSubclasses(env: Environment)(
definingClass: String): List[DexClass] = {
env.app.classes.find(c => c.name == definingClass) match {
case Some(dexClass) => dexClass :: subclasses(env)(dexClass)
case None => List()
}
}
private def subclasses(env: Environment)(
dexClass: DexClass): List[DexClass] = {
env.app.classes
.filter(c => c.superClass == dexClass.name)
.flatMap(c => subclasses(env)(c))
.toList
}
}