Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Change paths where we look for dyld and support multiple restore images #8

Merged
merged 1 commit into from
Sep 28, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 59 additions & 28 deletions import_system_symbols_from_ipsw.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from dataclasses import asdict, dataclass
from datetime import datetime
from pathlib import Path
from typing import Dict, List
from typing import Dict, List, Tuple
from urllib.parse import ParseResult, urlparse

import click
Expand Down Expand Up @@ -223,17 +223,54 @@ def extract_symbols_from_one_ipsw_archive(
span = sentry_sdk.Hub.current.scope.span
with span.start_child(op="task", description="Extract IPSW archive"):
extract_zip_archive(ipsw_archive_path, extract_dir)
plist_path = os.path.join(extract_dir, "Restore.plist")
(system_restore_image_filename, os_version, build_number) = read_restore_plist(plist_path)

# Starting iOS 16.0, dyld caches are in a different image
if prefix == "ios" and version.parse(os_version) >= version.parse("16.0"):
plist_path = os.path.join(extract_dir, "BuildManifest.plist")
(system_restore_image_filename, os_version, build_number) = read_build_manifest_plist(
plist_path
)

os_version, build_number = read_system_version_plist(extract_dir)
logging.info(f"Found image for {os_version} ({build_number}) in {extract_dir}")
parsed_version = version.parse(os_version)

# Starting iOS 16.0 and macOS 13.0, dyld caches are in a different image
if (
prefix == "macos"
and parsed_version >= version.parse("13.0")
or prefix == "ios"
and parsed_version >= version.parse("16.0")
):
system_restore_image_filename = read_build_manifest_plist(extract_dir)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this here yields a single value, whereas the other branch yields an iterator. why exactly is that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Restore.plist contains 2 possible restore images, one for a base system and one seemingly being the real system. We were extracting from the base system so far which is why our symbols were incomplete. I'm returning both images here and will loop through both to extract symbols.

As for the BuildManifest.plist, we only found the Cryptex1,SystemOS image being useful to access the dyld we want, so that's why it's returning only one value. Maybe in the future we'll need/want to support multiple images.

with span.start_children(op="task", description="Process one dmg"):
process_one_dmg(
extract_dir,
symcache_output_path,
prefix,
architecture,
system_restore_image_filename,
os_version,
build_number,
)
else:
for system_restore_image_filename in read_restore_plist(extract_dir):
with span.start_children(op="task", description="Process one dmg"):
process_one_dmg(
extract_dir,
symcache_output_path,
prefix,
architecture,
system_restore_image_filename,
os_version,
build_number,
)


def process_one_dmg(
extract_dir,
symcache_output_path,
prefix,
architecture,
system_restore_image_filename,
os_version,
build_number,
):
restore_image_path = os.path.join(extract_dir, system_restore_image_filename)
span = sentry_sdk.Hub.current.scope.span

logging.info(f"Mounting {restore_image_path}")
with span.start_child(op="task", description="Mount archive"):
Expand Down Expand Up @@ -428,28 +465,22 @@ def extract_zip_archive(archive_path: str, extract_dir: str) -> None:
)


def read_build_manifest_plist(plist_path: str):
with open(plist_path, "rb") as f:
def read_system_version_plist(extract_dir: str) -> Tuple[str, str]:
with open(os.path.join(extract_dir, "SystemVersion.plist"), "rb") as f:
plist = plistlib.load(f)
restore_image = plist["BuildIdentities"][0]["Manifest"]["Cryptex1,SystemOS"]["Info"]["Path"]
build_number = plist["ProductBuildVersion"]
os_version = plist["ProductVersion"]
logging.info(
f"Found image for {os_version} ({build_number}) in {os.path.dirname(plist_path)}"
)
return restore_image, os_version, build_number
return plist["ProductVersion"], plist["ProductBuildVersion"]


def read_restore_plist(plist_path: str):
with open(plist_path, "rb") as f:
def read_build_manifest_plist(extract_dir: str) -> str:
with open(os.path.join(extract_dir, "BuildManifest.plist"), "rb") as f:
plist = plistlib.load(f)
restore_image = list(plist["SystemRestoreImageFileSystems"].keys())[0]
build_number = plist["ProductBuildVersion"]
os_version = plist["ProductVersion"]
logging.info(
f"Found image for {os_version} ({build_number}) in {os.path.dirname(plist_path)}"
)
return restore_image, os_version, build_number
return plist["BuildIdentities"][0]["Manifest"]["Cryptex1,SystemOS"]["Info"]["Path"]


def read_restore_plist(extract_dir: str) -> List[str]:
with open(os.path.join(extract_dir, "Restore.plist"), "rb") as f:
plist = plistlib.load(f)
return list(plist["SystemRestoreImageFileSystems"].keys())


def upload_to_gcs(symcache_dir: str):
Expand Down