feat: change app icons

This commit is contained in:
zx
2024-09-08 19:29:59 -04:00
parent 30fa189197
commit 1e9607d9e1
6 changed files with 59 additions and 1 deletions

View File

@@ -16,6 +16,7 @@ more coming soon! i'm trying to copy pyzule in order to deprecate it in favor of
- change app name, version, bundle id, and minimum os version - change app name, version, bundle id, and minimum os version
- remove UISupportedDevices - remove UISupportedDevices
- remove watch app - remove watch app
- change the app icon
- fakesign the output ipa/app - fakesign the output ipa/app
- thin all binaries to arm64, it can LARGELY reduce app size sometimes! - thin all binaries to arm64, it can LARGELY reduce app size sometimes!
- remove all app extensions (or just encrypted ones!) - remove all app extensions (or just encrypted ones!)
@@ -30,6 +31,8 @@ also obviously install python, version 3.9 or greater is required (the version a
**if you want to inject dylibs AND ARE NOT ON iOS,** make sure you install lief (you only have to do this once): `pip install -U lief` **if you want to inject dylibs AND ARE NOT ON iOS,** make sure you install lief (you only have to do this once): `pip install -U lief`
**if you want to change app icons (iOS NOT supported),** also make sure you install pillow: `pip install Pillow`
then finally, to install or update cyan, just `pip install --force-reinstall git+https://github.com/asdfzxcvbn/pyzule-rw.git#egg=cyan` then finally, to install or update cyan, just `pip install --force-reinstall git+https://github.com/asdfzxcvbn/pyzule-rw.git#egg=cyan`
## todo ## todo
@@ -46,7 +49,7 @@ then finally, to install or update cyan, just `pip install --force-reinstall git
[x] feat: plugin operations (-q, -e) [x] feat: plugin operations (-q, -e)
[] feat: change app icon [x] feat: change app icon
[] feat: .cyan files (lol rip .pyzule files) [] feat: .cyan files (lol rip .pyzule files)

View File

@@ -42,6 +42,10 @@ def main() -> None:
"-m", metavar="minimum", "-m", metavar="minimum",
help="modify the app's minimum OS version" help="modify the app's minimum OS version"
) )
parser.add_argument(
"-k", metavar="icon",
help="modify the app's icon"
)
parser.add_argument( parser.add_argument(
"-u", "--remove-supported-devices", action="store_true", "-u", "--remove-supported-devices", action="store_true",

View File

@@ -55,6 +55,8 @@ def main(parser: ArgumentParser) -> None:
app.plist.change_bundle_id(args.b) app.plist.change_bundle_id(args.b)
if args.m is not None: if args.m is not None:
app.plist.change_minimum_version(args.m) app.plist.change_minimum_version(args.m)
if args.k is not None:
app.change_icon(args.k, tmpdir)
if args.remove_supported_devices: if args.remove_supported_devices:
app.plist.remove_uisd() app.plist.remove_uisd()

View File

@@ -1,6 +1,7 @@
import os import os
import shutil import shutil
from glob import glob from glob import glob
from uuid import uuid4
from typing import Optional, Literal from typing import Optional, Literal
from .executable import Executable from .executable import Executable
@@ -101,3 +102,45 @@ class AppBundle:
else: else:
print("[*] removed encrypted plugins:", ", ".join(removed)) print("[*] removed encrypted plugins:", ", ".join(removed))
def change_icon(self, path: str, tmpdir: str) -> None:
try:
from PIL import Image
except Exception:
return print("[?] pillow is not installed, -k is not available")
tmpath = f"{tmpdir}/icon.png"
if not path.endswith(".png"):
with Image.open(path) as img:
img.save(tmpath, "PNG")
else:
shutil.copyfile(path, tmpath)
uid = f"cyan_{uuid4().hex[:7]}a" # can't have it end with a num
i60 = f"{uid}60x60"
i76 = f"{uid}76x76"
with Image.open(tmpath) as img:
img.resize((120, 120)).save(f"{self.path}/{i60}@2x.png", "PNG")
img.resize((152, 152)).save(f"{self.path}/{i76}@2x~ipad.png", "PNG")
if "CFBundleIcons" not in self.plist:
self.plist["CFBundleIcons"] = {}
if "CFBundleIcons~ipad" not in self.plist:
self.plist["CFBundleIcons~ipad"] = {}
self.plist["CFBundleIcons"] = self.plist["CFBundleIcons"] | {
"CFBundlePrimaryIcon": {
"CFBundleIconFiles": [i60],
"CFBundleIconName": uid
}
}
self.plist["CFBundleIcons~ipad"] = self.plist["CFBundleIcons~ipad"] | {
"CFBundlePrimaryIcon": {
"CFBundleIconFiles": [i60, i76],
"CFBundleIconName": uid
}
}
self.plist.save()
print("[*] updated app icon")

View File

@@ -25,6 +25,9 @@ class Plist:
def __setitem__(self, key: str, val: Any) -> None: def __setitem__(self, key: str, val: Any) -> None:
self.data[key] = val self.data[key] = val
def __contains__(self, key: str) -> bool:
return key in self.data
def save(self) -> None: def save(self) -> None:
with open(self.path, "wb") as f: with open(self.path, "wb") as f:
plistlib.dump(self.data, f) plistlib.dump(self.data, f)

View File

@@ -54,6 +54,9 @@ def validate_inputs(args: Namespace) -> Optional[str]:
): ):
sys.exit(f"[!] invalid OS version: {args.m}") sys.exit(f"[!] invalid OS version: {args.m}")
if args.k is not None and not os.path.isfile(args.k):
sys.exit(f"[!] {args.k} does not exist")
def get_app(path: str, tmpdir: str, is_ipa: bool) -> str: def get_app(path: str, tmpdir: str, is_ipa: bool) -> str:
payload = f"{tmpdir}/Payload" payload = f"{tmpdir}/Payload"