
soot.dava.toolkits.base.AST.interProcedural.ConstantFieldValueFinder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soot Show documentation
Show all versions of soot Show documentation
A Java Optimization Framework
package soot.dava.toolkits.base.AST.interProcedural;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2006 Nomair A. Naeem
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import soot.BooleanType;
import soot.ByteType;
import soot.CharType;
import soot.DoubleType;
import soot.FloatType;
import soot.IntType;
import soot.LongType;
import soot.PrimType;
import soot.ShortType;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Type;
import soot.Value;
import soot.dava.DavaBody;
import soot.dava.DecompilationException;
import soot.dava.internal.AST.ASTNode;
import soot.dava.toolkits.base.AST.traversals.AllDefinitionsFinder;
import soot.jimple.DefinitionStmt;
import soot.jimple.DoubleConstant;
import soot.jimple.FieldRef;
import soot.jimple.FloatConstant;
import soot.jimple.IntConstant;
import soot.jimple.LongConstant;
import soot.jimple.NumericConstant;
import soot.tagkit.DoubleConstantValueTag;
import soot.tagkit.FloatConstantValueTag;
import soot.tagkit.IntegerConstantValueTag;
import soot.tagkit.LongConstantValueTag;
import soot.util.Chain;
/*
* Deemed important because of obfuscation techniques which add crazy
* control flow under some condition which is never executed because
* it uses some field which is always false!!
*
* Goal:
* Prove that a field is never assigned a value or that if it is assigned a value
* we can statically tell this value
*
*
*/
public class ConstantFieldValueFinder {
public final boolean DEBUG = false;
public static String combiner = "_$p$g_";
HashMap classNameFieldNameToSootFieldMapping = new HashMap();
HashMap fieldToValues = new HashMap();
HashMap primTypeFieldValueToUse = new HashMap();
Chain appClasses;
public ConstantFieldValueFinder(Chain classes) {
appClasses = classes;
debug("ConstantFieldValueFinder -- applyAnalyses", "computing Method Summaries");
computeFieldToValuesAssignedList();
valuesForPrimTypeFields();
}
/*
* The hashMap returned contains a mapping of class + combiner + field ----> Double/Float/Long/Integer if there is no
* mapping for a particular field then that means we couldnt detect a constant value for it
*/
public HashMap getFieldsWithConstantValues() {
return primTypeFieldValueToUse;
}
public HashMap getClassNameFieldNameToSootFieldMapping() {
return classNameFieldNameToSootFieldMapping;
}
/*
* This method gives values to all the fields in all the classes if they can be determined statically We only care about
* fields which have primitive types
*/
private void valuesForPrimTypeFields() {
// go through all the classes
Iterator classIt = appClasses.iterator();
while (classIt.hasNext()) {
SootClass s = (SootClass) classIt.next();
debug("\nvaluesforPrimTypeFields", "Processing class " + s.getName());
String declaringClass = s.getName();
Iterator fieldIt = s.getFields().iterator();
while (fieldIt.hasNext()) {
SootField f = (SootField) fieldIt.next();
String fieldName = f.getName();
Type fieldType = f.getType();
if (!(fieldType instanceof PrimType)) {
continue;
}
String combined = declaringClass + combiner + fieldName;
classNameFieldNameToSootFieldMapping.put(combined, f);
Object value = null;
// check for constant value tags
if (fieldType instanceof DoubleType && f.hasTag("DoubleConstantValueTag")) {
double val = ((DoubleConstantValueTag) f.getTag("DoubleConstantValueTag")).getDoubleValue();
value = new Double(val);
} else if (fieldType instanceof FloatType && f.hasTag("FloatConstantValueTag")) {
float val = ((FloatConstantValueTag) f.getTag("FloatConstantValueTag")).getFloatValue();
value = new Float(val);
} else if (fieldType instanceof LongType && f.hasTag("LongConstantValueTag")) {
long val = ((LongConstantValueTag) f.getTag("LongConstantValueTag")).getLongValue();
value = new Long(val);
} else if (fieldType instanceof CharType && f.hasTag("IntegerConstantValueTag")) {
int val = ((IntegerConstantValueTag) f.getTag("IntegerConstantValueTag")).getIntValue();
value = new Integer(val);
} else if (fieldType instanceof BooleanType && f.hasTag("IntegerConstantValueTag")) {
int val = ((IntegerConstantValueTag) f.getTag("IntegerConstantValueTag")).getIntValue();
if (val == 0) {
value = new Boolean(false);
} else {
value = new Boolean(true);
}
} else if ((fieldType instanceof IntType || fieldType instanceof ByteType || fieldType instanceof ShortType)
&& f.hasTag("IntegerConstantValueTag")) {
int val = ((IntegerConstantValueTag) f.getTag("IntegerConstantValueTag")).getIntValue();
value = new Integer(val);
}
// if there was a constant value tag we have its value now
if (value != null) {
debug("TAGGED value found for field: " + combined);
primTypeFieldValueToUse.put(combined, value);
// continue with next field
continue;
}
// see if the field was never assigned in which case it gets default values
Object temp = fieldToValues.get(combined);
if (temp == null) {
// no value list found is good
// add default value to primTypeFieldValueToUse hashmap
if (fieldType instanceof DoubleType) {
value = new Double(0);
} else if (fieldType instanceof FloatType) {
value = new Float(0);
} else if (fieldType instanceof LongType) {
value = new Long(0);
} else if (fieldType instanceof BooleanType) {
value = new Boolean(false);
} else if ((fieldType instanceof IntType || fieldType instanceof ByteType || fieldType instanceof ShortType)
|| fieldType instanceof CharType) {
value = new Integer(0);
} else {
throw new DecompilationException("Unknown primitive type...please report to developer");
}
primTypeFieldValueToUse.put(combined, value);
debug("DEFAULT value for field: " + combined);
// continue with next field
continue;
}
// havent got a tag with value and havent use default since SOME method did define the field atleast once
// there was some value assigned!!!!!!!!!
debug("CHECKING USER ASSIGNED VALUES FOR: " + combined);
ArrayList values = (ArrayList) temp;
// check if they are all constants and that too the same constant
Iterator it = values.iterator();
NumericConstant tempConstant = null;
while (it.hasNext()) {
Value val = (Value) it.next();
if (!(val instanceof NumericConstant)) {
tempConstant = null;
debug("Not numeric constant hence giving up");
break;
}
if (tempConstant == null) {
tempConstant = (NumericConstant) val;
} else {
// check that this value is the same as previous
if (!tempConstant.equals(val)) {
tempConstant = null;
break;
}
}
}
if (tempConstant == null) {
// continue with next field cant do anything about this one
continue;
}
// agreed on a unique constant value
/*
* Since these are fields are we are doing CONTEXT INSENSITIVE WE need to make sure that the agreed unique constant
* value is the default value
*
* I KNOW IT SUCKS BUT HEY WHAT CAN I DO!!!
*/
if (tempConstant instanceof LongConstant) {
Long tempVal = new Long(((LongConstant) tempConstant).value);
if (tempVal.compareTo(new Long(0)) == 0) {
primTypeFieldValueToUse.put(combined, tempVal);
} else {
debug("Not assigning the agreed value since that is not the default value for " + combined);
}
} else if (tempConstant instanceof DoubleConstant) {
Double tempVal = new Double(((DoubleConstant) tempConstant).value);
if (tempVal.compareTo(new Double(0)) == 0) {
primTypeFieldValueToUse.put(combined, tempVal);
} else {
debug("Not assigning the agreed value since that is not the default value for " + combined);
}
} else if (tempConstant instanceof FloatConstant) {
Float tempVal = new Float(((FloatConstant) tempConstant).value);
if (tempVal.compareTo(new Float(0)) == 0) {
primTypeFieldValueToUse.put(combined, tempVal);
} else {
debug("Not assigning the agreed value since that is not the default value for " + combined);
}
} else if (tempConstant instanceof IntConstant) {
Integer tempVal = new Integer(((IntConstant) tempConstant).value);
if (tempVal.compareTo(new Integer(0)) == 0) {
SootField tempField = classNameFieldNameToSootFieldMapping.get(combined);
if (tempField.getType() instanceof BooleanType) {
primTypeFieldValueToUse.put(combined, new Boolean(false));
// System.out.println("puttingvalue false for"+combined);
} else {
primTypeFieldValueToUse.put(combined, tempVal);
// System.out.println("puttingvalue 0 for"+combined);
}
} else {
debug("Not assigning the agreed value since that is not the default value for " + combined);
}
} else {
throw new DecompilationException("Un handled Numberic Constant....report to programmer");
}
} // all fields of the class
} // all classes
}
/*
* Go through all the methods in the application and make a mapping of className+methodName ---> values assigned There can
* obviously be more than one value assigned to each field
*/
private void computeFieldToValuesAssignedList() {
// go through all the classes
Iterator classIt = appClasses.iterator();
while (classIt.hasNext()) {
SootClass s = (SootClass) classIt.next();
debug("\ncomputeMethodSummaries", "Processing class " + s.getName());
// go though all the methods
Iterator methodIt = s.methodIterator();
while (methodIt.hasNext()) {
SootMethod m = (SootMethod) methodIt.next();
DavaBody body = null;
if (m.hasActiveBody()) {
/*
* Added to try to fix the no active body found exception
*/
body = (DavaBody) m.getActiveBody();
} else {
continue;
}
ASTNode AST = (ASTNode) body.getUnits().getFirst();
// find all definitions in the program
AllDefinitionsFinder defFinder = new AllDefinitionsFinder();
AST.apply(defFinder);
Iterator allDefIt = defFinder.getAllDefs().iterator();
// go through each definition
while (allDefIt.hasNext()) {
DefinitionStmt stmt = allDefIt.next();
// debug("DefinitionStmt")
Value left = stmt.getLeftOp();
/*
* Only care if we have fieldRef on the left
*/
if (!(left instanceof FieldRef)) {
continue;
}
// we know definition is to a field
debug("computeMethodSummaries method: " + m.getName(), "Field ref is: " + left);
// Information we want to store is class of field and name of field and the right op
FieldRef ref = (FieldRef) left;
SootField field = ref.getField();
/*
* Only care about fields with primtype
*/
if (!(field.getType() instanceof PrimType)) {
continue;
}
String fieldName = field.getName();
String declaringClass = field.getDeclaringClass().getName();
debug("\tField Name: " + fieldName);
debug("\tField DeclaringClass: " + declaringClass);
// get the valueList for this class+field combo
String combined = declaringClass + combiner + fieldName;
Object temp = fieldToValues.get(combined);
ArrayList valueList;
if (temp == null) {
// no value of this field was yet assigned
valueList = new ArrayList();
fieldToValues.put(combined, valueList);
} else {
valueList = (ArrayList) temp;
}
valueList.add(stmt.getRightOp());
} // going through all the definitions
} // going through methods of class s
} // going through classes
}
public void printConstantValueFields() {
System.out.println("\n\n Printing Constant Value Fields (method: printConstantValueFields)");
Iterator it = primTypeFieldValueToUse.keySet().iterator();
while (it.hasNext()) {
String combined = it.next();
int temp = combined.indexOf(combiner, 0);
if (temp > 0) {
System.out.println("Class: " + combined.substring(0, temp) + " Field: "
+ combined.substring(temp + combiner.length()) + " Value: " + primTypeFieldValueToUse.get(combined));
}
}
}
public void debug(String methodName, String debug) {
if (DEBUG) {
System.out.println(methodName + " DEBUG: " + debug);
}
}
public void debug(String debug) {
if (DEBUG) {
System.out.println("DEBUG: " + debug);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy