# HG changeset patch # User Thinker K.F. Li # Date 1312956242 -28800 # Node ID 987fead83ce3bab91f1debd61628b4314a23964f # Parent f31bfe55d9c234e9c778191ab8f574fe9ce0c320 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. diff -r f31bfe55d9c2 -r 987fead83ce3 paraspace/dex_deptracker.py --- 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 = {} diff -r f31bfe55d9c2 -r 987fead83ce3 paraspace/dexfile.py --- 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 diff -r f31bfe55d9c2 -r 987fead83ce3 paraspace/injection.py --- 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 diff -r f31bfe55d9c2 -r 987fead83ce3 paraspace/tests/dexfile_test.py --- 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' diff -r f31bfe55d9c2 -r 987fead83ce3 paraspace/tests/injection_test.py --- 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