changeset 108:18be67af7f1e

Use method redirection map for defining redirection
author Thinker K.F. Li <thinker@codemud.net>
date Mon, 01 Aug 2011 12:27:28 +0800
parents 4b3573d039af
children 835336632aba
files paraspace/dexfile.py paraspace/injection.py
diffstat 2 files changed, 112 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- 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:
--- 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