changeset 137:987fead83ce3

Fix issue that dalvik complaining fail to verify code. - Since order of typeId and methodId are changed, index values in code block of methods are invalid after sorting sorted arrays. - We add dex_sort_sorted_arrays_consistent() function as a wrapper of dex_sort_sorted_arrays(). It remap indices mentioned in code blocks after sorting.
author Thinker K.F. Li <thinker@codemud.net>
date Wed, 10 Aug 2011 14:04:02 +0800
parents f31bfe55d9c2
children 372009418896
files paraspace/dex_deptracker.py paraspace/dexfile.py paraspace/injection.py paraspace/tests/dexfile_test.py paraspace/tests/injection_test.py
diffstat 5 files changed, 135 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/dex_deptracker.py	Tue Aug 09 21:52:05 2011 +0800
+++ b/paraspace/dex_deptracker.py	Wed Aug 10 14:04:02 2011 +0800
@@ -96,6 +96,10 @@
     pass
 
 
+## \brief Find depend attributes of a class.
+#
+# It does not cross the boundary of the class.
+#
 def _find_dep_decls_from_clazz(name_path, clazz, dex_types):
     # XXX: implements the loop with _travel_dex_type()
     dep_decls = {}
--- a/paraspace/dexfile.py	Tue Aug 09 21:52:05 2011 +0800
+++ b/paraspace/dexfile.py	Wed Aug 10 14:04:02 2011 +0800
@@ -2085,7 +2085,8 @@
         method_typeid = methodid.classIdx
         classdef = self.find_class_typeid(method_typeid)
         
-        method = self.find_method_name_proto(method, method_proto, classdef)
+        method = self.find_method_name_proto(method_name, method_proto,
+                                             classdef)
         
         return method
 
--- a/paraspace/injection.py	Tue Aug 09 21:52:05 2011 +0800
+++ b/paraspace/injection.py	Wed Aug 10 14:04:02 2011 +0800
@@ -704,6 +704,45 @@
     pass
 
 
+## \brief Make indices map for typeid and methodid.
+#
+# It is used to create indices maps for typeid and methodid after
+# changing order.  For example, after sorting sorted array after an
+# injection, this function create maps for remapping indices mentioned
+# in the code.
+# 
+def _make_idx_map(saved_typeids, saved_methodids,
+                  new_typeids, new_methodids):
+    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)])
+    return typeidxs_map, methodidxs_map
+
+
+## \brief Sort sorted arrays and remapping indices for code blocks.
+#
+# Since sorting changes the order of sorted arrays, code blocks should
+# be updated by remapping indices, typeid indices and methodid indices.
+#
+def dex_sort_sorted_arrays_consistent(dex_linked):
+    from paraspace.dex_deptracker import dex_sort_sorted_arrays
+    
+    saved_typeids = list(dex_linked.typeIds.items)
+    saved_methodids = list(dex_linked.methodIds.items)
+    
+    dex_sort_sorted_arrays(dex_linked)
+
+    new_typeids = dex_linked.typeIds.items
+    new_methodids = dex_linked.methodIds.items
+    methodidxs_map, typeidxs_map = \
+        _make_idx_map(saved_typeids, saved_methodids, \
+                          new_typeids, new_methodids)
+    
+    dexfile_redirect_types(dex_linked, typeidxs_map, methodidxs_map)
+    pass
+
+
 ## \brief Inject and redirect a _DEX_ClassDef from one linked to another.
 #
 # The _DEX_ClassDef given by inj_classname would be inserted to dst_linked,
@@ -712,11 +751,10 @@
 #
 def inject_redir(src_linked, inj_classname,
                  dst_linked, redir_classname, decls):
-    from paraspace.dex_deptracker import dex_sort_sorted_arrays
     from paraspace.dex_deptracker import restore_dependencies
     
     inject_redir_no_restore(src_linked, inj_classname,
                             dst_linked, redir_classname, decls)
-    dex_sort_sorted_arrays(dst_linked)
+    dex_sort_sorted_arrays_consistent(dst_linked)
     restore_dependencies(dst_linked, decls)
     pass
--- a/paraspace/tests/dexfile_test.py	Tue Aug 09 21:52:05 2011 +0800
+++ b/paraspace/tests/dexfile_test.py	Wed Aug 10 14:04:02 2011 +0800
@@ -63,7 +63,7 @@
     assert isinstance(obj, dexfile.abs_value)
 
     obj, parent = _resolve_name_path('_DEX_AnnotationSetItem.annotationOffs.'
-                                     'items.0')
+                                     'items.0.offset')
     assert isinstance(obj, dexfile.depend_off)
     pass
 
@@ -95,11 +95,11 @@
     dex_types = dict([(dex_type_name, getattr(dexfile, dex_type_name))
                       for dex_type_name in dir(dexfile)
                       if dex_type_name.startswith('_DEX_')])
