Skip to content

Commit

Permalink
Merge pull request #1024 from Johann-PLW/main
Browse files Browse the repository at this point in the history
Update iTunesBackupInfo.py for lava output
  • Loading branch information
Johann-PLW authored Jan 20, 2025
2 parents 4d599f0 + f215bdd commit 4fab0f2
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 111 deletions.
12 changes: 10 additions & 2 deletions ileapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,14 +368,22 @@ def crunch_artifacts(
if os.path.exists(info_plist_path):
# process_artifact([info_plist_path], 'iTunesBackupInfo', 'Device Info', seeker, out_params.report_folder_base)
#plugin.method([info_plist_path], out_params.report_folder_base, seeker, wrap_text)
report_folder = os.path.join(out_params.report_folder_base, '_HTML')
report_folder = os.path.join(out_params.report_folder_base, '_HTML', 'iTunes Backup')
if not os.path.exists(report_folder):
try:
os.makedirs(report_folder)
except (FileExistsError, FileNotFoundError) as ex:
logfunc('Error creating report directory at path {}'.format(report_folder))
logfunc('Error was {}'.format(str(ex)))
loader["iTunesBackupInfo"].method([info_plist_path], out_params.report_folder_base, seeker, wrap_text, time_offset)
loader["iTunesBackupInfo"].method([info_plist_path], report_folder, seeker, wrap_text, time_offset)
report_folder = os.path.join(out_params.report_folder_base, '_HTML', 'Installed Apps')
if not os.path.exists(report_folder):
try:
os.makedirs(report_folder)
except (FileExistsError, FileNotFoundError) as ex:
logfunc('Error creating report directory at path {}'.format(report_folder))
logfunc('Error was {}'.format(str(ex)))
loader["iTunesBackupInstalledApplications"].method([info_plist_path], report_folder, seeker, wrap_text, time_offset)
#del search_list['lastBuild'] # removing lastBuild as this takes its place
print([info_plist_path]) # TODO Remove special consideration for itunes? Merge into main search
else:
Expand Down
226 changes: 117 additions & 109 deletions scripts/artifacts/iTunesBackupInfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,141 +3,149 @@
"name": "iTunes Backup Information",
"description": "Extract information from the Info.plist file of an iTunes backup",
"author": "@AlexisBrignoni - @johannplw",
"version": "0.1",
"date": "2023-10-11",
"creation_date": "2023-10-11",
"last_update_date": "2025-01-20",
"requirements": "none",
"category": "iTunes Backup Info",
"category": "iTunes Backup",
"notes": "",
"paths": ('*Info.plist', '*info.plist'),
"function": "get_iTunesBackupInfo"
"paths": ('*Info.plist',),
"output_types": ["html", "tsv", "lava"],
"artifact_icon": "refresh-cw"
},
"iTunesBackupInstalledApplications": {
"name": "iTunes Backup - Installed Applications",
"description": "Extract information about installed applications from the Info.plist file of an iTunes backup",
"author": "@johannplw",
"creation_date": "2023-10-11",
"last_update_date": "2025-01-20",
"requirements": "none",
"category": "Installed Apps",
"notes": "",
"paths": ('*Info.plist',),
"output_types": "standard",
"artifact_icon": "package",
}
}

import inspect
import datetime
import plistlib
import scripts.artifacts.artGlobals

from scripts.artifact_report import ArtifactHtmlReport
from scripts.ilapfuncs import logfunc, logdevinfo, tsv
from base64 import b64encode

def get_iTunesMetadata(applications):
app_list=[]

for bundle_id, app_data in applications.items():
apple_id = ''
purchase_date = ''
binary_app_icon = app_data.get('PlaceholderIcon', '')
if binary_app_icon:
base64_icon = b64encode(binary_app_icon).decode('utf-8')
icon_tag = f'<img src="data:image/jpeg;base64,{base64_icon}" alt="{bundle_id} App Icon" width="60">'
else:
icon_tag = ''

