apk_tool.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. import path_utils, contants, file_utils
  2. import os, subprocess, platform, zipfile
  3. from PrintLog import PrintLog
  4. # decompile apk
  5. def decompile(origin_apk_full_path, apk_decompile_out_dir):
  6. PrintLog("------------------------ start to decompiling -------------------------")
  7. global SUFFIX_BAT
  8. if not os.path.exists(origin_apk_full_path):
  9. PrintLog("[no such apk]:%s" % origin_apk_full_path)
  10. return 1
  11. apktool_path = path_utils.get_apktool_path()
  12. decompileCmd = " d -f -o %s/ %s" % (apk_decompile_out_dir, origin_apk_full_path)
  13. ret = exec_jar_cmd(apktool_path, decompileCmd)
  14. PrintLog("------------------------ finished decompiling -------------------------")
  15. return ret
  16. # recompile fileset to apk
  17. def recompile(apk_decompile_out_dir, out_put_unsigned_apk_path):
  18. PrintLog("------------------------------ start to recompile ------------------------------ ")
  19. apktool_path = path_utils.get_apktool_path()
  20. useAppt2 = ''
  21. if contants.IS_USE_AAPT2:
  22. useAppt2 = ' --use-aapt2'
  23. recompileCmd = 'b -f "%s" -o "%s"%s' % (apk_decompile_out_dir, out_put_unsigned_apk_path, useAppt2)
  24. ret = exec_jar_cmd(apktool_path, recompileCmd)
  25. PrintLog("------------------------------ finished recompile ------------------------------ ")
  26. return ret
  27. def signer(out_put_unsigned_apk_path, out_put_signed_apk_path, keystore_path, storepass, alias, keypass):
  28. """
  29. 签名apk
  30. """
  31. # if game in signConfig:
  32. # if sdk in signConfig[game]:
  33. # keystore = signConfig[game][sdk]
  34. # else:
  35. # keystore = signConfig['default']
  36. # else:
  37. # keystore = signConfig['default']
  38. apksigner = path_utils.get_apksigner_path()
  39. # 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
  40. useV2sign = ''
  41. if contants.IS_USE_APK_V2_SIGN:
  42. useV2sign = ' --v2-signing-enabled=false'
  43. return exec_jar_cmd(apksigner,
  44. 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (
  45. useV2sign, keystore_path, alias, storepass,
  46. keypass, out_put_signed_apk_path, out_put_unsigned_apk_path))
  47. def zipalign(out_put_signed_apk_path, out_put_zipalign_apk_path):
  48. align_apk_tool = path_utils.get_zipalign_path()
  49. return exec_format_cmd(
  50. '"%s" -f -p 4 "%s" "%s"' % (align_apk_tool, out_put_signed_apk_path, out_put_zipalign_apk_path))
  51. def exec_jar_cmd(jar, params):
  52. """
  53. 执行cmd命令
  54. 返回值:None —— 子进程尚未结束;
  55. ==0 —— 子进程正常退出;
  56. > 0—— 子进程异常退出,return code对应于出错码;
  57. < 0—— 子进程被信号杀掉了。
  58. """
  59. '''print(cmd)
  60. p = os.popen(cmd)
  61. print(p.read())'''
  62. cmd = 'java -jar "%s" %s' % (jar, params)
  63. PrintLog("[exec_jar_cmd]:%s" % cmd)
  64. ret = 0
  65. try:
  66. s = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, cwd=None)
  67. std_output, err_output = s.communicate()
  68. if platform.system() == 'Windows':
  69. std_output = std_output.decode('gbk')
  70. err_output = err_output.decode('gbk')
  71. '''
  72. None —— 子进程尚未结束;
  73. ==0 —— 子进程正常退出;
  74. > 0—— 子进程异常退出,return code对应于出错码;
  75. < 0—— 子进程被信号杀掉了。
  76. '''
  77. ret = s.returncode
  78. if ret:
  79. print('*******ERROR*******')
  80. print(std_output)
  81. print(err_output)
  82. print('*******************')
  83. cmd = 'error::' + cmd + ' !!!exec Fail!!! '
  84. else:
  85. print(std_output)
  86. print(err_output)
  87. cmd = cmd + ' !!!exec success!!! '
  88. print(cmd)
  89. except Exception as e:
  90. print('Exception ' + e)
  91. return 1
  92. return ret
  93. def exec_format_cmd(cmd, cd=None):
  94. """
  95. 执行cmd命令
  96. 返回值:None —— 子进程尚未结束;
  97. ==0 —— 子进程正常退出;
  98. > 0—— 子进程异常退出,return code对应于出错码;
  99. < 0—— 子进程被信号杀掉了。
  100. """
  101. '''print(cmd)
  102. p = os.popen(cmd)
  103. print(p.read())'''
  104. ret = 0
  105. try:
  106. s = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, cwd=cd)
  107. std_output, err_output = s.communicate()
  108. if platform.system() == 'Windows':
  109. std_output = std_output.decode('gbk')
  110. err_output = err_output.decode('gbk')
  111. '''
  112. None —— 子进程尚未结束;
  113. ==0 —— 子进程正常退出;
  114. > 0—— 子进程异常退出,return code对应于出错码;
  115. < 0—— 子进程被信号杀掉了。
  116. '''
  117. ret = s.returncode
  118. if ret:
  119. print('*******ERROR*******')
  120. print(std_output)
  121. print(err_output)
  122. print('*******************')
  123. cmd = 'error::' + cmd + ' !!!exec Fail!!! '
  124. else:
  125. print(std_output)
  126. print(err_output)
  127. cmd = cmd + ' !!!exec success!!! '
  128. print(cmd)
  129. except Exception as e:
  130. print('Exception ' + e)
  131. return 1
  132. return ret
  133. def create_R_file(apk_decompile_tmp_dir, package_name):
  134. decomplie_res_path = os.path.join(apk_decompile_tmp_dir, 'res')
  135. temp_gen_path = os.path.join(apk_decompile_tmp_dir, 'gen')
  136. if not os.path.exists(temp_gen_path):
  137. os.mkdir(temp_gen_path)
  138. temp_manifest_path = os.path.join(apk_decompile_tmp_dir, 'AndroidManifest.xml')
  139. android_platforms = path_utils.get_android_compile_tool_path()
  140. if not contants.IS_USE_AAPT2:
  141. aapt = path_utils.get_aapt_path()
  142. ret = get_exec_permission(aapt)
  143. if ret:
  144. return ret
  145. createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (
  146. aapt, temp_gen_path, decomplie_res_path, android_platforms, temp_manifest_path)
  147. ret = exec_format_cmd(createRCmd)
  148. if ret:
  149. return ret
  150. else:
  151. aapt2 = path_utils.get_aapt2_path()
  152. ret = get_exec_permission(aapt2)
  153. if ret:
  154. return ret
  155. complie_res_zip = os.path.join(temp_gen_path, 'resource.zip')
  156. complieResCmd = '%s compile --dir %s -o %s ' % (
  157. aapt2, decomplie_res_path, complie_res_zip)
  158. ret = exec_format_cmd(complieResCmd)
  159. if ret:
  160. return ret
  161. # link
  162. print('link res ...')
  163. outApk = os.path.join(temp_gen_path, 'sources.apk')
  164. linkResCmd = '%s link -o %s -I %s --manifest %s --java %s/ %s' % (
  165. aapt2, outApk, android_platforms, temp_manifest_path, temp_gen_path, complie_res_zip)
  166. print('link cmd is %s' % linkResCmd)
  167. ret = exec_format_cmd(linkResCmd)
  168. if ret:
  169. return ret
  170. # 编译R文件
  171. r_source_pkg_name = package_name.replace(".", "/")
  172. r_pkg_path = os.path.join(temp_gen_path, r_source_pkg_name)
  173. r_source_path = os.path.join(r_pkg_path, 'R.java')
  174. createRClassCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % r_source_path
  175. ret = exec_format_cmd(createRClassCmd)
  176. if ret:
  177. return ret
  178. # 生成dex
  179. print('dex R.class ...')
  180. outDex = os.path.join(temp_gen_path, 'classes.dex')
  181. if not contants.IS_USE_AAPT2:
  182. dx = path_utils.get_dx_path()
  183. dexCmd = '--dex --no-warning --output="%s" "%s"' % (
  184. outDex, temp_gen_path)
  185. else:
  186. dx = path_utils.get_d8_path()
  187. clazz = os.path.join(r_pkg_path, '*.class')
  188. dexCmd = '--lib "%s" --output "%s" %s' % (
  189. android_platforms, temp_gen_path, clazz)
  190. ret = exec_jar_cmd(dx, dexCmd)
  191. if ret:
  192. return ret
  193. # 反向dex生成smali
  194. # 存放在out目录
  195. print('baksmali classes.dex ...')
  196. bak_smali_path = path_utils.get_baksmali_path()
  197. out_smali_path = os.path.join(temp_gen_path, 'out')
  198. ret = exec_jar_cmd(
  199. bak_smali_path, 'd "%s" -o "%s"' % (outDex, out_smali_path))
  200. if ret:
  201. return ret
  202. # 将生成的文件拷贝到目标目录
  203. print('copy R.smali ...')
  204. smaliPath = os.path.join(apk_decompile_tmp_dir, 'smali')
  205. file_utils.copy_file_all_dir(out_smali_path, smaliPath)
  206. return 0
  207. def get_exec_permission(file):
  208. """
  209. linux下获取执行权限
  210. """
  211. if platform.system() == 'Windows':
  212. return 0
  213. return exec_format_cmd('chmod +x "%s"' % file)
  214. if __name__ == "__main__":
  215. create_R_file('/Users/kaiweicai/Documents/Project/PackKit/YYXXPackKit/game/037848/dcm_tmphuawei',
  216. 'com.yyxx.qyj2.huawei')