# HG changeset patch # User Thinker K.F. Li # Date 1312172848 -28800 # Node ID 18be67af7f1e3f0c62b3de19d9d2ab5cc721ab69 # Parent 4b3573d039af4649c5527b940864921b87f2a3ae Use method redirection map for defining redirection diff -r 4b3573d039af -r 18be67af7f1e paraspace/dexfile.py --- a/paraspace/dexfile.py Sat Jul 30 22:59:09 2011 +0800 +++ b/paraspace/dexfile.py Mon Aug 01 12:27:28 2011 +0800 @@ -1784,6 +1784,11 @@ @staticmethod def get_method_name(method): methodid = method.methodIdx + return DEXFile_linked.get_methodid_name(methodid) + + ## \brief Get name string of given method ID. + @staticmethod + def get_methodid_name(methodid): namestrid = methodid.nameIdx namestrdata = namestrid.stringDataOff name_str = namestrdata.data.data @@ -1814,11 +1819,6 @@ idx = self.methodIds.items.index(methodid) return idx - ## \brief Get name of given method ID. - @staticmethod - def get_methodid_name(methoid): - return methoid.nameIdx.stringDataOff.data.data - ## \brief Find the method ID item of given index. def find_methodid_idx(self, idx): methodid = self.methodIds.items[idx] @@ -1827,7 +1827,7 @@ ## \brief Find a method definition with an index to method ID. def find_method_idx(self, idx): methodid = self.find_methodid_idx(idx) - method_name = DEXFile_linked.get_methoid_name(methodid) + method_name = DEXFile_linked.get_methodid_name(methodid) method_proto = methodid.protoIdx method_typeid = methodid.classIdx classdef = self.find_class_typeid(method_typeid) @@ -1849,11 +1849,15 @@ for tl_typeid1, tl_typeid2 in map(None, typelist1.typeItems.items, typelist2.typeItems.items): - if tl_typeid1.typeIdx != tl_typeid2.typeIdx: + typename1 = DEXFile_linked.get_typeid_name(tl_typeid1.typeIdx) + typename2 = DEXFile_linked.get_typeid_name(tl_typeid2.typeIdx) + + if typename1 != typename2: return False pass return True + ## \brief Find the method of given name, prototype and class definition. def find_method_name_proto(self, method_name, proto, classdef): if not classdef.classDataOffRef.is_true: return @@ -1870,6 +1874,25 @@ pass raise ValueError, 'can not find a method for given name and prototype' + ## \brief Return index of given method ID. + def get_idx_methodid(self, methodid): + idx = self.methodIds.items.index(methodid) + return idx + + ## \brief Return method ID for given name, proto, and typeid/ + def find_methodid_name_proto(self, method_name, proto, typeid): + for methodid in self.methodIds.items: + if method_name != DEXFile_linked.get_methodid_name(methodid): + continue + if methodid.classIdx != typeid: + continue + if not DEXFile_linked. \ + _proto_is_compatible(methodid.protoIdx, proto): + continue + return methodid + raise ValueError, 'can not find the method ID for given name, ' \ + 'prototype and type ID' + @staticmethod def get_param_typeids_protoid(protoid): if not protoid.parametersOffRef.is_true: diff -r 4b3573d039af -r 18be67af7f1e paraspace/injection.py --- a/paraspace/injection.py Sat Jul 30 22:59:09 2011 +0800 +++ b/paraspace/injection.py Mon Aug 01 12:27:28 2011 +0800 @@ -217,7 +217,8 @@ return clone -def method_redirect_types(dex, method, redirect_map): +## \brief Redirect types and methods for the code of given method. +def method_redirect_types(dex, method, types_redir, methods_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 @@ -232,20 +233,25 @@ def redirect(opcode, args): if opcode == all_opcodes.OP_NEW_INSTANCE: typeidx = args[1] - if typeidx in redirect_map: - to_type = redirect_map[typeidx] + if typeidx in types_redir: + to_type = types_redir[typeidx] return opcode, (args[0], to_type) pass elif opcode == all_opcodes.OP_INVOKE_DIRECT: methodidx = args[2] + if methodidx not in methods_redir: + return opcode, args + + return opcode, (args[0], args[1], methods_redir[methodidx], + args[3], args[4], args[5], args[6]) methodid = dex.find_methodid_idx(methodidx) method_typeid = methodid.classIdx method_typeidx = dex.get_idx_typeid(method_typeid) - if method_typeidx not in redirect_map: + if method_typeidx not in types_redir: method_typeid = dex.find_typeid_idx(method_typeidx - 1) return opcode, args - new_method_typeidx = redirect_map[method_typeidx] + new_method_typeidx = types_redir[method_typeidx] new_method_typeid = dex.find_typeid_idx(new_method_typeidx) classdef = dex.find_class_typeid(new_method_typeid) method_name = DEXFile_linked.get_methodid_name(methodid) @@ -269,26 +275,92 @@ pass -def class_redirect_types(dex, classdef, redirect_map): +## \brief Make a map for methods from source type ID to ones from desinate. +def make_redir_classes_methods_map(dex_src, typeid_src, + dex_dst, typeid_dst): + from paraspace.dexfile import DEXFile_linked + + methods_src = [(idx, methodid) + for idx, methodid in enumerate(dex_src.methodIds.items) + if methodid.classIdx == typeid_src] + + def make_map_methodid(methodid_src): + name = DEXFile_linked.get_methodid_name(methodid_src) + proto = methodid_src.protoIdx + try: + methodid_dst = \ + dex_dst.find_methodid_name_proto(name, proto, typeid_dst) + except ValueError: + return -1 + methodidx_dst = dex_dst.get_idx_methodid(methodid_dst) + return methodidx_dst + + methods_map = [(methodidx_src, make_map_methodid(methodid_src)) + for methodidx_src, methodid_src in methods_src] + methods_map = [(methodidx_src, methodidx_dst) + for methodidx_src, methodidx_dst in methods_map + if methodidx_dst != -1] + methods_map = dict(methods_map) + return methods_map + + +## \brief Redirect types and methods mentioned in the code of a class. +# +# For code of given class definition, Every mentions of types and +# methods are rewrote to types and methods according types_redir and +# methods_redir respectively. +# +# \param dex is a DEXFile_linked. +# \param classdef is a class definition. +# \param types_redir is a map of types. +# \param methods_redir is a map of methods. +# +def class_redirect_types(dex, classdef, types_redir, methods_redir): if not classdef.classDataOffRef.is_true: return classdata = classdef.classDataOffRef.value for method in classdata.directMethods.items: - method_redirect_types(dex, method, redirect_map) + method_redirect_types(dex, method, types_redir, methods_redir) pass for method in classdata.virtualMethods.items: - method_redirect_types(dex, method, redirect_map) + method_redirect_types(dex, method, types_redir, methods_redir) pass pass -def dexfile_redirect_types(dex, redirect_map, excludes=set([])): +## \brief Make a map to map methods from source types to destinate types. +# +# This function create a map to map methods from source types to +# methods from destinate types in \ref types_redir. +# +# \param dex is a DEXFile_linked that owns source and destinate types. +# \param types_redir is a map of types for redirecting types. +# \return a map of method indices. +# +def _make_methods_redir_for_types_redir(dex, types_redir): + methods_map = {} + for typeidx_src, typeidx_dst in types_redir.items(): + typeid_src = dex.find_typeid_idx(typeidx_src) + typeid_dst = dex.find_typeid_idx(typeidx_dst) + class_methods_map = make_redir_classes_methods_map(dex, + typeid_src, + dex, + typeid_dst) + methods_map.update(class_methods_map) + pass + return methods_map + + +## \biref Redirect types of all code in given DEXFile_linked. +def dexfile_redirect_types(dex, types_redir, excludes=set([])): + methods_redir = _make_methods_redir_for_types_redir(dex, types_redir) + for classdef in dex.classDefs.items: typeid = classdef.classIdx idx = dex.get_idx_typeid(typeid) if idx in excludes: continue - class_redirect_types(dex, classdef, redirect_map) + class_redirect_types(dex, classdef, types_redir, methods_redir) pass pass