Ensure class permissions are valid when resolving a field while deodexing

This commit is contained in:
Ben Gruver 2012-12-25 18:04:28 -08:00
parent 650d426c12
commit ebd1b0e9c1
2 changed files with 31 additions and 16 deletions

View File

@ -64,20 +64,21 @@ public class DeodexUtil {
return inlineMethodResolver.resolveExecuteInline(instruction); return inlineMethodResolver.resolveExecuteInline(instruction);
} }
public FieldIdItem lookupField(ClassPath.ClassDef classDef, int fieldOffset) { public FieldIdItem lookupField(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
ClassPath.FieldDef field = classDef.getInstanceField(fieldOffset); int fieldOffset) {
ClassPath.FieldDef field = instanceClass.getInstanceField(fieldOffset);
if (field == null) { if (field == null) {
return null; return null;
} }
return parseAndResolveField(classDef, field); return parseAndResolveField(accessingClass, instanceClass, field);
} }
private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)"); private static final Pattern shortMethodPattern = Pattern.compile("([^(]+)\\(([^)]*)\\)(.+)");
public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass, public MethodIdItem lookupVirtualMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
int methodIndex) { int methodIndex) {
String method = definingClass.getVirtualMethod(methodIndex); String method = instanceClass.getVirtualMethod(methodIndex);
if (method == null) { if (method == null) {
return null; return null;
} }
@ -92,16 +93,16 @@ public class DeodexUtil {
String methodParams = m.group(2); String methodParams = m.group(2);
String methodRet = m.group(3); String methodRet = m.group(3);
if (definingClass instanceof ClassPath.UnresolvedClassDef) { if (instanceClass instanceof ClassPath.UnresolvedClassDef) {
//if this is an unresolved class, the only way getVirtualMethod could have found a method is if the virtual //if this is an unresolved class, the only way getVirtualMethod could have found a method is if the virtual
//method being looked up was a method on java.lang.Object. //method being looked up was a method on java.lang.Object.
definingClass = ClassPath.getClassDef("Ljava/lang/Object;"); instanceClass = ClassPath.getClassDef("Ljava/lang/Object;");
} else if (definingClass.isInterface()) { } else if (instanceClass.isInterface()) {
definingClass = definingClass.getSuperclass(); instanceClass = instanceClass.getSuperclass();
assert definingClass != null; assert instanceClass != null;
} }
return parseAndResolveMethod(accessingClass, definingClass, methodName, methodParams, methodRet); return parseAndResolveMethod(accessingClass, instanceClass, methodName, methodParams, methodRet);
} }
private MethodIdItem parseAndResolveMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass, private MethodIdItem parseAndResolveMethod(ClassPath.ClassDef accessingClass, ClassPath.ClassDef definingClass,
@ -203,7 +204,6 @@ public class DeodexUtil {
do { do {
TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, methodClassDef.getClassType()); TypeIdItem classTypeItem = TypeIdItem.lookupTypeIdItem(dexFile, methodClassDef.getClassType());
if (classTypeItem != null) { if (classTypeItem != null) {
MethodIdItem methodIdItem = MethodIdItem.lookupMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem); MethodIdItem methodIdItem = MethodIdItem.lookupMethodIdItem(dexFile, classTypeItem, protoItem, methodNameItem);
if (methodIdItem != null && checkClassAccess(accessingClass, methodClassDef)) { if (methodIdItem != null && checkClassAccess(accessingClass, methodClassDef)) {
@ -229,7 +229,15 @@ public class DeodexUtil {
return classRef.substring(1, lastSlash); return classRef.substring(1, lastSlash);
} }
private FieldIdItem parseAndResolveField(ClassPath.ClassDef classDef, ClassPath.FieldDef field) { /**
*
* @param accessingClass The class that contains the field reference. I.e. the class being deodexed
* @param instanceClass The inferred class type of the object that the field is being accessed on
* @param field The field being accessed
* @return The FieldIdItem of the resolved field
*/
private FieldIdItem parseAndResolveField(ClassPath.ClassDef accessingClass, ClassPath.ClassDef instanceClass,
ClassPath.FieldDef field) {
String definingClass = field.definingClass; String definingClass = field.definingClass;
String fieldName = field.name; String fieldName = field.name;
String fieldType = field.type; String fieldType = field.type;
@ -244,7 +252,7 @@ public class DeodexUtil {
return null; return null;
} }
ClassPath.ClassDef fieldClass = classDef; ClassPath.ClassDef fieldClass = instanceClass;
ArrayList<ClassPath.ClassDef> parents = new ArrayList<ClassPath.ClassDef>(); ArrayList<ClassPath.ClassDef> parents = new ArrayList<ClassPath.ClassDef>();
parents.add(fieldClass); parents.add(fieldClass);
@ -263,7 +271,7 @@ public class DeodexUtil {
} }
FieldIdItem fieldIdItem = FieldIdItem.lookupFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem); FieldIdItem fieldIdItem = FieldIdItem.lookupFieldIdItem(dexFile, classTypeItem, fieldTypeItem, fieldNameItem);
if (fieldIdItem != null) { if (fieldIdItem != null && checkClassAccess(accessingClass, fieldClass)) {
return fieldIdItem; return fieldIdItem;
} }
} }

View File

@ -3578,7 +3578,14 @@ public class MethodAnalyzer {
return false; return false;
} }
FieldIdItem fieldIdItem = deodexUtil.lookupField(objectRegisterType.type, fieldOffset); ClassPath.ClassDef accessingClass =
ClassPath.getClassDef(this.encodedMethod.method.getContainingClass(), false);
if (accessingClass == null) {
throw new ExceptionWithContext(String.format("Could not find ClassDef for current class: %s",
this.encodedMethod.method.getContainingClass()));
}
FieldIdItem fieldIdItem = deodexUtil.lookupField(accessingClass, objectRegisterType.type, fieldOffset);
if (fieldIdItem == null) { if (fieldIdItem == null) {
throw new ValidationException(String.format("Could not resolve the field in class %s at offset %d", throw new ValidationException(String.format("Could not resolve the field in class %s at offset %d",
objectRegisterType.type.getClassType(), fieldOffset)); objectRegisterType.type.getClassType(), fieldOffset));