【Android 逆向】APK 文件处理脚本 ApkTool.py ( 脚本简介 | 用法 | 分析 APK 文件 )(一)

简介: 【Android 逆向】APK 文件处理脚本 ApkTool.py ( 脚本简介 | 用法 | 分析 APK 文件 )(一)

文章目录

一、APK 文件处理脚本 ApkTool.py

二、ApkTool.py 脚本用法

三、ApkTool.py 脚本分析 APK 输出结果





一、APK 文件处理脚本 ApkTool.py


ApkTool.py 是一个 APK 文件处理脚本 , 主要针对 APK 文件进行各种处理 , 如文件分析 ;


该脚本需要使用 apktool.jar 和 aapt.exe 工具 , 将这两个文件放在 ApkTool.py 同级目录中 ;

image.png


完整运行环境参考 https://github.com/han1202012/APK ;



ApkTool.py 脚本内容 :


# coding=utf-8
import os
import sys
import argparse
from subprocess import Popen, PIPE
import sys
reload(sys)
sys.setdefaultencoding('utf8')
class ApkTool:
    def __init__(self, keystore=None, password=None, alias=None):
        if sys.platform == 'win32':
            self.file_separator = '\\'
        else:
            self.file_separator = '/'
        path = ''
        if hasattr(sys, '_MEIPASS'):
            path = sys._MEIPASS + self.file_separator
        self.apktooljar = path + 'apktool.jar'
        self.aapt = path + 'aapt.exe'
        self.objdump_x86 = path + 'objdump_x86.exe'
        self.objdump_arm = path + 'objdump_arm.exe'
        if keystore is None:
            self.keystore = path + 'mykey-123456.keystore'
        else:
            self.keystore = keystore
        if password is None:
            self.password = '123456'
        else:
            self.password = password
        if alias is None:
            self.alias = 'mykey'
        else:
            self.alias = alias
        self.cur_apk = {}
        return
    def unpack(self, apk, path):
        cmd = 'java -jar ' + self.apktooljar + (' d -f -o %s %s' % (path, apk))
        os.system(cmd)
        return
    def pack(self, path, apk):
        cmd = 'java -jar ' + self.apktooljar + (' b %s -o %s' % (path, apk))
        os.system(cmd)
        return
    def sign(self, apk, signed_apk):
        path, file = os.path.split(signed_apk)
        if os.path.exists(path) is False:
            os.makedirs(path)
        keystore = ' -keystore %s -storepass %s' % (self.keystore, self.password)
        signedjar = ' -signedjar %s %s -digestalg SHA1 -sigalg MD5withRSA %s' % (signed_apk, apk, self.alias)
        cmd = 'jarsigner -verbose ' + keystore + signedjar
        print(cmd)
        os.system(cmd)
    def get_apk_label(self, apk_path):
        pipe = Popen([self.aapt, 'dump', 'badging', apk_path], stdout=PIPE)
        if pipe is not None:
            while True:
                line = pipe.stdout.readline()
                line = line.decode('utf-8')
                if len(line) == 0:
                    break
                pos = line.find('application-label:')
                if pos != -1:
                    return line[pos + 19:len(line) - 3]  # \r\n占了2个,加上单引号一共3个字符
        return ''
    def get_apk_package_name(self, apk):
        pipe = Popen([self.aapt, 'dump', 'badging', apk], stdout=PIPE)
        if pipe is not None:
            while True:
                line = pipe.stdout.readline()
                line = line.decode('utf-8')
                if len(line) == 0:
                    break
                pos = line.find('package:')
                if pos != -1:
                    return line[pos + 8:len(line) - 2]  # \r\n占了2个,加上单引号一共3个字符
        return ''
def get_game_engine(libpath, file_separator):
    data = {
        'libcocos2dcpp.so': 'cocos引擎 cpp',
        'libcocos2dlua.so': 'cocos引擎 lua',
        'libcocos2djs.so': 'cocos引擎 javascipt',
        'libunity.so': 'unity3D引擎',
        'libgdx.so': 'libgdx引擎'
    }
    dir = ['armeabi-v7a', 'armeabi', 'x86']
    for d in dir:
        lib = libpath + d + file_separator
        for f in data.keys():
            if os.path.exists(lib + f):
                return data[f]
    return '未知引擎'
