【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开发
Android经典实战之TextureView原理和高级用法
本文介绍了 `TextureView` 的原理和特点,包括其硬件加速渲染的优势及与其他视图叠加使用的灵活性,并提供了视频播放和自定义绘制的示例代码。通过合理管理生命周期和资源,`TextureView` 可实现高效流畅的图形和视频渲染。
246 12
|
3月前
|
Java Android开发 Windows
使用keytool查看Android APK签名
本文介绍了如何使用Windows命令行工具和keytool查看APK的签名信息,并提供了使用AOSP环境中的signapk.jar工具对APK进行系统签名的方法。
388 0
使用keytool查看Android APK签名
|
3月前
|
Android开发
将AAB(Android App Bundle)转换为APK
将AAB(Android App Bundle)转换为APK
252 1
|
3月前
|
Android开发 开发者
Android、Flutter为不同的CPU架构包打包APK(v7a、v8a、x86)
Android、Flutter为不同的CPU架构包打包APK(v7a、v8a、x86)
296 1
|
3月前
|
Android开发
解决android apk安装后出现2个相同的应用图标
解决android apk安装后出现2个相同的应用图标
349 2
|
7天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
12天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
14天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
16天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。
下一篇
无影云桌面