if 'iTunesMetadata' in app_data.keys():
itunes_metadata = plistlib.loads(app_data['iTunesMetadata'])
item_name = itunes_metadata.get('itemName', '')
artist_name = itunes_metadata.get('artistName', '')
version = itunes_metadata.get('bundleShortVersionString', '')
genre = itunes_metadata.get('genre', '')
store_cohort = itunes_metadata.get('storeCohort', '')
if 'date=' in store_cohort:
date_start = store_cohort.find('date=') + 5
unix_install_timestamp = store_cohort[date_start:date_start + 10]
install_date = datetime.datetime.fromtimestamp(int(unix_install_timestamp)).strftime('%Y-%m-%d')
download_info = itunes_metadata.get('com.apple.iTunesStore.downloadInfo', '')
if download_info:
account_info = download_info.get('accountInfo', '')
if account_info:
apple_id = account_info.get('AppleID')
purchase_date = download_info.get('purchaseDate', '')
if purchase_date:
purchase_date = purchase_date[:-1].replace('T', ' ')
release_date = itunes_metadata.get('releaseDate', '')
source_app = itunes_metadata.get('sourceApp', '')
auto_download = itunes_metadata.get('is-auto-download', '')
purchased_redownload = itunes_metadata.get('is-purchased-redownload', '')
factory_install = itunes_metadata.get('isFactoryInstall', '')
side_loaded = itunes_metadata.get('sideLoadedDeviceBasedVPP', '')
game_center_enabled = itunes_metadata.get('gameCenterEnabled', '')
game_center_ever_enabled = itunes_metadata.get('gameCenterEverEnabled', '')
messages_extension = itunes_metadata.get('hasMessagesExtension', '')
app_list.append((bundle_id, icon_tag, item_name, artist_name, version, genre,
install_date, apple_id, purchase_date, release_date,
source_app, auto_download, purchased_redownload,
factory_install, side_loaded, game_center_enabled,
game_center_ever_enabled, messages_extension))
elif 'info_plist_bundle_id' in app_data.keys():
app_info = (bundle_id, )
app_info += ('',) * 17
app_list.append(app_info)

return app_list
from scripts.ilapfuncs import artifact_processor, get_file_path, get_plist_file_content, device_info, logfunc

def get_iTunesBackupInfo(files_found, report_folder, seeker, wrap_text, timezone_offset):
@artifact_processor
def iTunesBackupInfo(files_found, report_folder, seeker, wrap_text, timezone_offset):
source_path = get_file_path(files_found, "Info.plist")
data_list = []
apps_iTunesMetadata = []
installed_apps = None
apps = None

file_found = str(files_found[0])
with open(file_found, "rb") as fp:
pl = plistlib.load(fp)
for key, val in pl.items():
if isinstance(val, str) or isinstance(val, int) or isinstance(val, datetime.datetime):
data_list.append((key, val))
if key == ('Product Version'):
scripts.artifacts.artGlobals.versionf = val
logfunc(f"iOS version: {val}")
pl = get_plist_file_content(source_path)
for key, val in pl.items():
if isinstance(val, str) or isinstance(val, int) or isinstance(val, datetime.datetime):
data_list.append((key, val))
if key == ('Product Version'):
scripts.artifacts.artGlobals.versionf = val
logfunc(f"iOS version: {val}")
elif key == "Applications":
apps = val
elif key == "Installed Applications":
installed_apps = set(val)

elif key == "Applications":
apps = val

elif key == "Installed Applications":
installed_apps = set(val)

if installed_apps and apps:
apps_bundle_ids = set(apps)
if len(installed_apps) > len(apps_bundle_ids):
installed_apps = installed_apps.symmetric_difference(apps_bundle_ids)
for installed_app in installed_apps:
apps[installed_app] = {'info_plist_bundle_id': installed_app}
apps_iTunesMetadata = get_iTunesMetadata(apps)
elif installed_apps:
if not installed_apps and apps:
data_list.append(("Installed Applications", ', '.join(installed_apps)))


