# HG changeset patch # User Thinker K.F. Li # Date 1313489411 -28800 # Node ID bc213cb88636eaa776950deb1ee0e0038d904f56 # Parent 91fabeaffce829edc1519dff04c232460ccd5dc8 Inject and redirect fields diff -r 91fabeaffce8 -r bc213cb88636 paraspace/dexfile.py --- a/paraspace/dexfile.py Tue Aug 16 16:07:32 2011 +0800 +++ b/paraspace/dexfile.py Tue Aug 16 18:10:11 2011 +0800 @@ -2358,6 +2358,10 @@ ## \brief Return _DEX_StringId of given index. def find_strid_idx(self, idx): return self.stringIds.items[idx] + + ## \brief Return _DEX_FieldId of given index. + def find_fieldid_idx(self, idx): + return self.fieldIds.items[idx] pass diff -r 91fabeaffce8 -r bc213cb88636 paraspace/injection.py --- a/paraspace/injection.py Tue Aug 16 16:07:32 2011 +0800 +++ b/paraspace/injection.py Tue Aug 16 18:10:11 2011 +0800 @@ -273,21 +273,25 @@ classdefs = None typeids = None strids = None + fieldids = None - def __init__(self, classdefs, typeids, strids): + def __init__(self, classdefs, typeids, strids, fieldids): self.classdefs = set(classdefs) self.typeids = set(typeids) self.strids = set(strids) + self.fieldids = set(fieldids) pass @staticmethod def dup(src): - return relative_obj_set(src.classdefs, src.typeids, src.strids) + return relative_obj_set(src.classdefs, src.typeids, + src.strids, str.fieldids) def update(self, new_data): self.classdefs.update(new_data.classdefs) self.typeids.update(new_data.typeids) self.strids.update(new_data.strids) + self.fieldids.update(new_data.fieldids) pass pass @@ -297,10 +301,10 @@ # \param method is a \ref _DEX_Method. # \return a list of type indices mentioned in the code. # -def collect_typeidxs_stridxs_in_method(dex, method): +def collect_typeidxs_stridxs_fieldidxs_in_method(dex, method): from paraspace.dexfile import _DEX_Method, DEXFile_linked from paraspace.dalvik_opcodes import decode_insn_blk, all_opcodes - from itertools import chain + from paraspace.dalvik_opcodes import all_opcodes assert isinstance(method, _DEX_Method) @@ -344,36 +348,77 @@ return None + field_opcodes = set([all_opcodes.OP_IGET, + all_opcodes.OP_IGET_WIDE, + all_opcodes.OP_IGET_OBJECT, + all_opcodes.OP_IGET_BOOLEAN, + all_opcodes.OP_IGET_BYTE, + all_opcodes.OP_IGET_CHAR, + all_opcodes.OP_IGET_SHORT, + all_opcodes.OP_IPUT, + all_opcodes.OP_IPUT_WIDE, + all_opcodes.OP_IPUT_OBJECT, + all_opcodes.OP_IPUT_BOOLEAN, + all_opcodes.OP_IPUT_BYTE, + all_opcodes.OP_IPUT_CHAR, + all_opcodes.OP_IPUT_SHORT, + all_opcodes.OP_SGET, + all_opcodes.OP_SGET_WIDE, + all_opcodes.OP_SGET_OBJECT, + all_opcodes.OP_SGET_BOOLEAN, + all_opcodes.OP_SGET_BYTE, + all_opcodes.OP_SGET_CHAR, + all_opcodes.OP_SGET_SHORT, + all_opcodes.OP_SPUT, + all_opcodes.OP_SPUT_WIDE, + all_opcodes.OP_SPUT_OBJECT, + all_opcodes.OP_SPUT_BOOLEAN, + all_opcodes.OP_SPUT_BYTE, + all_opcodes.OP_SPUT_CHAR, + all_opcodes.OP_SPUT_SHORT]) + def collect_fields_in_op_vector(op_vector): + code, args = op_vector + if code in field_opcodes: + fieldidx = args[2] + return fieldidx + pass + code_blk = DEXFile_linked.get_code_block_method(method) op_vectors = decode_insn_blk(code_blk) types_insns = [collect_types_in_op_vector(op_vector) for op_vector in op_vectors] typeidxs = [idx for idx in types_insns if idx is not None] - strs_insns = [collect_strings_in_op_vector(op_vectors) - for op_vectors in op_vectors] + strs_insns = [collect_strings_in_op_vector(op_vector) + for op_vector in op_vectors] stridxs = [idx for idx in strs_insns if idx is not None] + + fields_insns = [collect_fields_in_op_vector(op_vector) + for op_vector in op_vectors] + fieldidxs = [idx for idx in fields_insns if idx is not None] - return typeidxs, stridxs + return typeidxs, stridxs, fieldidxs ## \brief Collect all type and string indices mentioned by the class code. -def collect_typeidxs_stridxs_mentioned_by_class(dex, classdef): +def collect_typeidxs_stridxs_fieldidxs_mentioned_by_class(dex, classdef): from paraspace.dexfile import DEXFile_linked assert isinstance(dex, DEXFile_linked) typeidxs = set() stridxs = set() + fieldidxs = set() methods = DEXFile_linked.get_methods_classdef(classdef) for method in methods: - method_typeidxs, method_stridxs = \ - collect_typeidxs_stridxs_in_method(dex, method) + method_typeidxs, method_stridxs, method_fieldidxs = \ + collect_typeidxs_stridxs_fieldidxs_in_method(dex, method) typeidxs.update(method_typeidxs) stridxs.update(method_stridxs) + fieldidxs.update(method_fieldidxs) pass - return list(typeidxs), list(stridxs) + return list(typeidxs), list(stridxs), list(fieldidxs) ## \brief Collect info of classes mentioned by the code of given class. @@ -392,15 +437,16 @@ pass return classdefs, undef_typeids - typeidxs, stridxs = \ - collect_typeidxs_stridxs_mentioned_by_class(dex, classdef) + typeidxs, stridxs, fieldidxs = \ + collect_typeidxs_stridxs_fieldidxs_mentioned_by_class(dex, classdef) typeids = [dex.find_typeid_idx(typeidx) for typeidx in typeidxs] strids = [dex.find_strid_idx(idx) for idx in stridxs] + fieldids = [dex.find_fieldid_idx(idx) for idx in fieldidxs] classdefs, typeids = classify_typeids_defined(dex, typeids) - rel_set = classdef_rel_set(classdefs, typeids, strids) + rel_set = classdef_rel_set(classdefs, typeids, strids, fieldids) return rel_set @@ -423,6 +469,19 @@ return clones +## \brief Insert _DEX_FieldId into another DEX. +def dexfile_insert_fieldid(dex_dst, dex_src, fieldid): + clone = _clone_composite(dex_dst, fieldid) + return clone + + +## \brief Insert _DEX_FieldIds into another DEX. +def dexfile_insert_fieldids(dex_dst, dex_src, fieldids): + clones = [dexfile_insert_fieldid(dex_dst, dex_src, fieldid) + for fieldid in fieldids] + return clones + + ## \brief Clone and insert a _DEX_TypeId to another DEXFile_linked. # # \param dex_dst is a DEXFile_linked where the cloning one is inserted. @@ -478,7 +537,7 @@ ## \brief Collects relative type IDs and classes definition for given class. def collect_classdefs_relative(dex, classdefs): - rel_set = classdef_rel_set(classdefs, [], []) + rel_set = classdef_rel_set(classdefs, [], [], []) classdef_queue = list(classdefs) while classdef_queue: @@ -524,15 +583,17 @@ dexfile_insert_or_merge_typeids(dex_dst, dex_src, rel_set.typeids) cloning_strids = \ dexfile_insert_stringids(dex_dst, dex_src, rel_set.strids) + cloning_fieldids = \ + dexfile_insert_fieldids(dex_dst, dex_src, rel_set.fieldids) cloning = classdef_rel_set(cloning_classdefs, cloning_typeids, - cloning_strids) + cloning_strids, cloning_fieldids) return cloning ## \brief Redirect types, methods and strings for the code of given method. def method_redirect_indices(dex, method, typeidxs_redir, methods_redir, - stridxs_redir): + stridxs_redir, fieldidxs_redir): from paraspace.dalvik_opcodes import decode_insn_blk, all_opcodes from paraspace.dalvik_opcodes import encode_opcode_vectors from paraspace.dexfile import DEXFile_linked @@ -544,6 +605,34 @@ insns_blk = code.insns.data op_vectors = decode_insn_blk(insns_blk) + field_opcodes = set([all_opcodes.OP_IGET, + all_opcodes.OP_IGET_WIDE, + all_opcodes.OP_IGET_OBJECT, + all_opcodes.OP_IGET_BOOLEAN, + all_opcodes.OP_IGET_BYTE, + all_opcodes.OP_IGET_CHAR, + all_opcodes.OP_IGET_SHORT, + all_opcodes.OP_IPUT, + all_opcodes.OP_IPUT_WIDE, + all_opcodes.OP_IPUT_OBJECT, + all_opcodes.OP_IPUT_BOOLEAN, + all_opcodes.OP_IPUT_BYTE, + all_opcodes.OP_IPUT_CHAR, + all_opcodes.OP_IPUT_SHORT, + all_opcodes.OP_SGET, + all_opcodes.OP_SGET_WIDE, + all_opcodes.OP_SGET_OBJECT, + all_opcodes.OP_SGET_BOOLEAN, + all_opcodes.OP_SGET_BYTE, + all_opcodes.OP_SGET_CHAR, + all_opcodes.OP_SGET_SHORT, + all_opcodes.OP_SPUT, + all_opcodes.OP_SPUT_WIDE, + all_opcodes.OP_SPUT_OBJECT, + all_opcodes.OP_SPUT_BOOLEAN, + all_opcodes.OP_SPUT_BYTE, + all_opcodes.OP_SPUT_CHAR, + all_opcodes.OP_SPUT_SHORT]) def redirect(opcode, args): if opcode == all_opcodes.OP_NEW_INSTANCE: typeidx = args[1] @@ -578,6 +667,11 @@ return opcode, args return opcode, (args[0], stridxs_redir[stridx]) + elif opcode in field_opcodes: + fieldidx = args[2] + if fieldidx not in fieldidxs_redir: + return opcode, args + return opcode, (args[0], args[1], fieldidxs_redir[fieldidx]) return opcode, args new_op_vectors = [redirect(opcode, args) for opcode, args in op_vectors] @@ -625,22 +719,23 @@ # \param dex is a DEXFile_linked. # \param classdef is a class definition. # \param typeidxs_redir is a map of types. +# \param methods_redir is a map of methods. # \param stridxs_redir is a map of strings. -# \param methods_redir is a map of methods. +# \param fieldidxs_redir is a map of fields. # def class_redirect_indices(dex, classdef, typeidxs_redir, methods_redir, - stridxs_redir): + stridxs_redir, fieldidxs_redir): if not classdef.classDataOffRef.is_true: return classdata = classdef.classDataOffRef.value for method in classdata.directMethods.items: method_redirect_indices(dex, method, typeidxs_redir, methods_redir, - stridxs_redir) + stridxs_redir, fieldidxs_redir) pass for method in classdata.virtualMethods.items: method_redirect_indices(dex, method, typeidxs_redir, methods_redir, - stridxs_redir) + stridxs_redir, fieldidxs_redir) pass pass @@ -688,23 +783,36 @@ return stridxs_map +def make_fieldidxs_redir_map(dex_src, dex_dst): + fieldidxs_map = {} + for idx, fieldid in enumerate(dex_src.fieldIds.items): + try: + tgt_idx = dex_dst.fieldIds.items.index(fieldid) + except ValueError: + continue + fieldidxs_map[idx] = tgt_idx + pass + return fieldidxs_map + + ## \biref Redirect types of all code in given DEXFile_linked. def dexfile_redirect_indices(dex, typeidxs_redir, methods_redir, stridxs_redir, - excludes=set([])): + fieldidxs_redir, excludes=set([])): for classdef in dex.classDefs.items: typeid = classdef.classIdx idx = dex.get_idx_typeid(typeid) if idx in excludes: continue class_redirect_indices(dex, classdef, typeidxs_redir, methods_redir, - stridxs_redir) + stridxs_redir, fieldidxs_redir) pass pass ## \brief Redirect types for code of types specified by given indices. def dexfile_redirect_indices_typeidxs(dex, typeidxs_redir, methodidxs_redir, - stridxs_redir, typeidxs): + stridxs_redir, fieldidxs_redir, + typeidxs): typeidxs = set(typeidxs) for classdef in dex.classDefs.items: typeid = classdef.classIdx @@ -712,7 +820,8 @@ if idx not in typeidxs: continue class_redirect_indices(dex, classdef, typeidxs_redir, - methodidxs_redir, stridxs_redir) + methodidxs_redir, stridxs_redir, + fieldidxs_redir) pass pass @@ -757,10 +866,14 @@ stridxs_redir = \ make_stridxs_redir_map(dex_src, dex_dst) + + fieldidxs_redir = \ + make_fieldidxs_redir_map(dex_src, dex_dst) dexfile_redirect_indices_typeidxs(dex_dst, typeidxs_redir, methodidxs_redir, stridxs_redir, + fieldidxs_redir, typeidxs_redir.values()) pass @@ -799,13 +912,15 @@ make_methodidxs_redir_map(dex, dex, typeidxs_redir) stridxs_redir = {} + fieldidxs_redir = {} ex_typeids = [dex.find_typeid_name(name) for name in exclude_classnames] ex_typeidxs = [dex.get_idx_typeid(typeid) for typeid in ex_typeids] dexfile_redirect_indices(dex, typeidxs_redir, methodidxs_redir, - stridxs_redir, excludes=ex_typeidxs) + stridxs_redir, fieldidxs_redir, + excludes=ex_typeidxs) pass @@ -833,16 +948,18 @@ # injection, this function create maps for remapping indices mentioned # in the code. # -def _make_idx_map(saved_typeids, saved_methodids, saved_strids, - new_typeids, new_methodids, new_strids): +def _make_idx_map(saved_typeids, saved_methodids, saved_strids, saved_fieldids, + new_typeids, new_methodids, new_strids, new_fieldids): methodidxs_map = dict([(idx, new_methodids.index(methodid)) for idx, methodid in enumerate(saved_methodids)]) typeidxs_map = dict([(idx, new_typeids.index(typeid)) for idx, typeid in enumerate(saved_typeids)]) stridxs_map = dict([(idx, new_strids.index(strid)) for idx, strid in enumerate(saved_strids)]) + fieldidxs_map = dict([(idx, new_fieldids.index(fieldid)) + for idx, fieldid in enumerate(saved_fieldids)]) - return typeidxs_map, methodidxs_map, stridxs_map + return typeidxs_map, methodidxs_map, stridxs_map, fieldidxs_map ## \brief Sort sorted arrays and remapping indices for code blocks. @@ -856,18 +973,22 @@ saved_typeids = list(dex_linked.typeIds.items) saved_methodids = list(dex_linked.methodIds.items) saved_strids = list(dex_linked.stringIds.items) + saved_fieldids = list(dex_linked.fieldIds.items) dex_sort_sorted_arrays(dex_linked) new_typeids = dex_linked.typeIds.items new_methodids = dex_linked.methodIds.items new_strids = dex_linked.stringIds.items - typeidxs_map, methodidxs_map, stridxs_map = \ + new_fieldids = dex_linked.fieldIds.items + typeidxs_map, methodidxs_map, stridxs_map, fieldidxs_map = \ _make_idx_map(saved_typeids, saved_methodids, saved_strids, \ - new_typeids, new_methodids, new_strids) + saved_fieldids, \ + new_typeids, new_methodids, new_strids, \ + new_fieldids) dexfile_redirect_indices(dex_linked, typeidxs_map, methodidxs_map, - stridxs_map) + stridxs_map, fieldidxs_map) pass diff -r 91fabeaffce8 -r bc213cb88636 paraspace/tests/injection_test.py --- a/paraspace/tests/injection_test.py Tue Aug 16 16:07:32 2011 +0800 +++ b/paraspace/tests/injection_test.py Tue Aug 16 18:10:11 2011 +0800 @@ -161,7 +161,7 @@ helloworld_linked, types_redir) dexfile_redirect_indices(helloworld_linked, types_redir, - methods_redir, excludes) + methods_redir, {}, excludes) for code in helloworld_linked.codeItems.items: op_vectors = dalvik_opcodes.decode_insn_blk(code.insns.data) @@ -181,8 +181,10 @@ def collect_types_in_method_test(): from paraspace.dex_deptracker import prepare_dep_decls - from paraspace.injection import collect_typeidxs_stridxs_in_method - from paraspace.injection import collect_typeidxs_stridxs_mentioned_by_class + from paraspace.injection import \ + collect_typeidxs_stridxs_fieldidxs_in_method + from paraspace.injection import \ + collect_typeidxs_stridxs_fieldidxs_mentioned_by_class from paraspace.dexfile import DEXFile_linked _install_dexfile_4_deptracker() @@ -203,17 +205,18 @@ init_method = fakefile_linked.find_method_name('', fakefile_def) - typeidxs, stridxs = \ - collect_typeidxs_stridxs_in_method(fakefile_linked, init_method) + typeidxs, stridxs, fieldidxs = \ + collect_typeidxs_stridxs_fieldidxs_in_method(fakefile_linked, \ + init_method) assert len(typeidxs) == 1 typeid = fakefile_linked.find_typeid_idx(typeidxs[0]) typeid_name = DEXFile_linked.get_typeid_name(typeid) assert typeid_name == 'Ljava/io/File;' - typeidxs, stridxs = \ - collect_typeidxs_stridxs_mentioned_by_class(fakefile_linked, \ - fakefile_def) + typeidxs, stridxs, fieldidxs = \ + collect_typeidxs_stridxs_fieldidxs_mentioned_by_class(\ + fakefile_linked, fakefile_def) assert len(typeidxs) == 1 typeid = fakefile_linked.find_typeid_idx(typeidxs[0]) @@ -370,7 +373,7 @@ helloworld_linked, \ typeidxs_redir_map) dexfile_redirect_indices(helloworld_linked, typeidxs_redir_map, - methodidxs_redir_map, {}, + methodidxs_redir_map, {}, {}, excludes=[fakefile_typeidx]) cloning_initdef = \