-    deps = _find_dep_decls_from_clazz('_DEX_AnnotationSetItem',
-                                      dexfile._DEX_AnnotationSetItem,
+    deps = _find_dep_decls_from_clazz('_DEX_AnnotationSetItem_anno_item',
+                                      dexfile._DEX_AnnotationSetItem_anno_item,
                                       dex_types)
     assert len(deps) == 1
-    name_path = '_DEX_AnnotationSetItem.annotationOffs.items.*'
+    name_path = '_DEX_AnnotationSetItem_anno_item.offset'
     assert name_path in deps
     assert deps[name_path][0] == dexfile.depend_off
     assert deps[name_path][1] == '_DEX_AnnotationItem'
--- a/paraspace/tests/injection_test.py	Tue Aug 09 21:52:05 2011 +0800
+++ b/paraspace/tests/injection_test.py	Wed Aug 10 14:04:02 2011 +0800
@@ -591,3 +591,88 @@
             pass
         pass
     pass
+
+
+## \brief Test case for dalvik complaining fail to verify code.
+#
+#    W/dalvikvm(  317): VFY: expected 1 args, found more (I)
+#    W/dalvikvm(  317): VFY:  rejecting call to Landroid/app/Activity;\
+#    .setContentView (I)V
+#    W/dalvikvm(  317): VFY:  rejecting opcode 0x6e at 0x0006
+#    W/dalvikvm(  317): VFY:  rejected Lcom/codemud/helloworld/helloworld;\
+#    .onClick (Landroid/view/View;)V
+#    W/dalvikvm(  317): Verifier rejected class Lcom/codemud/helloworld/\
+#    helloworld;
+#    W/dalvikvm(  317): Class init failed in newInstance call (Lcom/codemud/\
+#    helloworl
+#
+# DEXFile.methodIds is a sorted array.  The indices of _DEX_MethodIds would
+# be changed after injection and sorting, dex_sort_sorted_arrays().
+# It means indices in code blocks are invalid.  So, code blocks must be
+# rewrote with valid indices.
+#
+def code_verify_test():
+    from paraspace.dex_deptracker import prepare_dep_decls
+    from paraspace.injection import dex_sort_sorted_arrays_consistent
+    from paraspace.injection import inject_redir_no_restore
+    from paraspace.dalvik_opcodes import decode_insn_blk
+    
+    _install_dexfile_4_deptracker()
+    
+    all_dep_decls = prepare_dep_decls()
+    
+    srcdir = os.path.dirname(__file__)
+    datapath = os.path.join(srcdir, '..', '..', 'data')
+
+    fake_path = os.path.join(datapath, 'fakefile.dex')
+    hello_path = os.path.join(datapath, 'helloworld.dex')
+    
+    fake_dex = dexfile.DEXFile.open(fake_path)
+    fake_linked = dexfile.DEXFile_linked.build_dependencies(fake_dex,
+                                                            all_dep_decls)
+
+    hello_dex = dexfile.DEXFile.open(hello_path)
+    hello_linked = dexfile.DEXFile_linked.build_dependencies(hello_dex,
+                                                             all_dep_decls)
+
+    helloworld_typeid = \
+        hello_linked.find_typeid_name('Lcom/codemud/helloworld/helloworld;')
+    helloworld_methodids = \
+        hello_linked.find_methodids_typeid(helloworld_typeid)
+    for methodid in helloworld_methodids:
+        methodname = hello_linked.get_methodid_name(methodid)
+        if methodname == 'onClick':
+            methodidx = hello_linked.get_idx_methodid(methodid)
+            method = hello_linked.find_method_idx(methodidx)
+            blk = dexfile.DEXFile_linked.get_code_block_method(method)
+            opvectors = decode_insn_blk(blk)
+            pass
+        pass
+
+    inject_redir_no_restore(fake_linked, 'Lcom/codemud/fakefile/fakefile;',
+                            hello_linked, 'Ljava/io/File;', all_dep_decls)
+    dex_sort_sorted_arrays_consistent(hello_linked)
+
+    for methodid in hello_linked.methodIds.items:
+        methodname = hello_linked.get_methodid_name(methodid)
+        if methodname == 'setContentView':
+            protoid = methodid.protoIdx
+            sig = hello_linked.dump_protoid(protoid)
+            assert sig == '(I) --> V'
+            pass
+        pass
+
+    helloworld_typeid = \
+        hello_linked.find_typeid_name('Lcom/codemud/helloworld/helloworld;')
+    helloworld_methodids = \
+        hello_linked.find_methodids_typeid(helloworld_typeid)
+    for methodid in helloworld_methodids:
+        methodname = hello_linked.get_methodid_name(methodid)
+        if methodname == 'onClick':
+            methodidx = hello_linked.get_idx_methodid(methodid)
+            method = hello_linked.find_method_idx(methodidx)
+            blk = dexfile.DEXFile_linked.get_code_block_method(method)
+            opvectors = decode_insn_blk(blk)
+            pass
+        pass
+    pass