# Device details
keys = [data[0] for data in data_list]
device_info = ('Product Name', 'Product Type', 'Device Name', 'Product Version', 'Build Version',
dev_info = ('Product Name', 'Product Type', 'Device Name', 'Product Version', 'Build Version',
'Serial Number', 'MEID', 'IMEI', 'IMEI 2', 'ICCID', 'Phone Number',
'Unique Identifier', 'Last Backup Date')
for info in device_info:
for info in dev_info:
if info in keys:
index = keys.index(info)
info_key = data_list[index][0]
value_key = data_list[index][1]
logdevinfo(f"<b>{info_key}: </b>{value_key}")
device_info("iTunes Backup Information", info_key, value_key, source_path)

report = ArtifactHtmlReport('iTunes Backup')
report.start_artifact_report(report_folder, 'iTunes Backup Information')
report.add_script()
data_headers = ('Key','Values')
report.write_artifact_data_table(data_headers, data_list, file_found)
report.end_artifact_report()

tsvname = 'iTunes Backup'
tsv(report_folder, data_headers, data_list, tsvname)
data_headers = ('Property', 'Property Value')
return data_headers, data_list, source_path

if apps_iTunesMetadata:
report = ArtifactHtmlReport('iTunes Backup - Installed Applications')
report.start_artifact_report(report_folder, 'iTunes Backup Installed Applications')
report.add_script()
data_headers = ('Bundle ID', 'App Icon', 'Item Name', 'Artist Name', 'Version',
'Genre', 'Install Date', 'Downloaded by', 'Purchase Date',
'Release Date', 'Source App', 'Auto Download',
'Purchased Redownload', 'Factory Install', 'Side Loaded',
'Game Center Enabled', 'Game Center Ever Enabled',
'Messages Extension')
report.write_artifact_data_table(data_headers, apps_iTunesMetadata, file_found, html_no_escape=['App Icon'])
report.end_artifact_report()
@artifact_processor
def iTunesBackupInstalledApplications(files_found, report_folder, seeker, wrap_text, timezone_offset):
source_path = get_file_path(files_found, "Info.plist")
data_list = []
artifact_info = inspect.stack()[0]
installed_apps = None
apps = None

pl = get_plist_file_content(source_path)
for key, val in pl.items():
if key == "Applications":
apps = val
if key == "Installed Applications":
installed_apps = set(val)

if installed_apps and apps:
apps_bundle_ids = set(apps)
if len(installed_apps) > len(apps_bundle_ids):
installed_apps = installed_apps.symmetric_difference(apps_bundle_ids)
for installed_app in installed_apps:
apps[installed_app] = {'info_plist_bundle_id': installed_app}
for bundle_id, app_data in apps.items():
apple_id = ''
purchase_date = ''
icon = app_data.get('PlaceholderIcon', '')
if icon:
base64_icon = b64encode(icon).decode('utf-8')
icon_tag = f'<img src="data:image/jpeg;base64,{base64_icon}" alt="{bundle_id} App Icon" width="60">'
else:
icon_tag = ''

if 'iTunesMetadata' in app_data.keys():
itunes_metadata = plistlib.loads(app_data['iTunesMetadata'])
item_name = itunes_metadata.get('itemName', '')
artist_name = itunes_metadata.get('artistName', '')
version = itunes_metadata.get('bundleShortVersionString', '')
genre = itunes_metadata.get('genre', '')
store_cohort = itunes_metadata.get('storeCohort', '')
if 'date=' in store_cohort:
date_start = store_cohort.find('date=') + 5
unix_install_timestamp = store_cohort[date_start:date_start + 10]
install_date = datetime.datetime.fromtimestamp(int(unix_install_timestamp)).strftime('%Y-%m-%d')
download_info = itunes_metadata.get('com.apple.iTunesStore.downloadInfo', '')
if download_info:
account_info = download_info.get('accountInfo', '')
if account_info:
apple_id = account_info.get('AppleID')
purchase_date = download_info.get('purchaseDate', '')
if purchase_date:
purchase_date = purchase_date[:-1].replace('T', ' ')
release_date = itunes_metadata.get('releaseDate', '')
source_app = itunes_metadata.get('sourceApp', '')
auto_download = itunes_metadata.get('is-auto-download', '')
purchased_redownload = itunes_metadata.get('is-purchased-redownload', '')
factory_install = itunes_metadata.get('isFactoryInstall', '')
side_loaded = itunes_metadata.get('sideLoadedDeviceBasedVPP', '')
game_center_enabled = itunes_metadata.get('gameCenterEnabled', '')
game_center_ever_enabled = itunes_metadata.get('gameCenterEverEnabled', '')
messages_extension = itunes_metadata.get('hasMessagesExtension', '')
data_list.append((bundle_id, icon_tag, item_name, artist_name, version, genre,
install_date, apple_id, purchase_date, release_date,
source_app, auto_download, purchased_redownload,
factory_install, side_loaded, game_center_enabled,
game_center_ever_enabled, messages_extension))
elif 'info_plist_bundle_id' in app_data.keys():
app_info = (bundle_id, )
app_info += ('',) * 17
data_list.append(app_info)

data_headers = ('Bundle ID', ('App Icon', 'media'), 'Item Name', 'Artist Name', 'Version',
'Genre', 'Install Date', 'Downloaded by', 'Purchase Date',
'Release Date', 'Source App', 'Auto Download',
'Purchased Redownload', 'Factory Install', 'Side Loaded',
'Game Center Enabled', 'Game Center Ever Enabled',
'Messages Extension')
return data_headers, data_list, source_path

0 comments on commit 4fab0f2

Please sign in to comment.