# -*- coding:utf-8 -*- import os import re import shutil import subprocess import sys import time import win32api import win32con import yaml import xml.etree.ElementTree as ET channel_rose = '朱雀' channel_coolpad='FAKE' channel_xmy = '小绵羊' channel_9hgame = '九狐' channel_icefoxgame = '冰狐' # 测试组游戏地址,需要根据游戏修改 # 测试组游戏地址,需要根据游戏修改 # 测试组游戏地址,需要根据游戏修改 game_dir = r'\\10.8.230.114\public\测试组\20240523\破天一剑Y' # 其他情况使用BPM上面的任务名称 game_channel = '破天一剑Y-朱雀' def copy_mommy_for_9hgame(decompile_dir_path): htprotect_dir_path = os.path.join(decompile_dir_path, 'smali', 'com', 'ydzs', 'framework') if not os.path.exists(htprotect_dir_path): os.makedirs(htprotect_dir_path) shutil.copy(os.path.join(r'D:\special_problem\九狐', 'MommyUtils.smali'), htprotect_dir_path) if ' ' in game_channel: game_channel = game_channel.replace(' ', '-') print(sys.argv) if len(sys.argv) == 3: game_dir = sys.argv[1] game_channel = sys.argv[2] print(game_dir) print(game_channel) def fix_install_fail_bug(decompile_dir_path): namespace = '{http://schemas.android.com/apk/res/android}' ET.register_namespace('android', 'http://schemas.android.com/apk/res/android') manifest_path = os.path.join(decompile_dir_path, 'AndroidManifest.xml') xml_tree = ET.parse(manifest_path) xml_root = xml_tree.getroot() application_node = xml_root.find('./application') etract_value = application_node.get(f'{namespace}extractNativeLibs') if etract_value is not None and etract_value == 'false': # 修改extractNativeLib application_node.set(f'{namespace}extractNativeLibs', 'true') xml_tree.write(manifest_path, encoding='utf-8', xml_declaration=True) yaml_path = os.path.join(decompile_dir_path, 'apktool.yml') file = open(yaml_path, 'r', encoding='utf-8') yaml_result = yaml.load(file, Loader=yaml.BaseLoader) sdk_info = yaml_result['sdkInfo'] yaml_result['packageInfo']['renameManifestPackage'] = None print(sdk_info) if int(sdk_info['targetSdkVersion']) > 29: sdk_info['targetSdkVersion'] = '29' print(sdk_info) file.close() with open(yaml_path, 'w', encoding='utf-8') as f: yaml.dump(yaml_result, f) def rindex(lst, value): for i, v in enumerate(reversed(lst)): if v == value: return len(lst) - i - 1 # return the index in the original list` return None def move_game_apk_to_work(): cmd_move_str = f'copy {game_path} {work_path}' print(cmd_move_str) result = subprocess.getoutput(cmd_move_str) print(result) def get_decompile_dir_name(apk_path): s_index = apk_path.index('.') print('s_index', s_index) p_index = rindex(apk_path, '\\') print('p_index:', p_index) dir_name = apk_path[:rindex(apk_path, '\\') + 1] + apk_path[p_index + 1:s_index] print('dir_name:', dir_name) return dir_name def find_r_smali_and_replace(smali_file_path, regex_str): with open(smali_file_path, 'r') as f: smali_str = f.read() pattern = re.compile(regex_str) resource_arr = pattern.findall(smali_str) if len(resource_arr) > 0: print(smali_file_path) for r_str in resource_arr: virtual_name = r_str[r_str.index(' ') + 1:r_str.index(',')] print(virtual_name) resource_type = r_str[r_str.index('R$') + 2:r_str.index(';')].capitalize() print(resource_type) resource_name = r_str[r_str.index('->') + 2:r_str.index(':')] print(resource_name) new_r_str = "const-string %s, \"%s\"\n\n\tinvoke-static {%s}, Lcom/ydzs/framework/MommyUtils;->get%sId(Ljava/lang/String;)I\n\n\tmove-result %s" % ( virtual_name, resource_name, virtual_name, resource_type, virtual_name) print(new_r_str) smali_str = smali_str.replace(r_str, new_r_str) with open(smali_file_path, 'w') as f: f.write(smali_str) def replace_rose_resource(d_dir): r_regex_str = r'sget[^\n]*R\$layout[^\n]*I|sget[^\n]*R\$id[^\n]*I|sget[^\n]*R\$drawable[^\n]*I|sget[^\n]*R\$string[^\n]*I|sget[^\n]*R\$array[^\n]*I|sget[^\n]*R\$bool[^\n]*I|sget[^\n]*R\$integer[^\n]*I' for dirpath, dirnames, filenames in os.walk(d_dir): if r'com\wanwu' in dirpath or r'com\ydzs' in dirpath: for smali_file in filenames: smali_file_path = os.path.join(dirpath, smali_file) # print(smali_file_path) find_r_smali_and_replace(smali_file_path, r_regex_str) def fix_coolpad_version_3_method_name_change_bug(decompile_dir): is_version_3_sdk = False is_new_sdk_and_version_lt_version_3 = False for dirpath, dirnames, filenames in os.walk(decompile_dir): if r'com\yulong\sdk\promoter' in dirpath and 'OnGameAuthListener.smali' in filenames: auth_listener_path = os.path.join(dirpath, 'OnGameAuthListener.smali') with open(auth_listener_path, 'r', encoding='utf-8') as f: smali_str_arr = f.read() if 'onSuccess' in smali_str_arr: is_version_3_sdk = True if 'onResult' in smali_str_arr: is_new_sdk_and_version_lt_version_3 = True break for dirpath, dirnames, filenames in os.walk(decompile_dir): if r'com\yulong\sdk\promoter' in dirpath and 'PromoterGameAuthApi$1.smali' in filenames: smali_path = os.path.join(dirpath, 'PromoterGameAuthApi$1.smali') print(smali_path) with open(smali_path, 'r', encoding='utf-8') as f: smali_str_arr = f.readlines() index_str = r'onSuccess' if is_new_sdk_and_version_lt_version_3: index_str = r'onSuccess' elif is_version_3_sdk: index_str = r'onResult' for line in smali_str_arr: if index_str in line: print(line) index = smali_str_arr.index(line) if is_new_sdk_and_version_lt_version_3: smali_str_arr[index] = line.replace(index_str, 'onResult') elif is_version_3_sdk: smali_str_arr[index] = line.replace(index_str, 'onSuccess') print(smali_str_arr[index]) break with open(smali_path, 'w', encoding='utf-8') as f: f.write(''.join(smali_str_arr)) break return is_version_3_sdk def fix_coolpad_version_3_login_fail_bug(decompile_dir_path): insert_str_list = [ '\n\t.locals 0\n\n', '\treturn-void\n\n'] for dirpath, dirnames, filenames in os.walk(decompile_dir_path): if r'com\yulong\account\auth' in dirpath and 'AuthCodeApiImpl.smali' in filenames: smali_path = os.path.join(dirpath, 'AuthCodeApiImpl.smali') with open(smali_path, 'r', encoding='utf-8') as f: smali_str_arr = f.readlines() index_str = '.method private returnAuthError(Lcom/yulong/account/common/info/ErrorInfo;)V' end_method_str = '.end method' insert_str = ''.join(insert_str_list) on_create_index = 0 insert_index = 0 for line in smali_str_arr: if index_str in line: on_create_index = smali_str_arr.index(line) print('on_create_index', on_create_index, line) break for index, value in enumerate(smali_str_arr): if index > on_create_index and end_method_str in value: insert_index = index print('insert_index', index) break print(on_create_index, insert_index) del smali_str_arr[on_create_index + 1:insert_index] smali_str_arr.insert(on_create_index + 1, insert_str) with open(smali_path, 'w', encoding='utf-8') as f: f.write(''.join(smali_str_arr)) break start_time = int(time.time()) # 判断游戏是否需要修复并且是否是朱雀游戏,不需要修复就只需要拷贝arm64 script_dir_list = os.listdir(r'F:\python_learn\day_1\script') is_need_fix = False for py_name in script_dir_list: if game_channel in py_name: is_need_fix = True break print("aaaaaaaaaaaaaaa", is_need_fix) game_path = 'game_path is empty' for game_name in os.listdir(game_dir): if ((channel_rose in game_channel or '青雀' in game_channel) and channel_rose in game_name) \ or ((channel_coolpad in game_channel or 'fake' in game_channel) and channel_coolpad in game_name)\ or ((channel_icefoxgame in game_channel or '冰狐' in game_channel) and channel_icefoxgame in game_name)\ or (channel_9hgame in game_channel and channel_9hgame in game_name)\ or (channel_xmy in game_channel and channel_xmy in game_name)\ or ('遥望' in game_channel and '遥望' in game_name): game_path = os.path.join(game_dir, game_name) break print('game_path:', game_path) work_path = r"D:\work" apk_file_path = f'{work_path}' + game_path[rindex(game_path, "\\"):] apk_file_path_copy = os.path.join(work_path, 'copy_'+game_path[rindex(game_path, "\\")+1:]) print(apk_file_path_copy) if '全民泡泡' in game_channel: if channel_rose in game_channel: decompile_dir_name = os.path.join(work_path, 'qmpp_rose') elif channel_coolpad in game_channel or 'fake' in game_channel: decompile_dir_name = os.path.join(work_path, 'qmpp_coolpad') elif channel_9hgame in game_channel: decompile_dir_name = os.path.join(work_path, 'qmpp_9hgame') else: decompile_dir_name = os.path.join(work_path, 'qmpp_xmy') elif '我的安吉拉2' in game_channel: if channel_rose in game_channel: decompile_dir_name = os.path.join(work_path, 'wdajl_rose') elif channel_coolpad in game_channel or 'fake' in game_channel: decompile_dir_name = os.path.join(work_path, 'wdajl_coolpad') elif channel_9hgame in game_channel: decompile_dir_name = os.path.join(work_path, 'wdajl_9hgame') else: decompile_dir_name = os.path.join(work_path, 'wdajl_xmy') else: decompile_dir_name = get_decompile_dir_name(apk_file_path) kfzs_sign = "kfzs_sign" kfzs_sign_youliang = "kfzs_sign_youliang" ydzs_sign = "ydzs_sign" # 签名文件,需要根据游戏修改 # 签名文件,需要根据游戏修改 # 签名文件,需要根据游戏修改 current_sign = kfzs_sign if channel_rose in game_path or channel_coolpad in game_path or channel_9hgame in game_path: current_sign = ydzs_sign elif channel_xmy in game_path: current_sign = kfzs_sign # 修复脚本文件名,需要根据游戏修改 # 修复脚本文件名,需要根据游戏修改 # 修复脚本文件名,需要根据游戏修改 if is_need_fix: fix_python_path = os.path.join(r'F:\python_learn\day_1\script', f'{game_channel}.py') print('fix_python_path', fix_python_path) # # 拷贝游戏包 move_game_apk_to_work() # 复制一个原始包,只第一次复制 if apk_file_path_copy[rindex(apk_file_path, '\\')+1:] not in os.listdir(work_path): print("执行拷贝原始游戏包") copy_origin_game_apk = f'copy {apk_file_path} {apk_file_path_copy}' subprocess.getoutput(copy_origin_game_apk) else: print("不执行拷贝原始游戏包") # # 解包 cmd_decompile_str = rf'apktool d {apk_file_path} -f -o {decompile_dir_name} --only-main-classes' print(cmd_decompile_str) os.system(cmd_decompile_str) if channel_9hgame in game_path or channel_icefoxgame in game_path: copy_mommy_for_9hgame(decompile_dir_name) #朱雀包拷贝arm64 if (channel_rose in game_path or channel_coolpad in game_path or channel_9hgame in game_path or channel_icefoxgame in game_path) and 'arm64-v8a' in os.listdir(os.path.join(decompile_dir_name, 'lib')): print('朱雀拷贝arm64') arm64_path = os.path.join(decompile_dir_name, 'lib', 'arm64-v8a') cmd_copy_arm64 = rf'copy D:\special_problem\朱雀arm64\libydzs.so {arm64_path}' os.system(cmd_copy_arm64) cmd_copy_arm64 = rf'copy D:\special_problem\朱雀arm64\libwanwusdk.so {arm64_path}' os.system(cmd_copy_arm64) #朱雀包拷贝x86 if (channel_rose in game_path or channel_coolpad in game_path or channel_9hgame in game_path or channel_icefoxgame in game_path) and 'x86' in os.listdir(os.path.join(decompile_dir_name, 'lib')): print('朱雀拷贝x86') x86_path = os.path.join(decompile_dir_name, 'lib', 'x86') cmd_copy_x86 = rf'copy D:\special_problem\朱雀x86\libydzs.so {x86_path}' os.system(cmd_copy_x86) #朱雀包修改资源获取方式 if channel_rose in game_path or channel_coolpad in game_path or channel_9hgame in game_path or channel_icefoxgame in game_path: print('执行朱雀包修改资源脚本') replace_rose_resource(decompile_dir_name) for dirpath, dirnames, filenames in os.walk(decompile_dir_name): if r'com\ydzs\framework\java' in dirpath and 'YDZSSDKUser.smali' in filenames: smali_path = os.path.join(dirpath, 'YDZSSDKUser.smali') print(smali_path) with open(smali_path, 'r', encoding='utf-8') as f: smali_str_arr = f.readlines() index_str = 'invoke-static {}, Lcom/ydzs/framework/SDKNativeWrapper;->nativeGetRealnameStatus()Ljava/lang/String;' index_str2 = 'invoke-static {p1}, Lcom/ydzs/framework/SDKNativeWrapper;->nativeEnterGame(Ljava/util/HashMap;)Ljava/lang/String;' replace_str = '\tinvoke-static {}, Lcom/ydzs/framework/SDKNativeWrapper;->nativeGetRealnameStatus()V\n' replace_str2 = '\tinvoke-static {p1}, Lcom/ydzs/framework/SDKNativeWrapper;->nativeEnterGame(Ljava/util/HashMap;)V\n' for line in smali_str_arr: if index_str in line: smali_str_arr[smali_str_arr.index(line)] = replace_str if index_str2 in line: smali_str_arr[smali_str_arr.index(line)] = replace_str2 with open(smali_path, 'w', encoding='utf-8') as f: f.write(''.join(smali_str_arr)) if r'com\ydzs\framework' in dirpath and 'SDKNativeWrapper.smali' in filenames: smali_path = os.path.join(dirpath, 'SDKNativeWrapper.smali') print(smali_path) with open(smali_path, 'r', encoding='utf-8') as f: smali_str_arr = f.readlines() index_str = '.method public static native nativeGetRealnameStatus()Ljava/lang/String;' index_str2 = '.method public static native nativeEnterGame(Ljava/util/HashMap;)Ljava/lang/String;' replace_str = '.method public static native nativeGetRealnameStatus()V\n' replace_str2 = '.method public static native nativeEnterGame(Ljava/util/HashMap;)V\n' for line in smali_str_arr: if index_str in line: smali_str_arr[smali_str_arr.index(line)] = replace_str if index_str2 in line: smali_str_arr[smali_str_arr.index(line)] = replace_str2 with open(smali_path, 'w', encoding='utf-8') as f: f.write(''.join(smali_str_arr)) # # 修复脚本 if is_need_fix: os.system(f'python {fix_python_path} {decompile_dir_name} {game_dir}') #修复酷派新sdk 3.0接口方法名改变登录后闪退bug is_version_3_sdk = fix_coolpad_version_3_method_name_change_bug(decompile_dir_name) print('is_version_3_sdk: ', is_version_3_sdk) if is_version_3_sdk: fix_coolpad_version_3_login_fail_bug(decompile_dir_name) fix_install_fail_bug(decompile_dir_name) # # 合包 if '全民泡泡' in game_channel or '我的安吉拉2' in game_channel: cmd_build_str = f'apktool b {decompile_dir_name} -f -o {apk_file_path} --use-aapt2' elif '乱世终结' in game_channel: cmd_build_str = f'apktool b {decompile_dir_name} -f -o {apk_file_path} -api 29' else: cmd_build_str = f'apktool b {decompile_dir_name} -f -o {apk_file_path}' print('cmd_build_str:', cmd_build_str) os.system(cmd_build_str) # 签名 if '极无双' in game_channel or '终末阵线' in game_channel\ or '灌篮高手' in game_channel or '炼仙传说' in game_channel\ or '生死狙击' in game_channel or '全明星激斗' in game_channel\ or '弹弹堂大冒险' in game_channel or '勇者秘境' in game_channel: current_sign = kfzs_sign_youliang if '航海王启航D' in game_channel: current_sign = ydzs_sign if '我叫MT:经典再现Y' in game_channel: current_sign = kfzs_sign cmd_sign_str = rf'{current_sign} {apk_file_path}' print(cmd_sign_str) cmd_result = subprocess.getoutput(cmd_sign_str) print(cmd_result) # 拷贝回测试组 cmd_move_back_to_test_public = f'copy {apk_file_path} {game_dir}' print(cmd_move_back_to_test_public) cmd_result = subprocess.getoutput(cmd_move_back_to_test_public) print(cmd_result) end_time = int(time.time()) print('执行时间s:', end_time-start_time) print('执行时间m:', (end_time-start_time)/60) win32api.MessageBox(0, "游戏修复完毕", "提醒", win32con.MB_OK)