def retrieve_string_value(string_ptr): length_val = memory.readMemory32(string_ptr + config.offset_string_length) reference_ptr = memory.readMemory32(string_ptr + config.offset_string_reference) char_array = memory.retrieve_char_array(reference_ptr) return char_array
def resolve_mirror_Class(class_ptr): # find the clinit_thread_id_ field address_Class_clinit_thread_id_ = class_ptr pid_val = int(execution_state.getVariableService().readValue("$AARCH64::$System::$Memory::$CONTEXTIDR_EL1.PROCID")) & 0xffffffff while True: if memory.readMemory32(address_Class_clinit_thread_id_) == pid_val: break else: address_Class_clinit_thread_id_ = address_Class_clinit_thread_id_ + 0x4 # get the methods_ field address_methods_ = address_Class_clinit_thread_id_ - 0x4 - 0x4 - 0x4 - 0x8 - 0x8 methods_array_ptr = memory.readMemory32(address_methods_) methods_cnt = memory.readMemory32(methods_array_ptr) if config.debug: print "[ClassModification] len(methods_) = %#x" % methods_cnt method_list = [] current_method_ptr = methods_array_ptr + 0x4 for idx in range(methods_cnt): field_0 = current_method_ptr + config.offset_ArtMethod_declaring_class_ # specially, we record the address rather than its value field_1 = memory.readMemory32(current_method_ptr + config.offset_ArtMethod_access_flags_) field_2 = memory.readMemory32(current_method_ptr + config.offset_ArtMethod_dex_code_item_offset_) field_3 = memory.readMemory32(current_method_ptr + config.offset_ArtMethod_dex_method_index_) field_4 = memory.readMemory16(current_method_ptr + config.offset_ArtMethod_method_index_) field_5 = memory.readMemory16(current_method_ptr + config.offset_ArtMethod_hotness_count_) field_6 = memory.readMemory32(current_method_ptr + config.offset_ArtMethod_dex_cache_resolved_methods_) field_7 = memory.readMemory32(current_method_ptr + config.offset_ArtMethod_data_) field_8 = memory.readMemory32(current_method_ptr + config.offset_ArtMethod_entry_point_from_quick_compiled_code) method_list.append((field_0, field_1, field_2, field_3, field_4, field_5, field_6, field_7, field_8)) current_method_ptr = current_method_ptr + 0x20 return method_list
def parse_proto_id_item(dex_file_off, proto_ids_off, proto_id): proto_id_item_ptr = dex_file_off + proto_ids_off + proto_id * 0xc shorty_idx = memory.readMemory32(proto_id_item_ptr + offset_shorty_idx) return_type_idx = memory.readMemory32(proto_id_item_ptr + offset_return_type_idx) parameters_off = memory.readMemory32(proto_id_item_ptr + offset_parameters_off) type_list_ptr = dex_file_off + parameters_off type_list_size = memory.readMemory32(type_list_ptr + offset_type_list_size) type_list_list_ptr = type_list_ptr + offset_type_list_list type_item_list = [] for type_item_idx in range(type_list_size): type_idx = memory.readMemory16(type_list_list_ptr + type_item_idx * 0x2) type_item_list.append(type_idx)
def get_string_id_item_data_off(dex_file_off, string_ids_off, string_id): string_data_item_ptr = dex_file_off + string_ids_off + string_id * 0x4 string_data_item_off = memory.readMemory32(string_data_item_ptr + offset_string_data_off) utf16_size, offset_data_off = utility.readuleb128(dex_file_off + string_data_item_off + offset_utf16_size_off) return dex_file_off + string_data_item_off + offset_data_off
def parse_string_id_item(dex_file_off, string_ids_off, string_id): string_data_item_ptr = dex_file_off + string_ids_off + string_id * 0x4 string_data_item_off = memory.readMemory32(string_data_item_ptr + offset_string_data_off) utf16_size, offset_data_off = utility.readuleb128(dex_file_off + string_data_item_off + offset_utf16_size_off) data = memory.retrieve_char_array(dex_file_off + string_data_item_off + offset_data_off)
def get_parameters_list(dex_file_off, proto_ids_off, proto_id): proto_id_item_ptr = dex_file_off + proto_ids_off + proto_id * 0xc parameters_off = memory.readMemory32(proto_id_item_ptr + offset_parameters_off) if parameters_off == 0: # it refers that this prototype has no parameters return [] type_list_ptr = dex_file_off + parameters_off type_list_size = memory.readMemory32(type_list_ptr + offset_type_list_size) assert type_list_size < 100 type_list_list_ptr = type_list_ptr + offset_type_list_list type_item_list = [] for type_item_idx in range(type_list_size): type_idx = memory.readMemory16(type_list_list_ptr + type_item_idx * 0x2) type_item_list.append(type_idx) return type_item_list
def RegisterNatives(): class_ptr = int( execution_state.getRegisterService().getValue("R1")) & 0xffffffff methods_ptr = int( execution_state.getRegisterService().getValue("R2")) & 0xffffffff method_count = int( execution_state.getRegisterService().getValue("R3")) & 0xffffffff for idx in range(method_count): method_name_ptr = memory.readMemory32((methods_ptr + idx * 0xc) + 0x0) method_name_val = memory.retrieve_char_array(method_name_ptr) method_subsignature_ptr = memory.readMemory32((methods_ptr + idx * 0xc) + 0x4) method_subsignature_val = memory.retrieve_char_array( method_subsignature_ptr) method_pointer_ptr = (methods_ptr + idx * 0xc) + 0x8 method_pointer_val = memory.readMemory32(method_pointer_ptr) config.log_print( "[RegisterNatives] signature = %s%s, method_ptr = %0#10x" % (method_name_val, method_subsignature_val, method_pointer_val)) # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def FindClass(): # -- HEAD -- # start_prolog() # -- BODY -- # # get the "soa" parameter soa_param = int( execution_state.getRegisterService().getValue("R1")) & 0xffffffff # retrieve the "self_" field (i.e., Thread* const self_) thread_ptr = memory.readMemory32(soa_param) # get the "descriptor" parameter descriptor_param = int( execution_state.getRegisterService().getValue("R2")) & 0xffffffff descriptor_ptr = descriptor_param # read the "descriptor" string descriptor_string_val = memory.retrieve_char_array(descriptor_ptr) print "[FindClass] descriptor = %s" % descriptor_string_val if config.package_name.replace(".", "/") in descriptor_string_val: mirror_class_names, mirror_class_ptrs = force_loading( descriptor_string_val) config.save_class_info(thread_ptr, mirror_class_names, mirror_class_ptrs) # -- TAIL -- # end_prolog_done() else: # -- TAIL -- # end_prolog() # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def get_proto_ids_off(header_item_ptr): return memory.readMemory32(header_item_ptr + offset_proto_ids_off)
def init_art(): # get the PID pid_val = int(execution_state.getVariableService().readValue( "$AARCH64::$System::$Memory::$CONTEXTIDR_EL1.PROCID")) & 0xffffffff # -1- # read the "name" parameter name_ptr = int( execution_state.getRegisterService().getValue("R0")) & 0xffffffff name_val = memory.retrieve_char_array(name_ptr) # read the "flags" parameter flags_val = int( execution_state.getRegisterService().getValue("R1")) & 0xffffffff # read the "extinfo" parameter extinfo_ptr = int( execution_state.getRegisterService().getValue("R2")) & 0xffffffff if config.debug: print "[entrypoint] [do_dlopen] pid = %#x" % pid_val print "[entrypoint] [do_dlopen] name = %s" % name_val print "[entrypoint] [do_dlopen] flags_val = %#x" % flags_val print "[entrypoint] [do_dlopen] extinfo_ptr = %0#10x" % extinfo_ptr # the first loaded Oat file must be our target if not config.package_filter(name_val): # should not be reached assert False config.log_print("[entrypoint] [do_dlopen] pid = %#x" % pid_val) # -2- # goto the invocation of the find_library method brk_find_library_offset = config.linker_base + find_library_offset - config.linker_file_offset + config.linker_memory_offset execution_state.getExecutionService().resumeTo(brk_find_library_offset) try: execution_state.getExecutionService().waitForStop( 120000) # wait for 120s except DebugException: raise RuntimeError("wtf !!!") # retrieve soinfo pointer si_ptr = int( execution_state.getRegisterService().getValue("R0")) & 0xffffffff if config.debug: print "[entrypoint] [do_dlopen] si = %0#10x" % si_ptr base_ptr = si_ptr + config.offset_soinfo_base base_val = memory.readMemory32(base_ptr) size_ptr = si_ptr + config.offset_soinfo_size size_val = memory.readMemory32(size_ptr) if base_val == 0x0 or size_val == 0x0: # -3- # goto the invocation of the call_constructors method brk_call_constructors_offset = config.linker_base + call_constructors_offset - config.linker_file_offset + config.linker_memory_offset execution_state.getExecutionService().resumeTo( brk_call_constructors_offset) try: execution_state.getExecutionService().waitForStop( 120000) # wait for 120s except DebugException: raise RuntimeError("wtf !!!") base_ptr = si_ptr + config.offset_soinfo_base base_val = memory.readMemory32(base_ptr) size_ptr = si_ptr + config.offset_soinfo_size size_val = memory.readMemory32(size_ptr) if config.debug: print "[entrypoint] [do_dlopen] si->base = %0#10x" % base_val print "[entrypoint] [do_dlopen] si->size = %#x" % size_val config.log_print( "[entrypoint] [do_dlopen] name = %s, si->base = %0#10x, si->size = %#x" % (name_val, base_val, size_val)) if not base_val == 0x0: config.save_range_info(base_val, base_val + size_val - 0x1) # initialization setup(pid_val) # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def gettimeofday(): pid = int(execution_state.getVariableService().readValue( "$AARCH64::$System::$Memory::$CONTEXTIDR_EL1.PROCID")) & 0xffffffff # get timeval pointer and timezone pointer timeval_ptr = int( execution_state.getRegisterService().getValue("R0")) & 0xffffffff timezone_ptr = int( execution_state.getRegisterService().getValue("R1")) & 0xffffffff if config.debug: print "[gettimeofday] pid = %#x, timeval_ptr = %0#10x, timezone_ptr = %0#10x" % ( pid, timeval_ptr, timezone_ptr) config.log_print( "[gettimeofday] pid = %#x, timeval_ptr = %0#10x, timezone_ptr = %0#10x" % (pid, timeval_ptr, timezone_ptr)) if timeval_ptr == 0x0: execution_state.getExecutionService().resume() cleanup() return # disable itself for idx in range( 0, execution_state.getBreakpointService().getBreakpointCount()): brk_object = execution_state.getBreakpointService().getBreakpoint(idx) if (int(brk_object.getAddresses()[0]) & 0xffffffff) == config.brk_gettimeofday: brk_object.disable() brk_gettimeofday = config.libc_base + config.gettimeofday_end - config.libc_file_offset + config.libc_memory_offset execution_state.getExecutionService().resumeTo(brk_gettimeofday) try: execution_state.getExecutionService().waitForStop( 60000) # wait for 60s except DebugException: raise RuntimeError("wtf !!!") # obtain tv_sec value tv_sec_ptr = timeval_ptr + 0x0 tv_sec = memory.readMemory32(tv_sec_ptr) # obtain tv_usec_value tv_usec_ptr = timeval_ptr + 0x4 tv_usec = memory.readMemory32(tv_usec_ptr) if config.debug: print "[gettimeofday] (origin) pid = %#x, tv_sec = %0#10x, tv_usec = %0#10x" % ( pid, tv_sec, tv_usec) config.log_print( "[gettimeofday] (origin) pid = %#x, tv_sec = %0#10x, tv_usec = %0#10x" % (pid, tv_sec, tv_usec)) # anti time checking tv_sec_old, tv_usec_old = config.load_time_info() if tv_sec < tv_sec_old: pass else: if tv_sec_old != 0 and tv_usec_old != 0: time_interval = (tv_sec * 1000000L + tv_usec) - (tv_sec_old * 1000000L + tv_usec_old) if time_interval > 1 * TIME_INTERVAL: tv_sec_new = int( ((tv_sec_old * 1000000L + tv_usec_old) + 1 * TIME_INTERVAL) / 1000000L) tv_usec_new = int(((tv_sec_old * 1000000L + tv_usec_old) + 1 * TIME_INTERVAL) - (tv_sec_new * 1000000L)) time_old = tv_sec_old * 1000000L + tv_usec_old time_new = tv_sec_new * 1000000L + tv_usec_new assert time_new == (time_old + 1 * TIME_INTERVAL) time_memory_old = tv_sec_old * (2**32) * 1L + tv_usec_old print "[old] sec = %#x, usec = %#x, in-memory = %#x" % ( tv_sec_old, tv_usec_old, time_memory_old) time_memory_new = tv_sec_new * (2**32) * 1L + tv_usec_new print "[new] sec = %#x, usec = %#x, in-memory = %#x" % ( tv_sec_new, tv_usec_new, time_memory_new) config.save_time_info(tv_sec_new, tv_usec_new) memory_set_cmd = "memory set %0#10x 0 %#x" % (timeval_ptr + 0x0, tv_sec_new) execution_state.executeDSCommand(memory_set_cmd) memory_set_cmd = "memory set %0#10x 0 %#x" % (timeval_ptr + 0x4, tv_usec_new) execution_state.executeDSCommand(memory_set_cmd) # obtain tv_sec value tv_sec_ptr = timeval_ptr + 0x0 tv_sec = memory.readMemory32(tv_sec_ptr) # obtain tv_usec_value tv_usec_ptr = timeval_ptr + 0x4 tv_usec = memory.readMemory32(tv_usec_ptr) if config.debug: print "[gettimeofday] (adjust) pid = %#x, tv_sec = %0#10x, tv_usec = %0#10x" % ( pid, tv_sec, tv_usec) config.log_print( "[gettimeofday] (adjust) pid = %#x, tv_sec = %0#10x, tv_usec = %0#10x" % (pid, tv_sec, tv_usec)) else: config.save_time_info(tv_sec, tv_usec) elif tv_sec_old == 0 and tv_usec_old == 0: config.save_time_info(tv_sec, tv_usec) else: raise RuntimeError("invalid timeval valus !!!") # enable itself for idx in range( 0, execution_state.getBreakpointService().getBreakpointCount()): brk_object = execution_state.getBreakpointService().getBreakpoint(idx) if (int(brk_object.getAddresses()[0]) & 0xffffffff) == config.brk_gettimeofday: brk_object.enable() # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def LoadMethod(): # -1- # get the "dst" parameter dst_ptr = int(execution_state.getRegisterService().getValue("SP")) + 0x4 dst_val = memory.readMemory32(dst_ptr) if config.debug: print "[LoadMethod] dst = %0#10x" % dst_val # very strange !!! if (dst_val == 0x0) or (dst_val == 0x00000001): execution_state.getExecutionService().resume() return # get the return address of the LoadMethod brk_return_address = int( execution_state.getRegisterService().getValue("LR")) & 0xfffffffe if config.debug: print "[LoadMethod] return address = %0#10x" % brk_return_address # -2- # resume to the end of the LoadMethod brk_LoadMethod_end = config.libart_base + config.LoadMethod_end - config.libart_file_offset + config.libart_memory_offset execution_state.getExecutionService().resumeTo(brk_LoadMethod_end) try: execution_state.getExecutionService().waitForStop( 120000) # wait for 120s except DebugException: raise RuntimeError("wtf !!!") # get the pointer that refers to ArtMethod art_method_ptr = dst_val # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[LoadMethod] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[LoadMethod] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[LoadMethod] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # we only focus on the Java invocation appeared in the target package if not config.package_filter(dex_file_location_string_val): # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[LoadMethod] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[LoadMethod] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "tries_size" field of the "DexFile::CodeItem" structure tries_size_off = ( (dex_file_begin_val + art_method_dex_code_item_offset_value) & 0xffffffff) + config.offset_DexFile_CodeItem_tries_size_ tries_size_val = memory.readMemory16(tries_size_off) if config.debug: print "[LoadMethod] ArtMethod::CodeItem::tries_size_ = %#x" % tries_size_val # read the "insns_size_in_code_units_" field of the "DexFile::CodeItem" structure code_item_insns_size_in_code_units_off = ( (dex_file_begin_val + art_method_dex_code_item_offset_value) & 0xffffffff) + config.offset_DexFile_CodeItem_insns_size_in_code_units_ code_item_insns_size_in_code_units_val = memory.readMemory32( code_item_insns_size_in_code_units_off) if config.debug: print "[LoadMethod] ArtMethod::CodeItem::insns_size_in_code_units_ = %#x" % code_item_insns_size_in_code_units_val # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[LoadMethod] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[LoadMethod] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[LoadMethod] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[LoadMethod] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[DoCall] parameters = %s" % parameters_content method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[LoadMethod] method signature = %s" % method_signature config.log_print("[LoadMethod] origin method signature = %s" % method_signature) origin_ArtMethod_declaring_class = class_ptr origin_ArtMethod_access_flags = art_method_access_flags_value origin_ArtMethod_dex_code_item_offset = art_method_dex_code_item_offset_value origin_ArtMethod_dex_method_index = art_method_dex_method_index_val origin_ArtMethod_signature = method_signature # -3- # resume to the return address of the LoadMethod execution_state.getExecutionService().resumeTo(brk_return_address) try: execution_state.getExecutionService().waitForStop( 120000) # wait for 120s except DebugException: raise RuntimeError("wtf !!!") # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[LoadMethod] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[LoadMethod] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[LoadMethod] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # # we only focus on the Java invocation appeared in the target package # if not config.package_filter(dex_file_location_string_val): # # continue the execution of the target application # execution_state.getExecutionService().resume() # cleanup() # return # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[LoadMethod] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[LoadMethod] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "tries_size" field of the "DexFile::CodeItem" structure tries_size_off = ( (dex_file_begin_val + art_method_dex_code_item_offset_value) & 0xffffffff) + config.offset_DexFile_CodeItem_tries_size_ tries_size_val = memory.readMemory16(tries_size_off) if config.debug: print "[LoadMethod] ArtMethod::CodeItem::tries_size_ = %#x" % tries_size_val # read the "insns_size_in_code_units_" field of the "DexFile::CodeItem" structure code_item_insns_size_in_code_units_off = ( (dex_file_begin_val + art_method_dex_code_item_offset_value) & 0xffffffff) + config.offset_DexFile_CodeItem_insns_size_in_code_units_ code_item_insns_size_in_code_units_val = memory.readMemory32( code_item_insns_size_in_code_units_off) if config.debug: print "[LoadMethod] ArtMethod::CodeItem::insns_size_in_code_units_ = %#x" % code_item_insns_size_in_code_units_val # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[LoadMethod] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[LoadMethod] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[LoadMethod] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[LoadMethod] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[DoCall] parameters = %s" % parameters_content method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[LoadMethod] method signature = %s" % method_signature config.log_print("[LoadMethod] suspicious method signature = %s" % method_signature) suspicious_ArtMethod_declaring_class = class_ptr suspicious_ArtMethod_access_flags = art_method_access_flags_value suspicious_ArtMethod_dex_code_item_offset = art_method_dex_code_item_offset_value suspicious_ArtMethod_dex_method_index = art_method_dex_method_index_val suspicious_ArtMethod_signature = method_signature # if (origin_ArtMethod_declaring_class != suspicious_ArtMethod_declaring_class) or \ # (origin_ArtMethod_access_flags != suspicious_ArtMethod_access_flags) or \ # (origin_ArtMethod_dex_code_item_offset != suspicious_ArtMethod_dex_code_item_offset): # config.log_print("[LoadMethod] hooked !!!") # assert origin_ArtMethod_dex_method_index == suspicious_ArtMethod_dex_method_index # config.log_print("[LoadMethod][origin] declaring_class_ = %0#10x, access_flags_ = %#x, dex_code_item_offset_ = %0#10x" % (origin_ArtMethod_declaring_class, origin_ArtMethod_access_flags, origin_ArtMethod_dex_code_item_offset)) # config.log_print("[LoadMethod][suspicious] declaring_class_ = %0#10x, access_flags_ = %#x, dex_code_item_offset_ = %0#10x" % (suspicious_ArtMethod_declaring_class, suspicious_ArtMethod_access_flags, suspicious_ArtMethod_dex_code_item_offset)) # # dump the code_item on-demand # padding = 0x2 if (tries_size_val > 0) and (code_item_insns_size_in_code_units_val % 2 == 1) else 0x0 # code_item_size = config.offset_DexFile_CodeItem_insns_size_in_code_units_ + 0x4 + 0x2 * code_item_insns_size_in_code_units_val + padding + 0x8 * tries_size_val # code_item_size = code_item_size + encoded_catch_handler_list.parse_encoded_catch_handler_list(dex_file_begin_val, suspicious_ArtMethod_dex_code_item_offset + code_item_size, tries_size_val) # file_path = os.path.join(config.workspace, config.dex_directory, "code_item_%#x_%0#10x.bin" % (origin_ArtMethod_dex_method_index, origin_ArtMethod_dex_code_item_offset)) # file_format = "binary" # file_vtl_start_address = (dex_file_begin_val + suspicious_ArtMethod_dex_code_item_offset) & 0xffffffff # file_vtl_end_address = ((dex_file_begin_val + suspicious_ArtMethod_dex_code_item_offset) & 0xffffffff) + code_item_size - 0x1 # memory.dump(file_path, file_format, file_vtl_start_address, file_vtl_end_address) # Notice: for ijiami-16, we force dump the code_item if (art_method_dex_code_item_offset_value != 0x0): padding = 0x2 if (tries_size_val > 0) and ( code_item_insns_size_in_code_units_val % 2 == 1) else 0x0 code_item_size = config.offset_DexFile_CodeItem_insns_size_in_code_units_ + 0x4 + 0x2 * code_item_insns_size_in_code_units_val + padding + 0x8 * tries_size_val code_item_size = code_item_size + encoded_catch_handler_list.parse_encoded_catch_handler_list( dex_file_begin_val, suspicious_ArtMethod_dex_code_item_offset + code_item_size, tries_size_val) file_path = os.path.join( config.workspace, config.dex_directory, "code_item_%#x_%0#10x.bin" % (origin_ArtMethod_dex_method_index, origin_ArtMethod_dex_code_item_offset)) file_format = "binary" file_vtl_start_address = ( dex_file_begin_val + suspicious_ArtMethod_dex_code_item_offset) & 0xffffffff file_vtl_end_address = ( (dex_file_begin_val + suspicious_ArtMethod_dex_code_item_offset) & 0xffffffff) + code_item_size - 0x1 memory.dump(file_path, file_format, file_vtl_start_address, file_vtl_end_address) # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def parse_header_item(header_item_ptr): magic = memory.retrieve_byte_array(header_item_ptr + offset_magic, 0x8) checksum = memory.readMemory32(header_item_ptr + offset_checksum) signature = memory.retrieve_byte_array(header_item_ptr + offset_signature, 0x14) file_szie = memory.readMemory32(header_item_ptr + offset_file_size) header_size = memory.readMemory32(header_item_ptr + offset_header_size) assert header_size == 0x70 endian_tag = memory.readMemory32(header_item_ptr + offset_endian_tag) link_size = memory.readMemory32(header_item_ptr + offset_link_size) link_off = memory.readMemory32(header_item_ptr + offset_link_off) map_off = memory.readMemory32(header_item_ptr + offset_map_off) string_ids_size = memory.readMemory32(header_item_ptr + offset_string_ids_size) string_ids_off = memory.readMemory32(header_item_ptr + offset_string_ids_off) type_ids_size = memory.readMemory32(header_item_ptr + offset_type_ids_size) type_ids_off = memory.readMemory32(header_item_ptr + offset_type_ids_off) proto_ids_size = memory.readMemory32(header_item_ptr + offset_proto_ids_size) proto_ids_off = memory.readMemory32(header_item_ptr + offset_proto_ids_off) field_ids_size = memory.readMemory32(header_item_ptr + offset_field_ids_size) field_ids_off = memory.readMemory32(header_item_ptr + offset_field_ids_off) method_ids_size = memory.readMemory32(header_item_ptr + offset_method_ids_size) method_ids_off = memory.readMemory32(header_item_ptr + offset_method_ids_off) class_defs_size = memory.readMemory32(header_item_ptr + offset_class_defs_size) class_defs_off = memory.readMemory32(header_item_ptr + offset_class_defs_off) data_size = memory.readMemory32(header_item_ptr + offset_data_size) data_off = memory.readMemory32(header_item_ptr + offset_data_off) if config.debug: print "[header_item] magic = %s" % byte_array_to_hex_string(magic) print "[header_item] checksum = %#x" % checksum print "[header_item] signature = %s" % byte_array_to_hex_string( signature) print "[header_item] file_szie = %#x" % file_szie print "[header_item] header_size = %#x" % header_size print "[header_item] endian_tag = %#x" % endian_tag print "[header_item] link_size = %#x" % link_size print "[header_item] link_off = %#x" % link_off print "[header_item] map_off = %#x" % map_off print "[header_item] string_ids_size = %#x" % string_ids_size print "[header_item] string_ids_off = %#x" % string_ids_off print "[header_item] type_ids_size = %#x" % type_ids_size print "[header_item] type_ids_off = %#x" % type_ids_off print "[header_item] proto_ids_size = %#x" % proto_ids_size print "[header_item] proto_ids_off = %#x" % proto_ids_off print "[header_item] field_ids_size = %#x" % field_ids_size print "[header_item] field_ids_off = %#x" % field_ids_off print "[header_item] method_ids_size = %#x" % method_ids_size print "[header_item] method_ids_off = %#x" % method_ids_off print "[header_item] class_defs_size = %#x" % class_defs_size print "[header_item] class_defs_off = %#x" % class_defs_off print "[header_item] data_size = %#x" % data_size print "[header_item] data_off = %#x" % data_off
def ArtInterpreterToCompiledCodeBridge(): # # *essential* for robustness, remove the ArtQuickToInterpreterBridge breakpoint to guarantee that we have at least one available hardware breakpoint # rm_brks = [] # for breakpoint_index in range(0, execution_state.getBreakpointService().getBreakpointCount()): # breakpoint_object = execution_state.getBreakpointService().getBreakpoint(breakpoint_index) # if (int(breakpoint_object.getAddresses()[0]) & 0xffffffff) == config.brk_ArtQuickToInterpreterBridge: # rm_brks.append(breakpoint_object) # for brk_obj in rm_brks: # brk_obj.remove() # -1- for caller # get the "caller" parameter caller_ptr = int(execution_state.getRegisterService().getValue("R1")) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] caller = %0#10x" % caller_ptr # get the pointer that refers to ArtMethod art_method_ptr = caller_ptr # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # # we only focus on the method invocation from the target package # if not config.package_filter(dex_file_location_string_val): # # continue the execution of the target application # execution_state.getExecutionService().resume() # cleanup() # return # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[ArtInterpreterToCompiledCodeBridge] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[ArtInterpreterToCompiledCodeBridge] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[ArtInterpreterToCompiledCodeBridge] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[ArtInterpreterToCompiledCodeBridge] parameters = %s" % parameters_content caller_method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] caller signature = %s" % caller_method_signature # -2- for callee # get the "shadow_frame" parameter shadow_frame_ptr = int(execution_state.getRegisterService().getValue("R2")) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] shadow_frame = %0#10x" % shadow_frame_ptr # retrieve the "method_" field of ShadowFrame structure shadow_frame_method_ptr = memory.readMemory32( shadow_frame_ptr + config.offset_ShadowFrame_method_) # get the pointer that refers to ArtMethod art_method_ptr = shadow_frame_method_ptr # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # if config.package_filter(dex_file_location_string_val): # # we make an assumption that method invocations within the target package will not trigger the ArtQuickToInterpreterBridge breakpoint # pass # else: # # reset the ArtQuickToInterpreterBridge breakpoint itself # pid = int(execution_state.getVariableService().readValue("$AARCH64::$System::$Memory::$CONTEXTIDR_EL1.PROCID")) & 0xffffffff # brk_ArtQuickToInterpreterBridge_cmd = "hbreak" + " " + str(hex(config.brk_ArtQuickToInterpreterBridge)).replace('L', '') + " " + "context" + " " + str(hex(pid)).replace('L', '') # execution_state.executeDSCommand(brk_ArtQuickToInterpreterBridge_cmd) # for idx in range(0, execution_state.getBreakpointService().getBreakpointCount()): # brk_object = execution_state.getBreakpointService().getBreakpoint(idx) # if (int(brk_object.getAddresses()[0]) & 0xffffffff) == config.brk_ArtQuickToInterpreterBridge: # bs_ArtQuickToInterpreterBridge_cmd = "break-script" + " " + str(brk_object.getId()) + " " + os.path.join(config.workspace, config.script_directory, config.ArtQuickToInterpreterBridge_script) # execution_state.executeDSCommand(bs_ArtQuickToInterpreterBridge_cmd) # brk_object.enable() # # # continue the execution of the target application # # execution_state.getExecutionService().resume() # # return # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[ArtInterpreterToCompiledCodeBridge] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[ArtInterpreterToCompiledCodeBridge] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[ArtInterpreterToCompiledCodeBridge] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[ArtInterpreterToCompiledCodeBridge] parameters = %s" % parameters_content callee_method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[ArtInterpreterToCompiledCodeBridge] callee signature = %s" % callee_method_signature config.log_print( "[ArtInterpreterToCompiledCodeBridge] caller signature = %s" % caller_method_signature) config.log_print( "[ArtInterpreterToCompiledCodeBridge] callee signature = %s" % callee_method_signature) # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def get_class_idx(dex_file_off, class_defs_off, class_def_id): class_def_item_ptr = dex_file_off + class_defs_off + class_def_id * 0x20 return memory.readMemory32(class_def_item_ptr + offset_class_idx)
def dump_modified_method(origin_method_list, suspicious_method_list): assert len(origin_method_list) == len(suspicious_method_list) for idx in range(len(origin_method_list)): origin_method = origin_method_list[idx] suspicious_method = suspicious_method_list[idx] if origin_method != suspicious_method: assert origin_method[0] == suspicious_method[0] assert origin_method[3] == suspicious_method[3] # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = origin_method[0] # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32(art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32(class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) art_method_dex_method_index_val = origin_method[3] # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx(dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, class_descriptor_idx) name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, name_idx) proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx(dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx(dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list(dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx(dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content method_signature = "?? %s->%s %s%s" % (class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) config.log_print("[ClassModification] mirror::Class has been modified !!!") config.log_print("[ClassModification][origin] signature = %s, access_flags_ = %#x, dex_code_item_offset_ = %0#10x, entry_point_from_quick_compiled_code = %0#10x" % (method_signature, origin_method[1], origin_method[2], origin_method[8])) config.log_print("[ClassModification][suspicious] signature = %s, access_flags_ = %#x, dex_code_item_offset_ = %0#10x, entry_point_from_quick_compiled_code = %0#10x" % (method_signature, suspicious_method[1], suspicious_method[2], suspicious_method[8])) if origin_method[2] != suspicious_method[2]: # dump the code_item on-demand tries_size_off = ((dex_file_begin_val + suspicious_method[2]) & 0xffffffff) + config.offset_DexFile_CodeItem_tries_size_ print "[ClassModification] tries_size_off = %#x" % tries_size_off tries_size_val = memory.readMemory16(tries_size_off) code_item_insns_size_in_code_units_off = ((dex_file_begin_val + suspicious_method[2]) & 0xffffffff) + config.offset_DexFile_CodeItem_insns_size_in_code_units_ print "[ClassModification] code_item_insns_size_in_code_units_off = %#x" % code_item_insns_size_in_code_units_off code_item_insns_size_in_code_units_val = memory.readMemory32(code_item_insns_size_in_code_units_off) padding = 0x2 if (tries_size_val > 0) and (code_item_insns_size_in_code_units_val % 2 == 1) else 0x0 code_item_size = config.offset_DexFile_CodeItem_insns_size_in_code_units_ + 0x4 + 0x2 * code_item_insns_size_in_code_units_val + padding + 0x8 * tries_size_val code_item_size = code_item_size + encoded_catch_handler_list.parse_encoded_catch_handler_list(dex_file_begin_val, suspicious_method[2] + code_item_size, tries_size_val) file_path = os.path.join(config.workspace, config.dex_directory, "code_item_%#x_%0#10x.bin" % (origin_method[3], origin_method[2])) file_format = "binary" file_vtl_start_address = (dex_file_begin_val + suspicious_method[2]) & 0xffffffff file_vtl_end_address = ((dex_file_begin_val + suspicious_method[2]) & 0xffffffff) + code_item_size - 0x1 memory.dump(file_path, file_format, file_vtl_start_address, file_vtl_end_address)
def force_initializing(origin_class_ptr, mirror_class_ptrs, mirror_class_names): # save register values origin_R0_val = int(execution_state.getRegisterService().getValue("R0")) & 0xffffffff origin_R1_val = int(execution_state.getRegisterService().getValue("R1")) & 0xffffffff origin_R2_val = int(execution_state.getRegisterService().getValue("R2")) & 0xffffffff origin_R3_val = int(execution_state.getRegisterService().getValue("R3")) & 0xffffffff origin_R9_val = int(execution_state.getRegisterService().getValue("R9")) & 0xffffffff origin_R10_val = int(execution_state.getRegisterService().getValue("R10")) & 0xffffffff origin_R11_val = int(execution_state.getRegisterService().getValue("R11")) & 0xffffffff origin_R12_val = int(execution_state.getRegisterService().getValue("R12")) & 0xffffffff origin_SP_val = int(execution_state.getRegisterService().getValue("SP")) & 0xffffffff origin_LR_val = int(execution_state.getRegisterService().getValue("LR")) & 0xffffffff origin_CPSR_val = int(execution_state.getRegisterService().getValue("CPSR")) & 0xffffffff # save stack content page_size = 0x1000 page_vtl_start_address = origin_SP_val - (origin_SP_val % page_size) # print "[InitClass] origin SP = %0#10x" % origin_SP_val # print "[InitClass] origin page = %0#10x" % page_vtl_start_address origin_content = execution_state.getMemoryService().read(page_vtl_start_address, page_size) # print origin_content for idx in range(len(mirror_class_ptrs)): class_name = mirror_class_names[idx] print "[InitClass] force init class -> %s" % class_name config.log_print("[InitClass] force init class -> %s" % (class_name)) class_ptr = mirror_class_ptrs[idx] # recover register values execution_state.getRegisterService().setValue("R0", origin_R0_val) execution_state.getRegisterService().setValue("R1", origin_R1_val) execution_state.getRegisterService().setValue("R2", origin_R2_val) execution_state.getRegisterService().setValue("R3", origin_R3_val) execution_state.getRegisterService().setValue("R9", origin_R9_val) execution_state.getRegisterService().setValue("R10", origin_R10_val) execution_state.getRegisterService().setValue("R11", origin_R11_val) execution_state.getRegisterService().setValue("R12", origin_R12_val) execution_state.getRegisterService().setValue("SP", origin_SP_val) execution_state.getRegisterService().setValue("LR", origin_LR_val) execution_state.getRegisterService().setValue("CPSR", origin_CPSR_val) # recover stack content execution_state.getMemoryService().write(page_vtl_start_address, origin_content) # hook execution_state.getMemoryService().writeMemory32(origin_R2_val, class_ptr) # execute while True: execution_state.getExecutionService().resumeTo(config.brk_InitClass_end) try: execution_state.getExecutionService().waitForStop(10 * 60 * 1000) # wait for 10mins except DebugException: raise RuntimeError("wtf !!!") reference_ptr = int(execution_state.getRegisterService().getValue("R4")) & 0xffffffff ret_address = memory.readMemory32((int(execution_state.getRegisterService().getValue("SP")) & 0xffffffff) + 0x20 + 0x4 * 5) if origin_LR_val == ret_address and origin_R2_val == reference_ptr: break execution_state.getRegisterService().setValue("PC", config.brk_InitClass) print "[InitClass] force init done <- %s" % class_name config.log_print("[InitClass] force init done <- %s" % (class_name)) # recover register values execution_state.getRegisterService().setValue("R0", origin_R0_val) execution_state.getRegisterService().setValue("R1", origin_R1_val) execution_state.getRegisterService().setValue("R2", origin_R2_val) execution_state.getRegisterService().setValue("R3", origin_R3_val) execution_state.getRegisterService().setValue("R9", origin_R9_val) execution_state.getRegisterService().setValue("R10", origin_R10_val) execution_state.getRegisterService().setValue("R11", origin_R11_val) execution_state.getRegisterService().setValue("R12", origin_R12_val) execution_state.getRegisterService().setValue("SP", origin_SP_val) execution_state.getRegisterService().setValue("LR", origin_LR_val) execution_state.getRegisterService().setValue("CPSR", origin_CPSR_val) # recover stack content execution_state.getMemoryService().write(page_vtl_start_address, origin_content) # recover memory content execution_state.getMemoryService().writeMemory32(origin_R2_val, origin_class_ptr) return
def get_method_ids_off(header_item_ptr): return memory.readMemory32(header_item_ptr + offset_method_ids_off)
def get_descriptor_idx(dex_file_off, type_ids_off, type_id): type_id_item_ptr = dex_file_off + type_ids_off + type_id * 0x4 return memory.readMemory32(type_id_item_ptr + offset_descriptor_idx)
def parse_type_id_item(dex_file_off, type_ids_off, type_id): type_id_item_ptr = dex_file_off + type_ids_off + type_id * 0x4 descriptor_idx = memory.readMemory32(type_id_item_ptr + offset_descriptor_idx)
def InvokeWithArgArray(): # -1- for callee # get the "method" parameter method_ptr = int( execution_state.getRegisterService().getValue("R1")) & 0xffffffff if config.debug: print "[InvokeWithArgArray] callee = %0#10x" % method_ptr # get the pointer that refers to ArtMethod art_method_ptr = method_ptr # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[InvokeWithArgArray] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[InvokeWithArgArray] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[InvokeWithArgArray] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[InvokeWithArgArray] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[InvokeWithArgArray] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[InvokeWithArgArray] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[InvokeWithArgArray] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[InvokeWithArgArray] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[InvokeWithArgArray] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[InvokeWithArgArray] parameters = %s" % parameters_content callee_method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[InvokeWithArgArray] callee signature = %s" % callee_method_signature return_address = int( execution_state.getRegisterService().getValue("LR")) & 0xffffffff config.log_print("[InvokeWithArgArray] callee signature = %s, LR = %#x" % (callee_method_signature, return_address)) if "getSystemService" in callee_method_signature: cleanup() return if "getSubscriberId" in callee_method_signature: cleanup() return if "getNetworkOperatorName" in callee_method_signature: cleanup() return # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def ClassModification(): # at the very beginning, we remove the DexFile breakpoint rm_brks = [] for breakpoint_index in range( 0, execution_state.getBreakpointService().getBreakpointCount()): breakpoint_object = execution_state.getBreakpointService( ).getBreakpoint(breakpoint_index) if (int(breakpoint_object.getAddresses()[0]) & 0xffffffff) == config.brk_DexFile: rm_brks.append(breakpoint_object) for brk_obj in rm_brks: brk_obj.remove() # -1- DoCall # get the "shadow_frame" parameter shadow_frame_ptr = int(execution_state.getRegisterService().getValue("R2")) if config.debug: print "[ClassModification] shadow_frame = %0#10x" % shadow_frame_ptr # retrieve the "method_" field of ShadowFrame structure shadow_frame_method_ptr = memory.readMemory32( shadow_frame_ptr + config.offset_ShadowFrame_method_) # get the pointer that refers to ArtMethod art_method_ptr = shadow_frame_method_ptr if config.debug: print "[ClassModification] caller = %0#10x" % art_method_ptr # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val caller_class_ptr = class_ptr # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[ClassModification] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[ClassModification] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[ClassModification] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # we only focus on the Java invocation appeared in the target package if not config.package_filter(dex_file_location_string_val): # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[ClassModification] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[ClassModification] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[ClassModification] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[ClassModification] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[ClassModification] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[ClassModification] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[ClassModification] parameters = %s" % parameters_content caller_method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[ClassModification] caller signature = %s" % caller_method_signature # -2- for callee # get the "called_method" parameter callee_ptr = int(execution_state.getRegisterService().getValue("R0")) # get the pointer that refers to ArtMethod art_method_ptr = callee_ptr if config.debug: print "[ClassModification] callee = %0#10x" % art_method_ptr # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val callee_class_ptr = class_ptr # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[ClassModification] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[ClassModification] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[ClassModification] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # we only focus on the Java invocation appeared in the target package if not config.package_filter(dex_file_location_string_val): # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[ClassModification] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # we only focus on the Java -> native invocation if not (art_method_access_flags_value & config.ACC_NATIVE == config.ACC_NATIVE): # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[ClassModification] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[ClassModification] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[ClassModification] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[ClassModification] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[ClassModification] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[ClassModification] parameters = %s" % parameters_content callee_method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[ClassModification] callee signature = %s" % callee_method_signature config.log_print("[ClassModification] caller signature = %s" % caller_method_signature) config.log_print("[ClassModification] previous callee signature = %s" % callee_method_signature) # resolve the mirror::Class structure origin_method_list = resolve_mirror_Class(caller_class_ptr) suspicious_method_list = None # we will fill this list afterwards # -2- GenericJniMethodEnd # disable the DoCall breakpoint to avoid noisy for breakpoint_index in range( 0, execution_state.getBreakpointService().getBreakpointCount()): breakpoint_object = execution_state.getBreakpointService( ).getBreakpoint(breakpoint_index) if (int(breakpoint_object.getAddresses()[0]) & 0xffffffff) == config.brk_DoCall: breakpoint_object.disable() # resume to the start address of the GenericJniMethodEnd method previous_callee_method_signature = callee_method_signature brk_GenericJniMethodEnd = config.libart_base + config.GenericJniMethodEnd_start - config.libart_file_offset + config.libart_memory_offset while True: execution_state.getExecutionService().resumeTo(brk_GenericJniMethodEnd) try: execution_state.getExecutionService().waitForStop( 60000) # wait for 60s except DebugException: raise RuntimeError("wtf !!!") # get the pointer that refers to ArtMethod* art_method_ptr_ptr = int( execution_state.getRegisterService().getValue("SP")) + 0x8 # get the pointer that refers to ArtMethod art_method_ptr = memory.readMemory32(art_method_ptr_ptr) # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "reference_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[ClassModification] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val callee_method_signature = "unknown" if dex_file_begin_val == 0x0: pass else: # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[ClassModification] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value( dex_file_location_ptr) if config.debug: print "[ClassModification] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # we focus on the JNI method defined in the target packages if not config.package_filter(dex_file_location_string_val): # continue the while-loop continue # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[ClassModification] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[ClassModification] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[ClassModification] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx( dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[ClassModification] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx( dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[ClassModification] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx( dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[ClassModification] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[ClassModification] parameters = %s" % parameters_content callee_method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags( art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[ClassModification] method signature = %s" % callee_method_signature config.log_print("[ClassModification] current callee signature = %s" % callee_method_signature) if callee_method_signature == previous_callee_method_signature: # resolve the mirror::Class structure suspicious_method_list = resolve_mirror_Class(caller_class_ptr) break # jump out of the while-loop # -3- # make a comparison between the origin_method_list and the suspicous_method_list assert suspicious_method_list is not None for idx in range(len(origin_method_list)): origin_method = origin_method_list[idx] suspicious_method = suspicious_method_list[idx] if origin_method != suspicious_method: assert origin_method[0] == suspicious_method[0] assert origin_method[3] == suspicious_method[3] # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = origin_method[0] # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32( dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) art_method_dex_method_index_val = origin_method[3] # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx( dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) name_idx = method_id_item.get_name_idx( dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) proto_idx = method_id_item.get_proto_idx( dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags( art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) config.log_print( "[ClassModification] mirror::Class has been modified !!!") config.log_print( "[ClassModification][origin] signature = %s, access_flags_ = %#x, dex_code_item_offset_ = %0#10x, entry_point_from_quick_compiled_code = %0#10x" % (method_signature, origin_method[1], origin_method[2], origin_method[8])) config.log_print( "[ClassModification][suspicious] signature = %s, access_flags_ = %#x, dex_code_item_offset_ = %0#10x, entry_point_from_quick_compiled_code = %0#10x" % (method_signature, suspicious_method[1], suspicious_method[2], suspicious_method[8])) # enable the DoCall breakpoint for breakpoint_index in range( 0, execution_state.getBreakpointService().getBreakpointCount()): breakpoint_object = execution_state.getBreakpointService( ).getBreakpoint(breakpoint_index) if (int(breakpoint_object.getAddresses()[0]) & 0xffffffff) == config.brk_DoCall: breakpoint_object.enable() # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def parse_class_def_item(dex_file_off, class_defs_off, class_def_id): class_def_item_ptr = dex_file_off + class_defs_off + class_def_id * 0x20 class_idx = memory.readMemory32(class_def_item_ptr + offset_class_idx)
def get_string_ids_off(header_item_ptr): return memory.readMemory32(header_item_ptr + offset_string_ids_off)
def LoadClassMembers(): # at the very beginning, we are required to ensure that the LoadMethod breakpoint is enabled for idx in range( 0, execution_state.getBreakpointService().getBreakpointCount()): brk_object = execution_state.getBreakpointService().getBreakpoint(idx) if (int(brk_object.getAddresses()[0]) & 0xffffffff) == config.brk_LoadMethod: brk_object.enable() # get the "dex_file" parameter dex_file_param = int( execution_state.getRegisterService().getValue("R2")) & 0xffffffff dex_file_ptr = dex_file_param # read the "location_" field dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of the std::string structure dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[LoadClassMembers] location_ = %s" % dex_file_location_string_val # we only focus on the DexFile whose location is suspicious if not config.package_filter(dex_file_location_string_val): # disable the LoadMethod breakpoint here for idx in range( 0, execution_state.getBreakpointService().getBreakpointCount()): brk_object = execution_state.getBreakpointService().getBreakpoint( idx) if (int(brk_object.getAddresses()[0]) & 0xffffffff) == config.brk_LoadMethod: brk_object.disable() # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return # read the "begin_" field dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[LoadClassMembers] begin_ = %0#10x" % dex_file_begin_val # read the "size_" field dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[LoadClassMembers] size_ = %#x" % dex_file_size_val # parse the header_item of the dex file header_item.parse_header_item(dex_file_begin_val) # # calculate the "size_" value from the "map_off" field of the header_item # dex_file_size_val_calc = 0x0 # if config.package_filter(dex_file_location_string_val): # map_off = header_item.get_map_off(dex_file_begin_val) # map_list_ptr = dex_file_begin_val + map_off # map_list_size_val = memory.readMemory32(map_list_ptr + 0x0) # dex_file_size_val_calc = map_off + (0x4) + map_list_size_val * (0x2 + 0x2 + 0x4 + 0x4) # config.log_print("[LoadClassMembers] begin_ = %0#10x, size_ = %#x (inferring size = %#x), location_ = %s" % (dex_file_begin_val, dex_file_size_val, dex_file_size_val_calc, dex_file_location_string_val)) config.log_print( "[LoadClassMembers] begin_ = %0#10x, size_ = %#x, location_ = %s" % (dex_file_begin_val, dex_file_size_val, dex_file_location_string_val)) # get the "class_data" parameter class_data_param = int( execution_state.getRegisterService().getValue("R3")) & 0xffffffff class_data_off = class_data_param - dex_file_begin_val # parse class_data_item static_fields_size_off = 0x0 static_fields_size, length_static_fields_size = class_data_item.get_static_fields_size( dex_file_begin_val, class_data_off, static_fields_size_off) config.log_print( "[LoadClassMembers] [class_data_item] static_fields_size = %#x" % static_fields_size) instance_fields_size_off = static_fields_size_off + length_static_fields_size instance_fields_size, length_instance_fields_size = class_data_item.get_instance_fields_size( dex_file_begin_val, class_data_off, instance_fields_size_off) config.log_print( "[LoadClassMembers] [class_data_item] instance_fields_size = %#x" % instance_fields_size) direct_methods_size_off = instance_fields_size_off + length_instance_fields_size direct_methods_size, length_direct_methods_size = class_data_item.get_direct_methods_size( dex_file_begin_val, class_data_off, direct_methods_size_off) config.log_print( "[LoadClassMembers] [class_data_item] direct_methods_size = %#x" % direct_methods_size) virtual_methods_size_off = direct_methods_size_off + length_direct_methods_size virtual_methods_size, length_virtual_methods_size = class_data_item.get_virtual_methods_size( dex_file_begin_val, class_data_off, virtual_methods_size_off) config.log_print( "[LoadClassMembers] [class_data_item] virtual_methods_size = %#x" % virtual_methods_size) static_fields_off = virtual_methods_size_off + length_virtual_methods_size static_fields, length_static_fields = class_data_item.get_static_fields( dex_file_begin_val, class_data_off, static_fields_off, static_fields_size) for idx in range(static_fields_size): config.log_print( "[LoadClassMembers] [class_data_item] static_fields[%d].field_idx_diff = %#x" % (idx, static_fields[idx][0])) config.log_print( "[LoadClassMembers] [class_data_item] static_fields[%d].access_flags = %0#10x" % (idx, static_fields[idx][1])) instance_fields_off = static_fields_off + length_static_fields instance_fields, length_instance_fields = class_data_item.get_instance_fields( dex_file_begin_val, class_data_off, instance_fields_off, instance_fields_size) for idx in range(instance_fields_size): config.log_print( "[LoadClassMembers] [class_data_item] instance_fields[%d].field_idx_diff = %#x" % (idx, instance_fields[idx][0])) config.log_print( "[LoadClassMembers] [class_data_item] instance_fields[%d].access_flags = %0#10x" % (idx, instance_fields[idx][1])) direct_methods_off = instance_fields_off + length_instance_fields direct_methods, length_direct_methods = class_data_item.get_direct_methods( dex_file_begin_val, class_data_off, direct_methods_off, direct_methods_size) for idx in range(direct_methods_size): config.log_print( "[LoadClassMembers] [class_data_item] direct_methods[%d].method_idx_diff = %#x" % (idx, direct_methods[idx][0])) config.log_print( "[LoadClassMembers] [class_data_item] direct_methods[%d].access_flags = %0#10x" % (idx, direct_methods[idx][1])) config.log_print( "[LoadClassMembers] [class_data_item] direct_methods[%d].code_off = %0#10x" % (idx, direct_methods[idx][2])) virtual_methods_off = direct_methods_off + length_direct_methods virtual_methods, length_virtual_methods = class_data_item.get_virtual_methods( dex_file_begin_val, class_data_off, virtual_methods_off, virtual_methods_size) for idx in range(virtual_methods_size): config.log_print( "[LoadClassMembers] [class_data_item] virtual_methods[%d].method_idx_diff = %#x" % (idx, virtual_methods[idx][0])) config.log_print( "[LoadClassMembers] [class_data_item] virtual_methods[%d].access_flags = %0#10x" % (idx, virtual_methods[idx][1])) config.log_print( "[LoadClassMembers] [class_data_item] virtual_methods[%d].code_off = %0#10x" % (idx, virtual_methods[idx][2])) class_data_size = virtual_methods_off + length_virtual_methods if class_data_off < 0: config.log_print( "[LoadClassMembers] class_data = %0#10x (offset = %#x, size = %#x)" % (class_data_param, 0xffffffff + class_data_off, class_data_size)) else: config.log_print( "[LoadClassMembers] class_data = %0#10x (offset = %#x, size = %#x)" % (class_data_param, class_data_off, class_data_size)) # dump the class_data_item if (class_data_off < 0) or (class_data_off > dex_file_size_val): file_path = os.path.join( config.workspace, config.dex_directory, "class_data_item_%0#10x.bin" % (class_data_off if class_data_off > 0 else (0xffffffff + class_data_off))) file_format = "binary" file_vtl_start_address = class_data_param file_vtl_end_address = class_data_param + class_data_size - 0x1 memory.dump(file_path, file_format, file_vtl_start_address, file_vtl_end_address) # dump the in-memory DexFile file_path = os.path.join(config.workspace, config.dex_directory, dex_file_location_string_val.split("/")[-1]) if os.path.exists(file_path): os.remove(file_path) file_format = "binary" file_vtl_start_address = dex_file_begin_val file_vtl_end_address = dex_file_begin_val + dex_file_size_val - 0x1 file_path = memory.dump(file_path, file_format, file_vtl_start_address, file_vtl_end_address) # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def gettimeofday(): # -- HEAD -- # start_prolog() # -- BODY -- # pid = int(execution_state.getVariableService().readValue( "$AARCH64::$System::$Memory::$CONTEXTIDR_EL1.PROCID")) & 0xffffffff # only focus on the invocation from app -> gettimeofday lr = int(execution_state.getRegisterService().getValue("LR")) & 0xffffffff if not config.in_app_range(lr): # -- TAIL -- # end_prolog() # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return # get timeval pointer timeval_ptr = int( execution_state.getRegisterService().getValue("R0")) & 0xffffffff if config.debug: print "[gettimeofday] pid = %#x, lr = %0#10x, timeval_ptr = %0#10x" % ( pid, lr, timeval_ptr) config.log_print( "[gettimeofday] pid = %#x, lr = %0#10x, timeval_ptr = %0#10x" % (pid, lr, timeval_ptr)) brk_gettimeofday = config.libc_base + config.gettimeofday_end - config.libc_file_offset + config.libc_memory_offset execution_state.getExecutionService().resumeTo(brk_gettimeofday) try: execution_state.getExecutionService().waitForStop( 60000) # wait for 60s except DebugException: raise RuntimeError("wtf !!!") # obtain tv_sec value tv_sec_ptr = timeval_ptr + 0x0 tv_sec = memory.readMemory32(tv_sec_ptr) # obtain tv_usec_value tv_usec_ptr = timeval_ptr + 0x4 tv_usec = memory.readMemory32(tv_usec_ptr) if config.debug: print "[gettimeofday] (origin) pid = %#x, tv_sec = %0#10x, tv_usec = %0#10x" % ( pid, tv_sec, tv_usec) # config.log_print("[gettimeofday] (origin) pid = %#x, tv_sec = %0#10x, tv_usec = %0#10x" % (pid, tv_sec, tv_usec)) # anti time checking tv_sec_old, tv_usec_old = config.load_time_info() if tv_sec <= tv_sec_old: tv_sec = tv_sec_old + 0x1 if tv_sec < tv_sec_old: # TODO: should raise an exception, but we just ignore it at this time assert False else: if tv_sec_old != 0 and tv_usec_old != 0: time_interval = (tv_sec * 1000000L + tv_usec) - (tv_sec_old * 1000000L + tv_usec_old) if time_interval > TIME_INTERVAL: tv_sec_new = int( ((tv_sec_old * 1000000L + tv_usec_old) + TIME_INTERVAL) / 1000000L) tv_usec_new = int(( (tv_sec_old * 1000000L + tv_usec_old) + TIME_INTERVAL) - (tv_sec_new * 1000000L)) # verification time_old = tv_sec_old * 1000000L + tv_usec_old time_new = tv_sec_new * 1000000L + tv_usec_new assert time_new == (time_old + TIME_INTERVAL) time_memory_old = tv_sec_old * (2**32) * 0x1L + tv_usec_old print "[old] sec = %#x, usec = %#x, in-memory = %#x" % ( tv_sec_old, tv_usec_old, time_memory_old) time_memory_new = tv_sec_new * (2**32) * 0x1L + tv_usec_new print "[new] sec = %#x, usec = %#x, in-memory = %#x" % ( tv_sec_new, tv_usec_new, time_memory_new) config.save_time_info(tv_sec_new, tv_usec_new) memory_set_cmd = "memory set %0#10x 0 %#x" % (timeval_ptr + 0x0, tv_sec_new) execution_state.executeDSCommand(memory_set_cmd) memory_set_cmd = "memory set %0#10x 0 %#x" % (timeval_ptr + 0x4, tv_usec_new) execution_state.executeDSCommand(memory_set_cmd) # obtain tv_sec value tv_sec_ptr = timeval_ptr + 0x0 tv_sec = memory.readMemory32(tv_sec_ptr) # obtain tv_usec_value tv_usec_ptr = timeval_ptr + 0x4 tv_usec = memory.readMemory32(tv_usec_ptr) if config.debug: print "[gettimeofday] (adjust) pid = %#x, tv_sec = %0#10x, tv_usec = %0#10x" % ( pid, tv_sec, tv_usec) # config.log_print("[gettimeofday] (adjust) pid = %#x, tv_sec = %0#10x, tv_usec = %0#10x" % (pid, tv_sec, tv_usec)) else: config.save_time_info(tv_sec, tv_usec) elif tv_sec_old == 0 and tv_usec_old == 0: config.save_time_info(tv_sec, tv_usec) else: raise RuntimeError("invalid timeval valus !!!") # -- TAIL -- # end_prolog() # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def ArtQuickToInterpreterBridge(): # # at the very beginning, we are required to ensure that the DoCall breakpoint has been enabled # for idx in range(0, execution_state.getBreakpointService().getBreakpointCount()): # brk_object = execution_state.getBreakpointService().getBreakpoint(idx) # enable the DoCall breakpoint # if (int(brk_object.getAddresses()[0]) & 0xffffffff) == config.brk_DoCall: # brk_object.enable() # -1- for caller # get the "sp" parameter sp_ptr = int(execution_state.getRegisterService().getValue("R2")) if config.debug: print "[ArtQuickToInterpreterBridge] sp = %0#10x" % sp_ptr # get the pointer that refers to ArtMethod art_method_ptr = memory.readMemory32(sp_ptr) # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "reference_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32(art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val caller_method_signature = "unknown" if class_ptr == 0x0: pass else: # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32(class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # # we only focus on the Compiled Code -> Java invocation appeared in the target package # if not config.package_filter(dex_file_location_string_val): # # continue the execution of the target application # execution_state.getExecutionService().resume() # cleanup() # return # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32(art_method_access_flags_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::access_flags_ = %#x (%s)" % (art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32(art_method_dex_code_item_offset_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32(art_method_dex_method_index_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx(dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[ArtQuickToInterpreterBridge] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[ArtQuickToInterpreterBridge] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx(dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx(dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[ArtQuickToInterpreterBridge] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list(dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx(dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[ArtQuickToInterpreterBridge] parameters = %s" % parameters_content caller_method_signature = "%s %s->%s %s%s" % (config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[ArtQuickToInterpreterBridge] caller signature = %s" % caller_method_signature # -2- for callee # get the "method" parameter method_ptr = int(execution_state.getRegisterService().getValue("R0")) if config.debug: print "[ArtQuickToInterpreterBridge] method = %0#10x" % method_ptr # get the pointer that refers to ArtMethod art_method_ptr = method_ptr # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "reference_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32(art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32(class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # we only focus on the Compiled Code -> Java invocation appeared in the target package if not config.package_filter(dex_file_location_string_val): # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32(art_method_access_flags_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::access_flags_ = %#x (%s)" % (art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32(art_method_dex_code_item_offset_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32(art_method_dex_method_index_ptr) if config.debug: print "[ArtQuickToInterpreterBridge] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx(dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[ArtQuickToInterpreterBridge] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[ArtQuickToInterpreterBridge] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx(dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx(dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[ArtQuickToInterpreterBridge] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list(dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx(dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data(dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[ArtQuickToInterpreterBridge] parameters = %s" % parameters_content callee_method_signature = "%s %s->%s %s%s" % (config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[ArtQuickToInterpreterBridge] callee signature = %s" % callee_method_signature config.log_print("[ArtQuickToInterpreterBridge] caller signature = %s" % caller_method_signature) config.log_print("[ArtQuickToInterpreterBridge] callee signature = %s" % callee_method_signature) # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def get_class_defs_size(header_item_ptr): return memory.readMemory32(header_item_ptr + offset_class_defs_size)
def DoCall(): # -1- for caller # get the "shadow_frame" parameter shadow_frame_ptr = int(execution_state.getRegisterService().getValue("R2")) if config.debug: print "[DoCall] shadow_frame = %0#10x" % shadow_frame_ptr # retrieve the "method_" field of ShadowFrame structure shadow_frame_method_ptr = memory.readMemory32( shadow_frame_ptr + config.offset_ShadowFrame_method_) # get the pointer that refers to ArtMethod art_method_ptr = shadow_frame_method_ptr # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[DoCall] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[DoCall] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[DoCall] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # # we only focus on the Java invocation appeared in the target package # if not config.package_filter(dex_file_location_string_val): # # continue the execution of the target application # execution_state.getExecutionService().resume() # cleanup() # return # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[DoCall] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[DoCall] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[DoCall] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[DoCall] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[DoCall] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[DoCall] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[DoCall] parameters = %s" % parameters_content caller_method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[DoCall] caller signature = %s" % caller_method_signature # -2- for callee # get the "called_method" parameter callee_ptr = int(execution_state.getRegisterService().getValue("R0")) if config.debug: print "[DoCall] callee = %0#10x" % callee_ptr # get the pointer that refers to ArtMethod art_method_ptr = callee_ptr # read the "declaring_class_" field of ArtMethod art_method_declaring_class_ptr = art_method_ptr + config.offset_ArtMethod_declaring_class_ # read the "root_" field of GcRoot art_method_declaring_class_root_ptr = art_method_declaring_class_ptr + config.offset_GcRoot_root_ # read the "refeence_" field of CompressesReference art_method_declaring_class_root_reference_ptr = art_method_declaring_class_root_ptr + config.offset_CompressesReference_reference_ art_method_declaring_class_root_reference_val = memory.readMemory32( art_method_declaring_class_root_reference_ptr) class_ptr = art_method_declaring_class_root_reference_val # read the "dex_cache_" field of Class class_dex_cache_ptr = class_ptr + config.offset_Class_dex_cache_ # read the "reference_" field of HeapReference class_dex_cache_reference_ptr = class_dex_cache_ptr + config.offset_HeapReference_reference_ class_dex_cache_reference_val = memory.readMemory32( class_dex_cache_reference_ptr) dex_cache_ptr = class_dex_cache_reference_val # read the "dex_file_" field of DexCache dex_cache_dex_file_ptr = dex_cache_ptr + config.offset_DexCache_dex_file_ dex_cache_dex_file_val = memory.readMemory32(dex_cache_dex_file_ptr) dex_file_ptr = dex_cache_dex_file_val # read the "begin_" field of DexFile dex_file_begin_ptr = dex_file_ptr + config.offset_DexFile_begin_ dex_file_begin_val = memory.readMemory32(dex_file_begin_ptr) if config.debug: print "[DoCall] ArtMethod::declaring_class_::dex_cache_::dex_file_::begin_ = %0#10x" % dex_file_begin_val # read the "size_" field of DexFile dex_file_size_ptr = dex_file_ptr + config.offset_DexFile_size_ dex_file_size_val = memory.readMemory32(dex_file_size_ptr) if config.debug: print "[DoCall] ArtMethod::declaring_class_::dex_cache_::dex_file_::size_ = %#x" % dex_file_size_val # read the "location_" field of DexFile dex_file_location_ptr = dex_file_ptr + config.offset_DexFile_location_ # retrieve the value of std::string dex_file_location_string_val = retrieve_string_value(dex_file_location_ptr) if config.debug: print "[DoCall] ArtMethod::declaring_class_::dex_cache_::dex_file_::location_ = %s" % dex_file_location_string_val # read the "access_flags_" field of ArtMethod art_method_access_flags_ptr = art_method_ptr + config.offset_ArtMethod_access_flags_ art_method_access_flags_value = memory.readMemory32( art_method_access_flags_ptr) if config.debug: print "[DoCall] ArtMethod::access_flags_ = %#x (%s)" % ( art_method_access_flags_value, config.resolve_access_flags(art_method_access_flags_value)) # read the "dex_code_item_offset_" field of ArtMethod art_method_dex_code_item_offset_ptr = art_method_ptr + config.offset_ArtMethod_dex_code_item_offset_ art_method_dex_code_item_offset_value = memory.readMemory32( art_method_dex_code_item_offset_ptr) if config.debug: print "[DoCall] ArtMethod::dex_code_item_offset_ = %#x" % art_method_dex_code_item_offset_value # read the "dex_method_index_" field of ArtMethod art_method_dex_method_index_ptr = art_method_ptr + config.offset_ArtMethod_dex_method_index_ art_method_dex_method_index_val = memory.readMemory32( art_method_dex_method_index_ptr) if config.debug: print "[DoCall] ArtMethod::dex_method_index_ = %#x" % art_method_dex_method_index_val # resolve string_ids_off = header_item.get_string_ids_off(dex_file_begin_val) type_ids_off = header_item.get_type_ids_off(dex_file_begin_val) proto_ids_off = header_item.get_proto_ids_off(dex_file_begin_val) method_ids_off = header_item.get_method_ids_off(dex_file_begin_val) class_idx = method_id_item.get_class_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) class_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, class_idx) class_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, class_descriptor_idx) # if config.debug: # print "[DoCall] class name = %s" % class_descriptor_content name_idx = method_id_item.get_name_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) name_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, name_idx) # if config.debug: # print "[DoCall] method name = %s" % name_content proto_idx = method_id_item.get_proto_idx(dex_file_begin_val, method_ids_off, art_method_dex_method_index_val) proto_return_type_idx = proto_id_item.get_return_type_idx( dex_file_begin_val, proto_ids_off, proto_idx) proto_return_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, proto_return_type_idx) proto_return_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, proto_return_type_descriptor_idx) # if config.debug: # print "[DoCall] return type = %s" % proto_return_type_descriptor_content parameters_content = "" proto_parameters_list = proto_id_item.get_parameters_list( dex_file_begin_val, proto_ids_off, proto_idx) if len(proto_parameters_list) == 0: parameters_content = "()" else: for parameter_idx in range(len(proto_parameters_list)): parameter_type_idx = proto_parameters_list[parameter_idx] parameter_type_descriptor_idx = type_id_item.get_descriptor_idx( dex_file_begin_val, type_ids_off, parameter_type_idx) parameter_type_descriptor_content = string_id_item.get_string_id_item_data( dex_file_begin_val, string_ids_off, parameter_type_descriptor_idx) if len(proto_parameters_list) == 1: parameters_content = parameters_content + "(" + parameter_type_descriptor_content + ")" else: if parameter_idx == 0: parameters_content = parameters_content + "(" + parameter_type_descriptor_content elif parameter_idx == (len(proto_parameters_list) - 1): parameters_content = parameters_content + "," + parameter_type_descriptor_content + ")" else: parameters_content = parameters_content + "," + parameter_type_descriptor_content # if config.debug: # print "[DoCall] parameters = %s" % parameters_content callee_method_signature = "%s %s->%s %s%s" % ( config.resolve_method_access_flags(art_method_access_flags_value), class_descriptor_content, proto_return_type_descriptor_content, name_content, parameters_content) if config.debug: print "[DoCall] callee signature = %s" % callee_method_signature config.log_print("[DoCall] caller signature = %s" % caller_method_signature) config.log_print("[DoCall] callee signature = %s" % callee_method_signature) # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return
def InitClass(): # load class info thread_ptr, mirror_class_names, mirror_class_ptrs = config.load_class_info() thread_ptr_cur = int(execution_state.getRegisterService().getValue("R1")) & 0xffffffff if thread_ptr_cur != thread_ptr: # -- TAIL -- # end_prolog() # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return origin_reference_ptr = int(execution_state.getRegisterService().getValue("R2")) & 0xffffffff origin_class_ptr = memory.readMemory32(origin_reference_ptr) if not (origin_class_ptr in mirror_class_ptrs): # -- TAIL -- # end_prolog() # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return origin_ret_address = int(execution_state.getRegisterService().getValue("LR")) & 0xffffffff for idx in range(len(mirror_class_ptrs)): class_ptr = mirror_class_ptrs[idx] if origin_class_ptr == class_ptr: class_name = mirror_class_names[idx] print "[InitClass] init class name = %s, ret = %0#10x" % (class_name, origin_ret_address) config.log_print("[InitClass] init class -> %s, ret -> %0#10x" % (class_name, origin_ret_address)) # -- HEAD -- # start_prolog() # -- BODY -- # origin_method_lists = [] for idx in range(len(mirror_class_ptrs)): class_ptr = mirror_class_ptrs[idx] origin_method_list = resolve_mirror_Class(class_ptr) origin_method_lists.append(origin_method_list) force_initializing(origin_class_ptr, mirror_class_ptrs, mirror_class_names) suspicious_method_lists = [] for idx in range(len(mirror_class_ptrs)): class_ptr = mirror_class_ptrs[idx] suspicious_method_list = resolve_mirror_Class(class_ptr) suspicious_method_lists.append(suspicious_method_list) for idx in range(len(mirror_class_ptrs)): origin_method_list = origin_method_lists[idx] suspicious_method_list = suspicious_method_lists[idx] dump_modified_method(origin_method_list, suspicious_method_list) # -- TAIL -- # end_prolog_done() # continue the execution of the target application execution_state.getExecutionService().resume() cleanup() return