mirror of
https://github.com/NohamR/pyzule-rw.git
synced 2026-10-11 02:49:40 +00:00
feat: thinning
This commit is contained in:
@@ -43,6 +43,10 @@ def main() -> None:
|
|||||||
"-s", "--fakesign", action="store_true",
|
"-s", "--fakesign", action="store_true",
|
||||||
help="fakesign all binaries for use with appsync/trollstore"
|
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(
|
parser.add_argument(
|
||||||
"-c", "--compress", metavar="level", type=int, default=6,
|
"-c", "--compress", metavar="level", type=int, default=6,
|
||||||
@@ -53,6 +57,10 @@ def main() -> None:
|
|||||||
"--ignore-encrypted", action="store_true",
|
"--ignore-encrypted", action="store_true",
|
||||||
help="skip main binary encryption check"
|
help="skip main binary encryption check"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--overwrite", action="store_true",
|
||||||
|
help="overwrite existing files without confirming"
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-v", "--version", action="version", version="cyan v1.0b"
|
"-v", "--version", action="version", version="cyan v1.0b"
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ def main(parser: ArgumentParser) -> None:
|
|||||||
app.plist.enable_documents()
|
app.plist.enable_documents()
|
||||||
if args.fakesign:
|
if args.fakesign:
|
||||||
app.fakesign_all()
|
app.fakesign_all()
|
||||||
|
if args.thin:
|
||||||
|
app.thin_all()
|
||||||
|
|
||||||
# create subdirectories if necessary
|
# create subdirectories if necessary
|
||||||
if "/" in args.o:
|
if "/" in args.o:
|
||||||
@@ -56,7 +58,7 @@ def main(parser: ArgumentParser) -> None:
|
|||||||
|
|
||||||
# done !
|
# done !
|
||||||
if OUTPUT_IS_IPA:
|
if OUTPUT_IS_IPA:
|
||||||
print("[*] generating ipa..")
|
print(f"[*] generating ipa with compression level {args.compress}..")
|
||||||
tbhutils.make_ipa(tmpdir, args.o, args.compress)
|
tbhutils.make_ipa(tmpdir, args.o, args.compress)
|
||||||
print(f"[*] generated ipa at {args.o}")
|
print(f"[*] generated ipa at {args.o}")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from .executable import Executable
|
from .executable import Executable
|
||||||
from .plist import Plist
|
from .plist import Plist
|
||||||
@@ -15,6 +16,8 @@ class AppBundle:
|
|||||||
path
|
path
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.cached_executables: Optional[list[str]] = None
|
||||||
|
|
||||||
def remove(self, name: str) -> bool:
|
def remove(self, name: str) -> bool:
|
||||||
path = f"{self.path}/{name}"
|
path = f"{self.path}/{name}"
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
@@ -38,20 +41,38 @@ class AppBundle:
|
|||||||
else:
|
else:
|
||||||
print("[?] watch app not present")
|
print("[?] watch app not present")
|
||||||
|
|
||||||
def fakesign_all(self) -> None:
|
def get_executables(self) -> list[str]:
|
||||||
self.executable.fakesign()
|
return sum((
|
||||||
count = 1
|
glob(f"{self.path}/**/*.dylib", recursive=True),
|
||||||
|
|
||||||
for ts in sum((
|
|
||||||
glob(f"{self.path}/**/*.appex", recursive=True),
|
glob(f"{self.path}/**/*.appex", recursive=True),
|
||||||
glob(f"{self.path}/**/*.framework", recursive=True)
|
glob(f"{self.path}/**/*.framework", recursive=True)
|
||||||
), []): # type: ignore
|
), []) # type: ignore
|
||||||
pl = Plist(f"{ts}/Info.plist")
|
|
||||||
Executable(f"{ts}/{pl['CFBundleExecutable']}").fakesign()
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
for ts in glob(f"{self.path}/**/*.dylib", recursive=True):
|
def mass_operate(self, op: str, func: str) -> None:
|
||||||
Executable(ts).fakesign()
|
# this works since we call this after injecting
|
||||||
count += 1
|
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")
|
||||||
|
call = getattr(Executable(f"{ts}/{pl['CFBundleExecutable']}"), func)()
|
||||||
|
|
||||||
|
if call:
|
||||||
|
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")
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class Executable:
|
|||||||
install_dir, specific = tbhutils.get_tools_dir()
|
install_dir, specific = tbhutils.get_tools_dir()
|
||||||
nt = f"{specific}/install_name_tool"
|
nt = f"{specific}/install_name_tool"
|
||||||
ldid = f"{specific}/ldid"
|
ldid = f"{specific}/ldid"
|
||||||
|
lipo = f"{specific}/lipo"
|
||||||
otool = f"{specific}/otool"
|
otool = f"{specific}/otool"
|
||||||
|
|
||||||
starters = ("\t/Library/", "\t@rpath", "\t@executable_path")
|
starters = ("\t/Library/", "\t@rpath", "\t@executable_path")
|
||||||
@@ -183,12 +184,22 @@ class Executable:
|
|||||||
subprocess.run(["ldid", f"-S{ENT_PATH}", self.path])
|
subprocess.run(["ldid", f"-S{ENT_PATH}", self.path])
|
||||||
print("[*] restored entitlements")
|
print("[*] restored entitlements")
|
||||||
|
|
||||||
def fakesign(self, keep_entitlements: bool = True) -> None:
|
def fakesign(self, keep_entitlements: bool = True) -> bool:
|
||||||
cmd = [self.ldid, "-S"]
|
cmd = [self.ldid, "-S"]
|
||||||
if keep_entitlements:
|
if keep_entitlements:
|
||||||
cmd.append("-M")
|
cmd.append("-M")
|
||||||
|
|
||||||
subprocess.run(cmd + [self.path])
|
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:
|
def change_dependency(self, old: str, new: str) -> None:
|
||||||
subprocess.run([self.nt, "-change", old, new, self.path])
|
subprocess.run([self.nt, "-change", old, new, self.path])
|
||||||
|
|||||||
@@ -54,3 +54,4 @@ class Plist:
|
|||||||
print("[*] enabled documents support")
|
print("[*] enabled documents support")
|
||||||
else:
|
else:
|
||||||
print("[?] documents support was already enabled")
|
print("[?] documents support was already enabled")
|
||||||
|
|
||||||
|
|||||||
@@ -22,18 +22,21 @@ def validate_inputs(args: Namespace) -> Optional[str]:
|
|||||||
return f"{args.i} does not exist"
|
return f"{args.i} does not exist"
|
||||||
|
|
||||||
if os.path.exists(args.o):
|
if os.path.exists(args.o):
|
||||||
try:
|
if args.overwrite:
|
||||||
overwrite = input(
|
print(f"[*] {args.o} already exists; overwriting")
|
||||||
f"[<] {args.o} already exists, overwrite it? [Y/n] "
|
else:
|
||||||
if args.output is not None
|
try:
|
||||||
else "[<] no output was specified. overwrite the input? [Y/n] "
|
overwrite = input(
|
||||||
).strip().lower()
|
f"[<] {args.o} already exists, overwrite it? [Y/n] "
|
||||||
except KeyboardInterrupt:
|
if args.output is not None
|
||||||
sys.exit("[>] bye!")
|
else "[<] no output was specified. overwrite the input? [Y/n] "
|
||||||
|
).strip().lower()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit("[>] bye!")
|
||||||
|
|
||||||
if overwrite not in ("y", "yes", ""):
|
if overwrite not in ("y", "yes", ""):
|
||||||
print("[>] quitting.")
|
print("[>] quitting.")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if args.f is not None:
|
if args.f is not None:
|
||||||
# dictionary ensures unique names
|
# dictionary ensures unique names
|
||||||
|
|||||||
Reference in New Issue
Block a user