# -*- coding:utf-8 -*- import path_utils, contants, file_utils import os, subprocess, platform, zipfile, re from print_log import printlog # decompile apk def decompile(origin_apk_full_path, apk_decompile_out_dir): printlog("------------------------ start to decompiling -------------------------") global SUFFIX_BAT if not os.path.exists(origin_apk_full_path): printlog("[no such apk]:%s" % origin_apk_full_path) return 1 apktool_path = path_utils.get_apktool_path() decompileCmd = " d -f -o %s/ %s" % (apk_decompile_out_dir, origin_apk_full_path) ret = exec_jar_cmd(apktool_path, decompileCmd) printlog("------------------------ finished decompiling -------------------------") return ret # recompile fileset to apk def recompile(apk_decompile_out_dir, out_put_unsigned_apk_path): printlog("------------------------------ start to recompile ------------------------------ ") apktool_path = path_utils.get_apktool_path() useAppt2 = '' if contants.IS_USE_AAPT2: useAppt2 = ' --use-aapt2' recompileCmd = 'b -f "%s" -o "%s"%s' % (apk_decompile_out_dir, out_put_unsigned_apk_path, useAppt2) ret = exec_jar_cmd(apktool_path, recompileCmd) printlog("------------------------------ finished recompile ------------------------------ ") return ret def V1signer(out_put_unsigned_apk_path, out_put_signed_apk_path, keystore_path, storepass, alias, keypass): getKeystoreAlgorithmCmd = "%s -list -v -keystore %s -alias %s -storepass %s" % ( contants.KEY_TOOL_PATH, keystore_path, alias, storepass) ret, result = exec_format_cmd_with_result(getKeystoreAlgorithmCmd) regex = re.compile('签名算法名称: (\S+)') algorithm_method = regex.findall(result) if algorithm_method: algorithm_method = algorithm_method[0] else: regex = re.compile('Signature algorithm name: (\S+)') algorithm_method = regex.findall(result) if algorithm_method: algorithm_method = algorithm_method[0] if not algorithm_method: printlog("获取签名算法失败,签名失败。") return 1 printlog("签名文件算法为:%s" % algorithm_method) resignCmd = "%s -sigalg %s -digestalg SHA1 -storepass %s -keypass %s -keystore %s -signedjar %s %s %s" % ( contants.JAR_SIGNER_TOOL_PATH, algorithm_method, storepass, keypass, keystore_path, out_put_signed_apk_path, out_put_unsigned_apk_path, alias) return exec_format_cmd(resignCmd) def signer(out_put_unsigned_apk_path, out_put_signed_apk_path, keystore_path, storepass, alias, keypass): """ 签名apk """ # if game in signConfig: # if sdk in signConfig[game]: # keystore = signConfig[game][sdk] # else: # keystore = signConfig['default'] # else: # keystore = signConfig['default'] apksigner = path_utils.get_apksigner_path() # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk useV2sign = '' if not contants.IS_USE_APK_V2_SIGN: useV2sign = ' --v2-signing-enabled=false' return exec_jar_cmd(apksigner, 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % ( useV2sign, keystore_path, alias, storepass, keypass, out_put_signed_apk_path, out_put_unsigned_apk_path)) def zipalign(out_put_signed_apk_path, out_put_zipalign_apk_path): align_apk_tool = path_utils.get_zipalign_path() return exec_format_cmd( '"%s" -f -p 4 "%s" "%s"' % (align_apk_tool, out_put_signed_apk_path, out_put_zipalign_apk_path)) def exec_jar_cmd(jar, params): cmd = 'java -jar "%s" %s' % (jar, params) printlog("[exec_jar_cmd]:%s" % cmd) ret, result = exec_common_cmd(cmd) return ret def exec_format_cmd(cmd): ret, result = exec_common_cmd(cmd) return ret def exec_format_cmd_with_result(cmd): ret, result = exec_common_cmd(cmd) return ret, result def exec_common_cmd(cmd, cd=None): """ 执行cmd命令 返回值:None —— 子进程尚未结束; ==0 —— 子进程正常退出; > 0—— 子进程异常退出,return code对应于出错码; < 0—— 子进程被信号杀掉了。 """ '''print(cmd) p = os.popen(cmd) print(p.read())'' ''' try: s = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, cwd=cd,encoding='utf-8') std_output, err_output = s.communicate() if platform.system() == 'Windows': std_output = std_output.decode('gbk') err_output = err_output.decode('gbk') ''' None —— 子进程尚未结束; ==0 —— 子进程正常退出; > 0—— 子进程异常退出,return code对应于出错码; < 0—— 子进程被信号杀掉了。 ''' ret = s.returncode if ret: print('*******ERROR*******') print(std_output) print(err_output) print('*******************') cmd = 'error::' + cmd + ' !!!exec Fail!!! ' else: print(std_output) print(err_output) cmd = cmd + ' !!!exec success!!! ' print(cmd) except Exception as e: print('Exception ' + e) return 1, e return ret, std_output def create_R_file(apk_decompile_tmp_dir, package_name): decomplie_res_path = os.path.join(apk_decompile_tmp_dir, 'res') temp_gen_path = os.path.join(apk_decompile_tmp_dir, 'gen') if not os.path.exists(temp_gen_path): os.mkdir(temp_gen_path) temp_manifest_path = os.path.join(apk_decompile_tmp_dir, 'AndroidManifest.xml') android_platforms = path_utils.get_android_compile_tool_path() if not contants.IS_USE_AAPT2: aapt = path_utils.get_aapt_path() ret = get_exec_permission(aapt) if ret: return ret createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % ( aapt, temp_gen_path, decomplie_res_path, android_platforms, temp_manifest_path) ret = exec_format_cmd(createRCmd) if ret: return ret else: aapt2 = path_utils.get_aapt2_path() ret = get_exec_permission(aapt2) if ret: return ret complie_res_zip = os.path.join(temp_gen_path, 'resource.zip') complieResCmd = '%s compile --dir %s -o %s ' % ( aapt2, decomplie_res_path, complie_res_zip) ret = exec_format_cmd(complieResCmd) if ret: return ret # link print('link res ...') outApk = os.path.join(temp_gen_path, 'sources.apk') linkResCmd = '%s link -o %s -I %s --manifest %s --java %s/ %s' % ( aapt2, outApk, android_platforms, temp_manifest_path, temp_gen_path, complie_res_zip) print('link cmd is %s' % linkResCmd) ret = exec_format_cmd(linkResCmd) if ret: return ret # 编译R文件 r_source_pkg_name = package_name.replace(".", "/") r_pkg_path = os.path.join(temp_gen_path, r_source_pkg_name) r_source_path = os.path.join(r_pkg_path, 'R.java') createRClassCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % r_source_path ret = exec_format_cmd(createRClassCmd) if ret: return ret # 生成dex print('dex R.class ...') outDex = os.path.join(temp_gen_path, 'classes.dex') if not contants.IS_USE_AAPT2: dx = path_utils.get_dx_path() dexCmd = '--dex --no-warning --output="%s" "%s"' % ( outDex, temp_gen_path) else: dx = path_utils.get_d8_path() clazz = os.path.join(r_pkg_path, '*.class') dexCmd = '--lib "%s" --output "%s" %s' % ( android_platforms, temp_gen_path, clazz) ret = exec_jar_cmd(dx, dexCmd) if ret: return ret # 反向dex生成smali # 存放在out目录 print('baksmali classes.dex ...') bak_smali_path = path_utils.get_baksmali_path() out_smali_path = os.path.join(temp_gen_path, 'out') ret = exec_jar_cmd( bak_smali_path, 'd "%s" -o "%s"' % (outDex, out_smali_path)) if ret: return ret # 将生成的文件拷贝到目标目录 print('copy R.smali ...') smaliPath = os.path.join(apk_decompile_tmp_dir, 'smali') file_utils.copy_file_all_dir(out_smali_path, smaliPath) return 0 def get_exec_permission(file): """ linux下获取执行权限 """ if platform.system() == 'Windows': return 0 return exec_format_cmd('chmod +x "%s"' % file) if __name__ == "__main__": V1signer('/Users/kaiweicai/Documents/Project/PackKit/YYXXPackKit/output/g1_huawei_com.yyxx.qyj2.huawei_Y010402.apk', '/Users/kaiweicai/Documents/Project/PackKit/YYXXPackKit/output/g1_huawei_com.yyxx.qyj2.huawei_Y010402_____.apk', '/Users/kaiweicai/Documents/Project/PackKit/YYXXPackKit/keystore/ziyun.jks' , 'yh1234', 'key0', 'yh1234')