feat: iOS support

This commit is contained in:
zx
2024-09-03 20:36:45 -04:00
parent 4f51f54879
commit ce42bdff76
14 changed files with 23 additions and 13 deletions

View File

@@ -4,11 +4,6 @@ rewriting [pyzule](https://github.com/asdfzxcvbn/pyzule), but actually good this
this is pretty much just a hobby project that i'll work on when i'm bored. pyzule in its current state is kinda ugly, but it works and i haven't really had the motivation to work on it. there really isn't any need for improvements, anyway.. this is pretty much just a hobby project that i'll work on when i'm bored. pyzule in its current state is kinda ugly, but it works and i haven't really had the motivation to work on it. there really isn't any need for improvements, anyway..
`cyan` will target python v3.12 (finally!), be pep8-compliant (hopefully..), and be type-hinted! `cyan` will ~~target python v3.12 (finally!)~~, be pep8-compliant (hopefully..), and be type-hinted!
## plan
- have a __main__ file ofc, this is what `cyan` command runs
- also have a cyan file, it should have the main logic of the program
- have other files for a class of the ipa/app, main executable, etc

View File

@@ -8,7 +8,7 @@ class AppBundle:
self.plist = get_plist(plist_path) self.plist = get_plist(plist_path)
self.executable = Executable( self.executable = Executable(
f"{path}/{self.plist["CFBundleExecutable"]}", f"{path}/{self.plist['CFBundleExecutable']}",
path path
) )

View File

View File

@@ -27,13 +27,17 @@ class Executable:
self.bn = os.path.basename(path) self.bn = os.path.basename(path)
self.inj: Optional[lief.MachO.Binary] = None self.inj: Optional[lief.MachO.Binary] = None
if self.specific.endswith("iOS"):
self.inj_func = self.ios_inject
else:
self.inj_func = self.insert_cmd
def is_encrypted(self) -> bool: def is_encrypted(self) -> bool:
proc = subprocess.run( proc = subprocess.run(
[self.otool, "-l", self.path], [self.otool, "-l", self.path],
capture_output=True capture_output=True
) )
# print(proc.stdout)
return b"cryptid 1" in proc.stdout return b"cryptid 1" in proc.stdout
def inject(self, tweaks: dict[str, str], tmpdir: str) -> None: def inject(self, tweaks: dict[str, str], tmpdir: str) -> None:
@@ -155,12 +159,12 @@ class Executable:
elif bn.endswith(".dylib"): elif bn.endswith(".dylib"):
fpath = f"{FRAMEWORKS_DIR}/{bn}" fpath = f"{FRAMEWORKS_DIR}/{bn}"
existed = tbhutils.delete_if_exists(fpath, bn) existed = tbhutils.delete_if_exists(fpath, bn)
self.insert_cmd(f"@rpath/{bn}") self.inj_func(f"@rpath/{bn}")
shutil.copy2(path, FRAMEWORKS_DIR) shutil.copy2(path, FRAMEWORKS_DIR)
elif bn.endswith(".framework"): elif bn.endswith(".framework"):
fpath = f"{FRAMEWORKS_DIR}/{bn}" fpath = f"{FRAMEWORKS_DIR}/{bn}"
existed = tbhutils.delete_if_exists(fpath, bn) existed = tbhutils.delete_if_exists(fpath, bn)
self.insert_cmd(f"@rpath/{bn}/{bn[:-10]}") self.inj_func(f"@rpath/{bn}/{bn[:-10]}")
shutil.copytree(path, fpath) shutil.copytree(path, fpath)
else: else:
fpath = f"{self.bundle_path}/{bn}" fpath = f"{self.bundle_path}/{bn}"
@@ -193,10 +197,20 @@ class Executable:
def insert_cmd(self, cmd: str) -> None: def insert_cmd(self, cmd: str) -> None:
if self.inj is None: if self.inj is None:
lief.logging.disable()
self.inj = lief.parse(self.path) # type: ignore self.inj = lief.parse(self.path) # type: ignore
self.inj.add(lief.MachO.DylibCommand.weak_lib(cmd)) # type: ignore self.inj.add(lief.MachO.DylibCommand.weak_lib(cmd)) # type: ignore
def ios_inject(self, cmd: str) -> None:
subprocess.run(
[
f"{self.specific}/insert_dylib",
"--weak", "--inplace", "--no-strip-codesig", "--all-yes",
cmd, self.path
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
def get_dependencies(self) -> list[str]: def get_dependencies(self) -> list[str]:
proc = subprocess.run( proc = subprocess.run(
[self.otool, "-L", self.path], [self.otool, "-L", self.path],

View File

@@ -88,7 +88,7 @@ def get_tools_dir() -> tuple[str, str]:
system = platform.system() system = platform.system()
if "iPhone" in mach or "iPad" in mach: if "iPhone" in mach or "iPad" in mach:
mach = "arm64" mach = "iOS"
with resources.files() as files: # type: ignore with resources.files() as files: # type: ignore
return ( return (

Binary file not shown.

0
cyan/tools/Darwin/arm64/install_name_tool Normal file → Executable file
View File

0
cyan/tools/Darwin/arm64/ldid Normal file → Executable file
View File

0
cyan/tools/Darwin/arm64/otool Normal file → Executable file
View File

1
cyan/tools/Darwin/iOS Symbolic link
View File

@@ -0,0 +1 @@
arm64

0
cyan/tools/Darwin/x86_64/install_name_tool Normal file → Executable file
View File

0
cyan/tools/Darwin/x86_64/ldid Normal file → Executable file
View File

0
cyan/tools/Darwin/x86_64/otool Normal file → Executable file
View File

View File

@@ -7,8 +7,8 @@ setup(
author="zx", author="zx",
author_email="hi@zxcvbn.fyi", author_email="hi@zxcvbn.fyi",
packages=["cyan", "cyan.tbhtypes"], packages=["cyan", "cyan.tbhtypes"],
install_requires=["lief"], # install_requires=["lief"],
python_requires=">=3.12", python_requires=">=3.9",
include_package_data=True, include_package_data=True,
entry_points={ entry_points={
"console_scripts": ["cyan=cyan.__main__:main"], "console_scripts": ["cyan=cyan.__main__:main"],