def analyse(apk, tool):
    path, file = os.path.split(apk)
    if len(path) == 0:
        path = '.'
    out_name = file[:-4]
    out_txt = out_name + '.txt'
    f_out = open(out_txt, 'w+')
    line = '文件名称:%s\n' % apk
    f_out.write(line)
    line = '应用名称:%s\n' % tool.get_apk_label(apk)
    f_out.write(line)
    line = '应用信息:%s\n' % tool.get_apk_package_name(apk)
    f_out.write(line)
    unpack_path = path + tool.file_separator + 'unpack' + tool.file_separator + out_name
    if os.path.exists(unpack_path) is False:
        os.makedirs(unpack_path)
    repack_path = path + tool.file_separator + 'repack' + tool.file_separator + out_name + '.apk'
    if os.path.exists(path + tool.file_separator + 'repack') is False:
        os.makedirs(path + tool.file_separator + 'repack')
    sign_path = path + tool.file_separator + 'sign' + tool.file_separator + out_name + '.apk'
    if os.path.exists(path + tool.file_separator + 'sign') is False:
        os.makedirs(path + tool.file_separator + 'sign')
    if os.path.exists(unpack_path + tool.file_separator + 'lib') is False:
        tool.unpack(apk, unpack_path)
    if os.path.exists(repack_path) is False:
        tool.pack(unpack_path, repack_path)
    if os.path.exists(sign_path) is False:
        tool.sign(repack_path, sign_path)
    if os.path.exists(repack_path) is False:
        line = '打包检测:重打包失败,无法重打包\n'
    else:
        line = '打包检测:重打包成功\n'
        is_repack_ok = True
    f_out.write(line)
    if os.path.exists(sign_path) is False:
        line = '签名检测:重签名失败,无法重签名\n'
    else:
        line = '签名检测:重签名成功\n'
    f_out.write(line)
    libpath = unpack_path + tool.file_separator
    libpath += 'lib' + tool.file_separator
    line = '引擎检测:%s\n' % get_game_engine(libpath, tool.file_separator)
    f_out.write(line)
    f_out.write(
        '----------------------------------------------------------------------------------------------------------------------------------\n')
    f_out.close()
    pass
def main():
    parser = argparse.ArgumentParser(prog=sys.argv[0], usage='%(prog)s [options]')
    help = """help 或者 -h 显示本帮助文档 """
    parser.add_argument('-help', help=help, action='store_const', const='help')
    parser.add_argument('-keystore', nargs='?', help='指定签名文件,默认mykey-123456.keystore')
    parser.add_argument('-passwd', nargs='?', help='指定签名密码,默认123456')
    parser.add_argument('-alias', nargs='?', help='指定签名别名,默认mykey')
    parser.add_argument('-label', help='获取包名', action='store_const', const='label')
    parser.add_argument('-unpack', help='解包文件', action='store_const', const='unpack')
    parser.add_argument('-pack', help='打包文件', action='store_const', const='pack')
    parser.add_argument('-sign', help='签名文件', action='store_const', const='sign')
    parser.add_argument('-analyse', help='分析包', action='store_const', const='analyse')
    parser.add_argument('-inapk', nargs='?', help='指定输入apk路径')
    parser.add_argument('-outapk', nargs='?', help='指定输出apk路径')
    parser.add_argument('-outpath', nargs='?', help='指定输出目录')
    parser.add_argument('-inpath', nargs='?', help='指定输入目录')
    args = parser.parse_args()
    if args.help is not None:
        parser.print_help()
        return
    attrs = ['keystore', 'passwd', 'alias', 'inapk', 'outapk', 'inpath', 'outpath', 'help']
    value_map = {}
    for attr in attrs:
        value_map[attr] = getattr(args, attr, None)
    tool = ApkTool(value_map['keystore'], value_map['passwd'], value_map['alias'])
    if args.unpack is not None:
        # -unpack -inapk D:\bamenGame\测试游戏\17.12.18jhzd.apk -outpath D:\bamenGame\测试游戏\out\17.12.18jhzd
        if value_map['inapk'] is None:
            print('需要指定输入apk路径')
            return
        if value_map['outpath'] is None:
            print('需要指定输出目录')
            return
        tool.unpack(value_map['inapk'], value_map['outpath'])
        return
    if args.pack is not None:
        # -pack -outapk D:\bamenGame\测试游戏\repack\17.12.18jhzd.apk -inpath D:\bamenGame\测试游戏\out\17.12.18jhzd
        if value_map['inpath'] is None:
            print('需要指定输入目录')
            return
        if value_map['outapk'] is None:
            print('需要指定输出包路径')
            return
        tool.pack(value_map['inpath'], value_map['outapk'])
        return
    if args.sign is not None:
        # -sign -inapk D:\bamenGame\测试游戏\repack\17.12.18jhzd.apk -outapk D:\bamenGame\测试游戏\sign\17.12.18jhzd.apk
        if value_map['inapk'] is None:
            print('需要指定输入目录')
            return
        if value_map['outapk'] is None:
            print('需要指定输出包路径')
            return
        tool.sign(value_map['inapk'], value_map['outapk'])
        return
    if args.label is not None:
        if value_map['inapk'] is None:
            print('需要指定输入游戏包')
            return
        print(tool.get_apk_label(value_map['inapk']))
        return
    if args.analyse is not None:
        if value_map['inapk'] is None:
            print('需要指定输入游戏包,现在分析当前目录下所有的apk文件')
            for file in os.listdir(os.curdir):
                if os.path.isdir(file):
                    continue
                if os.path.splitext(file)[1] == '.apk':
                    analyse(file, tool)
            return
        analyse(value_map['inapk'], tool)
        return
    parser.print_help()
