def repack_apk(apk_path_or_list, provider_name, merge_dex_path, activity_list=None, res_file_list=None, debuggable=None, vm_safe_mode=None, max_heap_size=0, force_append=False): ''' ''' if not isinstance(apk_path_or_list, list): apk_path_or_list = [apk_path_or_list] elif len(apk_path_or_list) == 0: raise ValueError('apk path not specified') apk_file_list = [] signature_dict = {} for it in apk_path_or_list: apk_file = APKFile(it) apk_file_list.append(apk_file) manifest = AndroidManifest(apk_file) if debuggable != None: manifest.debuggable = debuggable # 修改debuggable属性 if vm_safe_mode != None: manifest.vm_safe_mode = vm_safe_mode # 修改安全模式 process_list = manifest.get_process_list() authorities = manifest.package_name + '.authorities' print('Add provider %s' % provider_name) manifest.add_provider(provider_name, authorities) # 主进程 for i, process in enumerate(process_list): sub_provider_name = provider_name + '$InnerClass' + str(i + 1) print('Add provider %s in process %s' % (sub_provider_name, process)) manifest.add_provider(sub_provider_name, authorities + str(i), process) if activity_list: for activity in activity_list: print('Add activity %s' % activity['name']) manifest.add_activity(activity['name'], activity['exported'], activity['process']) # 合并dex文件 print('Merge dex %s' % merge_dex_path) classes_dex_path = tempfile.mktemp('.dex') dex_index = 1 low_memory = False while True: dex_file = 'classes%s.dex' % (dex_index if dex_index > 1 else '') if not apk_file.get_file(dex_file): # 作为最后一个classes.dex with open(merge_dex_path, 'rb') as f: apk_file.add_file(dex_file, f.read()) print('Save dex %s to %s' % (merge_dex_path, dex_file)) break if force_append or low_memory: # 低内存下直接跳过已有dex,进行加速 dex_index += 1 continue if os.path.exists(classes_dex_path): os.remove(classes_dex_path) apk_file.extract_file(dex_file, classes_dex_path) try: merge_dex(classes_dex_path, [classes_dex_path, merge_dex_path], max_heap_size) except TooManyMethodsError: print('Merge dex into %s failed due to methods number' % dex_file) dex_index += 1 except OutOfMemoryError: print('Merge dex into %s failed due to out of memory error' % dex_file) low_memory = True dex_index += 1 else: print('Merge dex into %s success' % dex_file) with open(classes_dex_path, 'rb') as f: apk_file.add_file(dex_file, f.read()) break if dex_index > 1: # 合并进非主dex只支持5.0以上系统 print('WARNING: APK can only be installed in android above 5.0') manifest.min_sdk_version = 21 manifest.save() if res_file_list: for src_path, dst_path in res_file_list: with open(src_path, 'rb') as f: print('Copy file %s => %s' % (src_path, dst_path)) data = f.read() apk_file.add_file(dst_path, data) for it in apk_file.list_dir('META-INF'): if it.lower().endswith('.rsa'): print('Signature file is %s' % it) tmp_rsa_path = tempfile.mktemp('.rsa') apk_file.extract_file('META-INF/%s' % it, tmp_rsa_path) orig_signature = get_apk_signature(tmp_rsa_path).strip() os.remove(tmp_rsa_path) logging.info('%s signature is %s' % (manifest.package_name, orig_signature)) signature_dict[manifest.package_name] = orig_signature break else: raise RuntimeError('Can not find .sf file in META-INF dir') for it in apk_file.list_dir('META-INF'): apk_file.delete_file('META-INF/%s' % it) out_apk_list = [] # 写入原始签名信息 print('Write original signatures: %s' % json.dumps(signature_dict)) temp_dir = tempfile.mkdtemp('-repack') for i, apk_file in enumerate(apk_file_list): apk_file.add_file('assets/qt4a_package_signatures.txt', json.dumps(signature_dict)) file_name = os.path.split(apk_path_or_list[i])[-1][:-4] + '-repack.apk' tmp_apk_path = os.path.join(temp_dir, file_name) apk_file.save(tmp_apk_path) new_path = resign_apk(tmp_apk_path) os.remove(tmp_apk_path) out_apk_list.append(new_path) if len(out_apk_list) == 1: return out_apk_list[0] else: return out_apk_list
def repack_apk(apk_path_or_list, debuggable=True): '''重打包apk :param apk_path_or_list: apk路径或apk路径列表 :type apk_path_or_list: string/list :param debuggable: 重打包后的apk是否是调试版本: True - 是 False - 否 None - 与原apk保持一致 :type debuggable: bool/None ''' cur_path = os.path.dirname(os.path.abspath(__file__)) if not isinstance(apk_path_or_list, list): apk_path_or_list = [apk_path_or_list] elif len(apk_path_or_list) == 0: raise ValueError('apk path not specified') apk_file_list = [] signature_dict = {} for it in apk_path_or_list: apk_file = APKFile(it) apk_file_list.append(apk_file) manifest = AndroidManifest(apk_file) if debuggable != None: manifest.debuggable = debuggable # 修改debuggable属性 process_list = manifest.get_process_list() provider_name = 'com.test.androidspy.inject.DexLoaderContentProvider' authorities = manifest.package_name + '.authorities' manifest.add_provider(provider_name, authorities) # 主进程 manifest.add_activity('com.test.androidspy.inject.CmdExecuteActivity', "true", ':qt4a_cmd') for i, process in enumerate(process_list): manifest.add_provider(provider_name + '$InnerClass' + str(i + 1), authorities + str(i), process) manifest.save() # 合并dex文件 dexloader_path = os.path.join(cur_path, 'tools', 'dexloader.dex') classes_dex_path = tempfile.mktemp('.dex') apk_file.extract_file('classes.dex', classes_dex_path) merge_dex(classes_dex_path, [classes_dex_path, dexloader_path]) with open(classes_dex_path, 'rb') as f: apk_file.add_file('classes.dex', f.read()) # 添加QT4A测试桩文件 file_list = [ 'AndroidSpy.jar', 'arm64-v8a/libdexloader.so', 'arm64-v8a/libdexloader64.so', 'arm64-v8a/libandroidhook.so', 'armeabi/libdexloader.so', 'armeabi/libandroidhook.so', 'armeabi-v7a/libdexloader.so', 'armeabi-v7a/libandroidhook.so', 'x86/libdexloader.so', 'x86/libandroidhook.so' ] tools_path = os.path.join(os.path.dirname(cur_path), 'androiddriver', 'tools') for it in file_list: file_path = os.path.join(tools_path, it) with open(file_path, 'rb') as f: data = f.read() apk_file.add_file('assets/qt4a/%s' % it, data) for it in apk_file.list_dir('META-INF'): if it.lower().endswith('.rsa'): print('Signature file is %s' % it) tmp_rsa_path = tempfile.mktemp('.rsa') apk_file.extract_file('META-INF/%s' % it, tmp_rsa_path) orig_signature = get_apk_signature(tmp_rsa_path).strip() os.remove(tmp_rsa_path) logging.info('%s signature is %s' % (manifest.package_name, orig_signature)) signature_dict[manifest.package_name] = orig_signature break else: raise RuntimeError('Can not find .sf file in META-INF dir') for it in apk_file.list_dir('META-INF'): apk_file.delete_file('META-INF/%s' % it) out_apk_list = [] # 写入原始签名信息 temp_dir = tempfile.mkdtemp('-repack') for i, apk_file in enumerate(apk_file_list): apk_file.add_file('assets/qt4a_package_signatures.txt', json.dumps(signature_dict)) file_name = os.path.split(apk_path_or_list[i])[-1][:-4] + '-repack.apk' tmp_apk_path = os.path.join(temp_dir, file_name) apk_file.save(tmp_apk_path) new_path = resign_apk(tmp_apk_path) os.remove(tmp_apk_path) out_apk_list.append(new_path) if len(out_apk_list) == 1: return out_apk_list[0] else: return out_apk_list