You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
AppInfoScanner/libs/task/android_task.py

153 lines
6.3 KiB

#! /usr/bin/python3
# -*- coding: utf-8 -*-
# Author: kelvinBen
# Github: https://github.com/kelvinBen/AppInfoScanner
import os
import re
import config
import hashlib
from queue import Queue
import libs.core as cores
class AndroidTask(object):
def __init__(self, path, package):
self.path = path
self.package = package
self.file_queue = Queue()
self.shell_flag = False
self.packagename = ""
self.comp_list = []
self.file_identifier = []
self.permissions = []
def start(self):
# 检查java环境是否存在
if os.system("java -version") != 0:
raise Exception("Please install the Java environment!")
input_file_path = self.path
if os.path.isdir(input_file_path):
self.__decode_dir__(input_file_path)
else:
if self.__decode_file__(input_file_path) == "error":
raise Exception(
"Retrieval of this file type is not supported. Select APK file or DEX file.")
return {"comp_list": self.comp_list, "shell_flag": self.shell_flag, "file_queue": self.file_queue, "packagename": self.packagename, "file_identifier": self.file_identifier, "permissions": self.permissions}
def __decode_file__(self, file_path):
apktool_path = str(cores.apktool_path)
backsmali_path = str(cores.backsmali_path)
base_out_path = str(cores.output_path)
filename = os.path.basename(file_path)
suffix_name = filename.split(".")[-1]
if suffix_name == "apk" or suffix_name == "hpk":
name = filename.split(".")[0]
output_path = os.path.join(base_out_path, name)
self.__decode_apk__(file_path, apktool_path, output_path)
elif suffix_name == "dex":
f = open(file_path, 'rb')
md5_obj = hashlib.md5()
while True:
r = f.read(1024)
if not r:
break
md5_obj.update(r)
dex_md5 = md5_obj.hexdigest().lower()
self.file_identifier.append(dex_md5)
output_path = os.path.join(base_out_path, dex_md5)
if not os.path.exists(output_path):
os.makedirs(output_path)
self.__decode_dex__(file_path, backsmali_path, output_path)
else:
return "error"
def __decode_dir__(self, root_dir):
dir_or_files = os.listdir(root_dir)
for dir_or_file in dir_or_files:
dir_or_file_path = os.path.join(root_dir, dir_or_file)
if os.path.isdir(dir_or_file_path):
self.__decode_dir__(dir_or_file_path)
else:
if self.__decode_file__(dir_or_file_path) == "error":
continue
# 分解apk
def __decode_apk__(self, file_path, apktool_path, output_path):
cmd_str = ('java -jar "%s" d -f "%s" -o "%s" --only-main-classe') % (
str(apktool_path), str(file_path), str(output_path))
if os.system(cmd_str) == 0:
self.__shell_test__(output_path)
self.__scanner_file_by_apktool__(output_path)
else:
print("[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues")
raise Exception(file_path + ", Decompilation failed.")
# 分解dex
def __decode_dex__(self, file_path, backsmali_path, output_path):
cmd_str = ('java -jar "%s" d "%s"') % (str(backsmali_path),
str(file_path))
if os.system(cmd_str) == 0:
self.__get_scanner_file__(output_path)
else:
print("[-] Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues")
raise Exception(file_path + ", Decompilation failed.")
# 初始化检测文件信息
def __scanner_file_by_apktool__(self, output_path):
file_names = os.listdir(output_path)
for file_name in file_names:
file_path = os.path.join(output_path, file_name)
if not os.path.isdir(file_path):
continue
if "smali" in file_name or "assets" in file_name:
scanner_file_suffixs = ["smali", "js", "xml"]
if cores.resource_flag:
scanner_file_suffixs = ["smali"]
self.__get_scanner_file__(file_path, scanner_file_suffixs)
def __get_scanner_file__(self, scanner_dir, scanner_file_suffixs=["smali"]):
dir_or_files = os.listdir(scanner_dir)
for dir_or_file in dir_or_files:
dir_file_path = os.path.join(scanner_dir, dir_or_file)
if os.path.isdir(dir_file_path):
self.__get_scanner_file__(dir_file_path, scanner_file_suffixs)
else:
if ("." not in dir_or_file) or (len(dir_or_file.split(".")) < 1) or (dir_or_file.split(".")[-1] not in scanner_file_suffixs):
continue
self.file_queue.put(dir_file_path)
for component in config.filter_components:
comp = component.replace(".", "/")
if(comp in dir_file_path):
if(component not in self.comp_list):
self.comp_list.append(component)
def __shell_test__(self, output):
am_path = os.path.join(output, "AndroidManifest.xml")
with open(am_path, "r", encoding='utf-8', errors='ignore') as f:
am_str = f.read()
am_package = re.compile(r'<manifest.*package=\"(.*?)\".*')
apackage = am_package.findall(am_str)
if len(apackage) >= 1:
self.packagename = apackage[0]
self.file_identifier.append(apackage[0])
am_name = re.compile(r'<application.*android:name=\"(.*?)\".*>')
aname = am_name.findall(am_str)
if aname and len(aname) >= 1:
if aname[0] in config.shell_list:
self.shell_flag = True
am_permission = re.compile(r'<uses-permission android:name="(.*)"/>')
ampermissions = am_permission.findall(am_str)
for ampermission in ampermissions:
if ampermission in config.apk_permissions:
self.permissions.append(ampermission)