if __name__ == '__main__':
    main()






二、ApkTool.py 脚本用法


执行如下命令 , 分析 apk 文件 ;


python ApkTool.py -analyse -inapk apk/app-debug.apk


分析结果会放在 ApkTool.py 脚本所在目录的 app-debug.txt 文件中 , app-debug 是 apk 文件的名称 , 后缀改为 txt ;


分析完毕的内容如下 :


文件名称:apk/app-debug.apk
应用名称:EventBus_Demo
应用信息: name='com.eventbus_demo' versionCode='1' versionName='1.0' platformBuildVersionName=''
打包检测:重打包成功
签名检测:重签名成功
引擎检测:未知引擎
----------------------------------------------------------------------------------------------------------------------------------


如果文件比较多的话 , 通宵跑程序 ;


如果应用做了加固处理 , 是无法进行重打包的 ;




目录
相关文章
|
2月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
271 4
|
2月前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
2月前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
89 21
|
1月前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
36 8
|
Java Android开发 存储
Android 文件操作心得体会
android 的文件操作说白了就是Java的文件操作的处理。所以如果对Java的io文件操作比较熟悉的话,android的文件操作就是小菜一碟了。好了,话不多说,开始今天的正题吧。
984 0
|
Android开发
android 文件操作
详细介绍:http://wenku.baidu.com/view/fcf6d3f47c1cfad6195fa724.html?from=rec&pos=0&weight=14&lastweight=1&count=5        /**          * 在SD卡上创建文件  ...
734 0
|
3天前
|
缓存 前端开发 Android开发
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
|
7天前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈

热门文章

最新文章

  • 1
    app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
  • 2
    【03】优雅草央千澈详解关于APP签名以及分发-上架完整流程-第三篇安卓APP上架华为商店后面的步骤-华为应用商店相对比较麻烦一些-华为商店安卓上架
  • 3
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 4
    apk安装包EXE,mis程序打包后报毒的正确处理方式-千万不要再人傻钱多被骗-真正的合法途径的处理方式才是正确的-apk安装包EXE,mis程序如何处理-优雅草央千澈
  • 5
    【03】完整flutter的APP打包流程-以apk设置图标-包名-签名-APP名-打包流程为例—-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈 章节内容【03】
  • 6
    如何修复 Android 和 Windows 不支持视频编解码器的问题?
  • 7
    【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
  • 8
    [Android] 基于WLAN无线执行自动化方法
  • 9
    [Android Pro] CPU占用计算方法
  • 10
    Android之TCP服务器编程