feat: thinning

This commit is contained in:
zx
2024-09-06 16:57:50 -04:00
parent bacc28e9c7
commit 17da3e897c
6 changed files with 72 additions and 26 deletions

View File

@@ -43,6 +43,10 @@ def main() -> None:
"-s", "--fakesign", action="store_true",
help="fakesign all binaries for use with appsync/trollstore"
)
parser.add_argument(
"-q", "--thin", action="store_true",
help="thin all binaries to arm64, may largely reduce size"
)
parser.add_argument(
"-c", "--compress", metavar="level", type=int, default=6,
@@ -53,6 +57,10 @@ def main() -> None:
"--ignore-encrypted", action="store_true",
help="skip main binary encryption check"
)
parser.add_argument(
"--overwrite", action="store_true",
help="overwrite existing files without confirming"
)
parser.add_argument(
"-v", "--version", action="version", version="cyan v1.0b"

View File

@@ -49,6 +49,8 @@ def main(parser: ArgumentParser) -> None:
app.plist.enable_documents()
if args.fakesign:
app.fakesign_all()
if args.thin:
app.thin_all()
# create subdirectories if necessary
if "/" in args.o:
@@ -56,7 +58,7 @@ def main(parser: ArgumentParser) -> None:
# done !
if OUTPUT_IS_IPA:
print("[*] generating ipa..")
print(f"[*] generating ipa with compression level {args.compress}..")
tbhutils.make_ipa(tmpdir, args.o, args.compress)
print(f"[*] generated ipa at {args.o}")
else:

View File

@@ -1,6 +1,7 @@
import os
import shutil
from glob import glob
from typing import Optional
from .executable import Executable
from .plist import Plist
@@ -15,6 +16,8 @@ class AppBundle:
path
)
self.cached_executables: Optional[list[str]] = None
def remove(self, name: str) -> bool:
path = f"{self.path}/{name}"
if not os.path.exists(path):
@@ -38,20 +41,38 @@ class AppBundle:
else:
print("[?] watch app not present")
def fakesign_all(self) -> None:
self.executable.fakesign()
count = 1
for ts in sum((
def get_executables(self) -> list[str]:
return sum((
glob(f"{self.path}/**/*.dylib", recursive=True),
glob(f"{self.path}/**/*.appex", recursive=True),
glob(f"{self.path}/**/*.framework", recursive=True)
), []): # type: ignore
), []) # type: ignore
def mass_operate(self, op: str, func: str) -> None:
# this works since we call this after injecting
if self.cached_executables is None:
self.cached_executables = self.get_executables()
if getattr(self.executable, func)():
count = 1
else:
count = 0
for ts in self.cached_executables:
if ts.endswith(".dylib"):
call = getattr(Executable(ts), func)()
else:
pl = Plist(f"{ts}/Info.plist")
Executable(f"{ts}/{pl['CFBundleExecutable']}").fakesign()
call = getattr(Executable(f"{ts}/{pl['CFBundleExecutable']}"), func)()
if call:
count += 1
for ts in glob(f"{self.path}/**/*.dylib", recursive=True):
Executable(ts).fakesign()
count += 1
print(f"[*] {op} \033[96m{count}\033[0m item(s)")
def fakesign_all(self) -> None:
self.mass_operate("fakesigned", "fakesign")
def thin_all(self) -> None:
self.mass_operate("thinned", "thin")
print(f"[*] fakesigned \033[96m{count}\033[0m items")

View File

@@ -16,6 +16,7 @@ class Executable:
install_dir, specific = tbhutils.get_tools_dir()
nt = f"{specific}/install_name_tool"
ldid = f"{specific}/ldid"
lipo = f"{specific}/lipo"
otool = f"{specific}/otool"
starters = ("\t/Library/", "\t@rpath", "\t@executable_path")
@@ -183,12 +184,22 @@ class Executable:
subprocess.run(["ldid", f"-S{ENT_PATH}", self.path])
print("[*] restored entitlements")
def fakesign(self, keep_entitlements: bool = True) -> None:
def fakesign(self, keep_entitlements: bool = True) -> bool:
cmd = [self.ldid, "-S"]
if keep_entitlements:
cmd.append("-M")
subprocess.run(cmd + [self.path])
return True
def thin(self) -> bool:
if subprocess.run(
[self.lipo, "-thin", "arm64", self.path, "-output", self.path],
stderr=subprocess.DEVNULL
).returncode == 0:
return True
return False
def change_dependency(self, old: str, new: str) -> None:
subprocess.run([self.nt, "-change", old, new, self.path])

View File

@@ -54,3 +54,4 @@ class Plist:
print("[*] enabled documents support")
else:
print("[?] documents support was already enabled")

View File

@@ -22,6 +22,9 @@ def validate_inputs(args: Namespace) -> Optional[str]:
return f"{args.i} does not exist"
if os.path.exists(args.o):
if args.overwrite:
print(f"[*] {args.o} already exists; overwriting")
else:
try:
overwrite = input(
f"[<] {args.o} already exists, overwrite it? [Y/n] "