|
|
|
#! /usr/bin/python3
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Author: kelvinBen
|
|
|
|
# Github: https://github.com/kelvinBen/AppInfoScanner
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import shutil
|
|
|
|
import zipfile
|
|
|
|
import binascii
|
|
|
|
import platform
|
|
|
|
import libs.core as cores
|
|
|
|
from queue import Queue
|
|
|
|
|
|
|
|
|
|
|
|
class iOSTask(object):
|
|
|
|
elf_file_name = ""
|
|
|
|
|
|
|
|
def __init__(self, path):
|
|
|
|
self.path = path
|
|
|
|
self.file_queue = Queue()
|
|
|
|
self.shell_flag = False
|
|
|
|
self.file_identifier = []
|
|
|
|
self.permissions = []
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
file_path = self.path
|
|
|
|
if file_path.split(".")[-1] == 'ipa':
|
|
|
|
self.__decode_ipa__(cores.output_path)
|
|
|
|
self.__scanner_file_by_ipa__(cores.output_path)
|
|
|
|
elif self.__get_file_header__(file_path):
|
|
|
|
self.file_queue.put(file_path)
|
|
|
|
else:
|
|
|
|
raise Exception(
|
|
|
|
"Retrieval of this file type is not supported. Select IPA file or Mach-o file.")
|
|
|
|
return {"shell_flag": self.shell_flag, "file_queue": self.file_queue, "comp_list": [], "packagename": None, "file_identifier": self.file_identifier, "permissions": self.permissions}
|
|
|
|
|
|
|
|
def __get_file_header__(self, file_path):
|
|
|
|
hex_hand = 0x0
|
|
|
|
macho_name = os.path.split(file_path)[-1]
|
|
|
|
self.file_identifier.append(macho_name)
|
|
|
|
with open(file_path, "rb") as macho_file:
|
|
|
|
macho_file.seek(hex_hand, 0)
|
|
|
|
magic = binascii.hexlify(macho_file.read(4)).decode().upper()
|
|
|
|
macho_magics = ["CFFAEDFE", "CEFAEDFE", "BEBAFECA", "CAFEBABE"]
|
|
|
|
if magic in macho_magics:
|
|
|
|
self.__shell_test__(macho_file, hex_hand)
|
|
|
|
macho_file.close()
|
|
|
|
return True
|
|
|
|
macho_file.close()
|
|
|
|
return False
|
|
|
|
|
|
|
|
def __shell_test__(self, macho_file, hex_hand):
|
|
|
|
while True:
|
|
|
|
magic = binascii.hexlify(macho_file.read(4)).decode().upper()
|
|
|
|
if magic == "2C000000":
|
|
|
|
macho_file.seek(hex_hand, 0)
|
|
|
|
encryption_info_command = binascii.hexlify(
|
|
|
|
macho_file.read(24)).decode()
|
|
|
|
cryptid = encryption_info_command[-8:len(
|
|
|
|
encryption_info_command)]
|
|
|
|
if cryptid == "01000000":
|
|
|
|
self.shell_flag = True
|
|
|
|
break
|
|
|
|
hex_hand = hex_hand + 4
|
|
|
|
|
|
|
|
def __scanner_file_by_ipa__(self, output):
|
|
|
|
scanner_file_suffix = ["plist", "js", "xml", "html"]
|
|
|
|
scanner_dir = os.path.join(output, "Payload")
|
|
|
|
self.__get_scanner_file__(scanner_dir, scanner_file_suffix)
|
|
|
|
|
|
|
|
def __get_scanner_file__(self, scanner_dir, file_suffix):
|
|
|
|
dir_or_files = os.listdir(scanner_dir)
|
|
|
|
for dir_file in dir_or_files:
|
|
|
|
dir_file_path = os.path.join(scanner_dir, dir_file)
|
|
|
|
if os.path.isdir(dir_file_path):
|
|
|
|
if dir_file.endswith(".app"):
|
|
|
|
self.elf_file_name = dir_file.replace(".app", "")
|
|
|
|
self.__get_scanner_file__(dir_file_path, file_suffix)
|
|
|
|
else:
|
|
|
|
if self.elf_file_name == dir_file:
|
|
|
|
self.__get_file_header__(dir_file_path)
|
|
|
|
self.file_queue.put(dir_file_path)
|
|
|
|
continue
|
|
|
|
if cores.resource_flag:
|
|
|
|
dir_file_suffix = dir_file.split(".")
|
|
|
|
if len(dir_file_suffix) > 1:
|
|
|
|
if dir_file_suffix[-1] in file_suffix:
|
|
|
|
self.__get_file_header__(dir_file_path)
|
|
|
|
self.file_queue.put(dir_file_path)
|
|
|
|
|
|
|
|
def __decode_ipa__(self, output_path):
|
|
|
|
with zipfile.ZipFile(self.path, "r") as zip_files:
|
|
|
|
zip_file_names = zip_files.namelist()
|
|
|
|
zip_files.extract(zip_file_names[0], output_path)
|
|
|
|
try:
|
|
|
|
new_zip_file = zip_file_names[0].encode(
|
|
|
|
'cp437').decode('utf-8')
|
|
|
|
except UnicodeEncodeError:
|
|
|
|
new_zip_file = zip_file_names[0].encode(
|
|
|
|
'utf-8').decode('utf-8')
|
|
|
|
|
|
|
|
old_zip_dir = self.__get_parse_dir__(
|
|
|
|
output_path, zip_file_names[0])
|
|
|
|
new_zip_dir = self.__get_parse_dir__(output_path, new_zip_file)
|
|
|
|
os.rename(old_zip_dir, new_zip_dir)
|
|
|
|
|
|
|
|
for zip_file in zip_file_names:
|
|
|
|
old_ext_path = zip_files.extract(zip_file, output_path)
|
|
|
|
if not "Payload" in old_ext_path:
|
|
|
|
continue
|
|
|
|
start = str(old_ext_path).index("Payload")
|
|
|
|
dir_path = old_ext_path[start:len(old_ext_path)]
|
|
|
|
old_ext_path = os.path.join(output_path, dir_path)
|
|
|
|
try:
|
|
|
|
new_zip_file = zip_file.encode('cp437').decode('utf-8')
|
|
|
|
except UnicodeEncodeError:
|
|
|
|
new_zip_file = zip_file.encode('utf-8').decode('utf-8')
|
|
|
|
|
|
|
|
new_ext_path = os.path.join(output_path, new_zip_file)
|
|
|
|
|
|
|
|
if platform.system() == "Windows":
|
|
|
|
new_ext_path = new_ext_path.replace("/", "\\")
|
|
|
|
|
|
|
|
if not os.path.exists(new_ext_path):
|
|
|
|
dir_path = os.path.dirname(new_ext_path)
|
|
|
|
if not os.path.exists(dir_path):
|
|
|
|
os.makedirs(dir_path)
|
|
|
|
shutil.move(old_ext_path, new_ext_path)
|
|
|
|
# 当旧目录与新目录不一致时,删除旧的目录
|
|
|
|
if not (old_ext_path == new_ext_path) and os.path.exists(old_ext_path) and (".app" in old_ext_path):
|
|
|
|
try:
|
|
|
|
# mac发生权限问题的时候做处理
|
|
|
|
os.remove(old_ext_path)
|
|
|
|
except Exception:
|
|
|
|
shutil.rmtree(old_ext_path)
|
|
|
|
|
|
|
|
def __get_parse_dir__(self, output_path, file_path):
|
|
|
|
start = file_path.index("Payload/")
|
|
|
|
end = file_path.index(".app")
|
|
|
|
root_dir = file_path[start:end]
|
|
|
|
if platform.system() == "Windows":
|
|
|
|
root_dir = root_dir.replace("/", "\\")
|
|
|
|
old_root_dir = os.path.join(output_path, root_dir+".app")
|
|
|
|
return old_root_dir
|