mirror of
https://git-qiuchenly.yltfspace.com/QiuChenly/corepatch
synced 2025-11-25 02:24:56 +08:00
Compare commits
2 Commits
210590e6a0
...
cd73d6a641
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd73d6a641 | ||
|
|
16f5e7ef3c |
476
ori.py
476
ori.py
@@ -1,476 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
import plistlib
|
||||
import subprocess
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
import time
|
||||
|
||||
|
||||
def read_input(prompt):
|
||||
return input(prompt).strip().lower()
|
||||
|
||||
def search_apps(app_list, install_apps, keyword):
|
||||
keyword = keyword.lower()
|
||||
installed_apps = {app['CFBundleIdentifier']: app['CFBundleName'].lower() for app in install_apps}
|
||||
def is_match(pn):
|
||||
return keyword in (pn.lower() if isinstance(pn, str) else any(keyword in p.lower() for p in pn))
|
||||
matched_apps = []
|
||||
for app in app_list:
|
||||
pn_list = app.get("packageName")
|
||||
if isinstance(pn_list, list):
|
||||
matched = [pn for pn in pn_list if is_match(pn) and any(pid == pn and keyword in name for pid, name in installed_apps.items())]
|
||||
matched_apps.extend({**app, "packageName": pn} for pn in matched)
|
||||
elif pn_list and is_match(pn_list):
|
||||
matched_apps.append({**app, "packageName": pn_list})
|
||||
return matched_apps
|
||||
|
||||
def parse_app_info(app_base_locate, app_info_file):
|
||||
with open(app_info_file, "rb") as f:
|
||||
app_info = plistlib.load(f)
|
||||
app_info = {
|
||||
"appBaseLocate": app_base_locate,
|
||||
"CFBundleIdentifier": app_info.get("CFBundleIdentifier"),
|
||||
"CFBundleVersion": app_info.get("CFBundleVersion", ""),
|
||||
"CFBundleShortVersionString": app_info.get("CFBundleShortVersionString", ""),
|
||||
"CFBundleName": app_info.get("CFBundleExecutable", ""),
|
||||
"CFBundleExecutable": app_info.get("CFBundleExecutable", ""),
|
||||
}
|
||||
return app_info
|
||||
|
||||
|
||||
def scan_apps():
|
||||
appList = []
|
||||
base_dirs = ["/Applications", "/Applications/Setapp"]
|
||||
|
||||
for base_dir in base_dirs:
|
||||
if not os.path.exists(base_dir):
|
||||
continue
|
||||
lst = os.listdir(base_dir)
|
||||
for app in lst:
|
||||
app_info_file = os.path.join(base_dir, app, "Contents", "Info.plist")
|
||||
if not os.path.exists(app_info_file):
|
||||
continue
|
||||
try:
|
||||
appList.append(parse_app_info(base_dir + "/" + app, app_info_file))
|
||||
# print("检查本地App:", app_info_file)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
return appList
|
||||
|
||||
|
||||
def check_compatible(compatible_version_code, compatible_version_subcode, app_version_code, app_subversion_code):
|
||||
if compatible_version_code is None and compatible_version_subcode is None:
|
||||
return True
|
||||
|
||||
if compatible_version_code:
|
||||
for code in compatible_version_code:
|
||||
if app_version_code == code:
|
||||
return True
|
||||
|
||||
if compatible_version_subcode:
|
||||
for code in compatible_version_subcode:
|
||||
if app_subversion_code == code:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def handle_keygen(bundleIdentifier):
|
||||
# 取出用户名
|
||||
username = os.path.expanduser("~").split("/")[-1]
|
||||
subprocess.run("chmod +x ./tool/KeygenStarter", shell=True)
|
||||
subprocess.run(f"./tool/KeygenStarter '{bundleIdentifier}' '{username}'", shell=True)
|
||||
|
||||
def handle_helper(app_base, target_helper, component_apps, SMExtra, bridge_path, useOptool,helperNoInject,dylibSelect):
|
||||
"""增强Helper
|
||||
|
||||
Args:
|
||||
app_base (dict): app信息
|
||||
target_helper (string): helper文件路径
|
||||
"""
|
||||
subprocess.run("chmod +x ./tool/GenShineImpactStarter", shell=True)
|
||||
subprocess.run(f"./tool/GenShineImpactStarter '{target_helper}' {'' if SMExtra is None else SMExtra}", shell=True)
|
||||
if useOptool:
|
||||
sh = f"./tool/optool install -p '{bridge_path}{dylibSelect}' -t '{target_helper}'"
|
||||
else:
|
||||
sh = f"./tool/insert_dylib '{bridge_path}{dylibSelect}' '{target_helper}' '{target_helper}'"
|
||||
|
||||
if helperNoInject:
|
||||
pass
|
||||
else:
|
||||
subprocess.run(sh, shell=True)
|
||||
helper_name = target_helper.split("/")[-1]
|
||||
|
||||
# 检查是否存在
|
||||
target = f"/Library/LaunchDaemons/{helper_name}.plist"
|
||||
if os.path.exists(target):
|
||||
subprocess.run(f"sudo /bin/launchctl unload {target}", shell=True)
|
||||
subprocess.run(f"sudo /usr/bin/killall -u root -9 {helper_name}", shell=True)
|
||||
subprocess.run(f"sudo /bin/rm {target}", shell=True)
|
||||
subprocess.run(f"sudo /bin/rm /Library/PrivilegedHelperTools/{helper_name}", shell=True)
|
||||
subprocess.run(f"sudo xattr -c '{app_base}'", shell=True)
|
||||
|
||||
src_info = [f"{app_base}/Contents/Info.plist"]
|
||||
if isinstance(component_apps, list):
|
||||
src_info.extend([f"{app_base}{i}/Contents/Info.plist" for i in component_apps])
|
||||
|
||||
for i in src_info:
|
||||
command = ["/usr/libexec/PlistBuddy", "-c", f"Set :SMPrivilegedExecutables:{helper_name} 'identifier \\\"{helper_name}\\\"'", i]
|
||||
subprocess.run(command, text=True)
|
||||
subprocess.run(f'/usr/bin/codesign -f -s - --all-architectures --deep "{target_helper}"', shell=True)
|
||||
subprocess.run(f'/usr/bin/codesign -f -s - --all-architectures --deep "{app_base}"', shell=True)
|
||||
|
||||
|
||||
def getAppMainExecutable(app_base):
|
||||
# 读取Contents/Info.plist中的CFBundleExecutable
|
||||
with open(f"{app_base}/Contents/Info.plist", "rb") as f:
|
||||
app_info = plistlib.load(f)
|
||||
return app_info["CFBundleExecutable"]
|
||||
|
||||
|
||||
# 获取BundleID
|
||||
def getBundleID(app_base):
|
||||
with open(f"{app_base}/Contents/Info.plist", "rb") as f:
|
||||
app_info = plistlib.load(f)
|
||||
return app_info["CFBundleIdentifier"]
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
with open("config.json", "r") as f:
|
||||
config = json.load(f)
|
||||
|
||||
base_public_config = config["basePublicConfig"]
|
||||
app_list = config["AppList"]
|
||||
proc_version = config["Version"]
|
||||
|
||||
print()
|
||||
print(" ██████╗ ██╗██╗ ██╗ ██████╗██╗ ██╗███████╗███╗ ██╗██╗ ██╗ ██╗ ")
|
||||
print(" ██╔═══██╗██║██║ ██║██╔════╝██║ ██║██╔════╝████╗ ██║██║ ╚██╗ ██╔╝ ")
|
||||
print(" ██║ ██║██║██║ ██║██║ ███████║█████╗ ██╔██╗ ██║██║ ╚████╔╝ ")
|
||||
print(" ██║▄▄ ██║██║██║ ██║██║ ██╔══██║██╔══╝ ██║╚██╗██║██║ ╚██╔╝ ")
|
||||
print(" ╚██████╔╝██║╚██████╔╝╚██████╗██║ ██║███████╗██║ ╚████║███████╗██║ ")
|
||||
print(" ╚══▀▀═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝╚══════╝╚═╝ ")
|
||||
print()
|
||||
print("Original Design By QiuChenly(github.com/qiuchenly), Py ver. by X1a0He")
|
||||
print(f"自动注入版本号: {proc_version}")
|
||||
print("注入时请根据提示输入'y' 或者按下回车键跳过这一项。")
|
||||
|
||||
# QiuChenlyTeam 特殊变量
|
||||
isDevHome = False #os.getenv("InjectLibDev")
|
||||
|
||||
# start_time = time.time()
|
||||
install_apps = scan_apps()
|
||||
# end_time = time.time()
|
||||
# elapsed_time = end_time - start_time
|
||||
# print("扫描本地App耗时: {:.2f}s".format(elapsed_time))
|
||||
app_Lst = []
|
||||
keyword = input("请输入应用名称或包名的关键字进行搜索,或直接按回车键遍历所有支持的应用: ").strip()
|
||||
|
||||
if keyword:
|
||||
matched_apps = search_apps(app_list, install_apps, keyword)
|
||||
if not matched_apps:
|
||||
print("未找到匹配的应用程序。")
|
||||
else:
|
||||
app_Lst = []
|
||||
selected = set()
|
||||
while len(selected) < len(matched_apps):
|
||||
print("找到以下匹配的应用程序:")
|
||||
for i, app in enumerate(matched_apps, 1):
|
||||
status = " ✅[已选中]" if i-1 in selected else ""
|
||||
print(f"{i}. {app.get('packageName')}{status}")
|
||||
if len(selected) == len(matched_apps):
|
||||
print("所有应用已选中,即将开始处理...")
|
||||
break
|
||||
choice = input("请输入要注入的应用程序编号,输入0退出,或按回车继续: ").strip()
|
||||
if choice == '0':
|
||||
print("已退出程序。")
|
||||
exit(0)
|
||||
elif choice.isdigit() and 0 < int(choice) <= len(matched_apps):
|
||||
index = int(choice) - 1
|
||||
if index not in selected:
|
||||
app_Lst.append(matched_apps[index])
|
||||
selected.add(index)
|
||||
if len(selected) == len(matched_apps): print("所有应用已选中,即将开始处理...")
|
||||
else: print(f"应用 {matched_apps[index].get('packageName')} 已经被选择,请选择其他应用。")
|
||||
elif choice == '':
|
||||
if not app_Lst: print("未选择任何应用,请至少选择一个应用。")
|
||||
else: break
|
||||
else: print("无效的输入,请重新选择。")
|
||||
else:
|
||||
app_Lst = [app.copy() | {"packageName": name} for app in app_list
|
||||
if not (app.get("forQiuChenly") and not os.path.exists("/Users/qiuchenly"))
|
||||
for name in (app["packageName"] if isinstance(app["packageName"], list) else [app["packageName"]])]
|
||||
|
||||
for app in app_Lst:
|
||||
package_name = app.get("packageName")
|
||||
app_base_locate = app.get("appBaseLocate")
|
||||
bridge_file = app.get("bridgeFile")
|
||||
inject_file = app.get("injectFile")
|
||||
support_version = app.get("supportVersion")
|
||||
support_subversion = app.get("supportSubVersion")
|
||||
extra_shell = app.get("extraShell")
|
||||
need_copy_to_app_dir = app.get("needCopyToAppDir")
|
||||
deep_sign_app = app.get("deepSignApp")
|
||||
disable_library_validate = app.get("disableLibraryValidate")
|
||||
entitlements = app.get("entitlements")
|
||||
no_sign_target = app.get("noSignTarget")
|
||||
no_deep = app.get("noDeep")
|
||||
tccutil = app.get("tccutil")
|
||||
auto_handle_setapp = app.get("autoHandleSetapp")
|
||||
auto_handle_helper = app.get("autoHandleHelper")
|
||||
helper_file = app.get("helperFile")
|
||||
componentApp = app.get("componentApp")
|
||||
onlysh = app.get("onlysh")
|
||||
SMExtra = app.get("SMExtra")
|
||||
keygen = app.get("keygen")
|
||||
useOptool = app.get("useOptool")
|
||||
helperNoInject = app.get("helperNoInject")
|
||||
# forceSignMainExecute
|
||||
forceSignMainExecute = app.get("forceSignMainExecute")
|
||||
dylibSelect = app.get("dylibSelect") # 选择注入的库
|
||||
|
||||
if dylibSelect is None:
|
||||
dylibSelect = "91QiuChenly.dylib"
|
||||
|
||||
local_app = [
|
||||
local_app
|
||||
for local_app in install_apps
|
||||
if local_app["CFBundleIdentifier"] == package_name
|
||||
]
|
||||
|
||||
if not local_app and (
|
||||
app_base_locate is None or not os.path.isdir(app_base_locate)
|
||||
):
|
||||
continue
|
||||
|
||||
if not local_app:
|
||||
# print("[🔔] 此App包不是常见类型结构,请注意当前App注入的路径是 {appBaseLocate}".format(appBaseLocate=app_base_locate))
|
||||
# print("读取的是 {appBaseLocate}/Contents/Info.plist".format(appBaseLocate=app_base_locate))
|
||||
local_app.append(
|
||||
parse_app_info(
|
||||
app_base_locate,
|
||||
os.path.join(app_base_locate, "Contents", "Info.plist"),
|
||||
)
|
||||
)
|
||||
|
||||
local_app = local_app[0]
|
||||
if app_base_locate is None:
|
||||
app_base_locate = local_app["appBaseLocate"]
|
||||
|
||||
if bridge_file is None:
|
||||
bridge_file = base_public_config.get("bridgeFile", bridge_file)
|
||||
|
||||
if auto_handle_setapp is not None:
|
||||
bridge_file = "/Contents/MacOS/"
|
||||
executableAppName = local_app["CFBundleExecutable"]
|
||||
inject_file = os.path.basename(app_base_locate + bridge_file + executableAppName)
|
||||
print(f"======== Setapp下一个App的处理结果如下 [{app_base_locate}] [{bridge_file}] [{inject_file}]")
|
||||
|
||||
if not check_compatible(support_version, support_subversion, local_app["CFBundleShortVersionString"], local_app["CFBundleVersion"],):
|
||||
print(f"[😅] [{local_app['CFBundleName']}] - [{local_app['CFBundleShortVersionString']}] - [{local_app['CFBundleIdentifier']}]不是受支持的版本,跳过注入😋。")
|
||||
continue
|
||||
|
||||
print(f"[🤔] [{local_app['CFBundleName']}] - [{local_app['CFBundleShortVersionString']}] 是受支持的版本,是否需要注入?y/n(默认n)")
|
||||
action = read_input("").strip().lower()
|
||||
if action != "y":
|
||||
continue
|
||||
|
||||
if onlysh:
|
||||
subprocess.run(f"sudo sh tool/{extra_shell}", shell=True)
|
||||
continue
|
||||
|
||||
# 检查是否为com.adobe开头
|
||||
# if local_app["CFBundleIdentifier"].startswith("com.adobe"):
|
||||
# subprocess.run(
|
||||
# "sudo chmod -R 777 /Applications/Utilities/Adobe Creative Cloud/Components/Apps/*",
|
||||
# shell=True,
|
||||
# )
|
||||
# # 检查是否存在/Applications/Utilities/Adobe Creative Cloud/Components/Apps/Apps1_0.js
|
||||
# if not os.path.exists(
|
||||
# "/Applications/Utilities/Adobe Creative Cloud/Components/Apps/Apps1_0.js"
|
||||
# ):
|
||||
# # 替换文件中的key:"getEntitlementStatus",value:function(e){为key:"getEntitlementStatus",value:function(e){return "Entitled Installed"
|
||||
# with open(
|
||||
# "/Applications/Utilities/Adobe Creative Cloud/Components/Apps/Apps1_0.js",
|
||||
# "r",
|
||||
# encoding="utf-8",
|
||||
# ) as f:
|
||||
# content = f.read()
|
||||
# # 判断是否写过了
|
||||
# if (
|
||||
# 'key:"getEntitlementStatus",value:function(e){return "Entitled Installed"'
|
||||
# not in content
|
||||
# ):
|
||||
# # sed -i "s#key:\"getEntitlementStatus\",value:function(e){#key:\"getEntitlementStatus\",value:function(e){return \"Entitled Installed\"#g" /Applications/Utilities/Adobe\ Creative\ Cloud/Components/Apps/Apps1_0.js
|
||||
# content = content.replace(
|
||||
# 'key:"getEntitlementStatus",value:function(e){',
|
||||
# 'key:"getEntitlementStatus",value:function(e){return "Entitled Installed";',
|
||||
# )
|
||||
# with open(
|
||||
# "/Applications/Utilities/Adobe Creative Cloud/Components/Apps/Apps1_0.js",
|
||||
# "w",
|
||||
# encoding="utf-8",
|
||||
# ) as f:
|
||||
# f.write(content)
|
||||
|
||||
print(f"开始注入App: {package_name}")
|
||||
|
||||
subprocess.run(["sudo", "chmod", "-R", "777", app_base_locate])
|
||||
subprocess.run(["sudo", "xattr", "-cr", app_base_locate])
|
||||
|
||||
subprocess.run(
|
||||
["sudo", "pkill", "-f", getAppMainExecutable(app_base_locate)]
|
||||
)
|
||||
|
||||
if keygen is not None:
|
||||
print("正在注册App...")
|
||||
handle_keygen(local_app["CFBundleIdentifier"])
|
||||
continue
|
||||
|
||||
# dest = os.path.join(app_base_locate, bridge_file, inject_file)
|
||||
dest = rf"{app_base_locate}{bridge_file}{inject_file}"
|
||||
backup = rf"{dest}_backup"
|
||||
|
||||
if os.path.exists(backup):
|
||||
print("备份的原始文件已经存在,需要直接用这个文件注入吗?y/n(默认y)")
|
||||
action = read_input("").strip().lower()
|
||||
if action == "n":
|
||||
os.remove(backup)
|
||||
subprocess.run(f"sudo cp '{dest}' '{backup}'", shell=True)
|
||||
else:
|
||||
subprocess.run(f"sudo cp '{dest}' '{backup}'", shell=True)
|
||||
|
||||
current = Path(__file__).resolve()
|
||||
|
||||
sh = f"chmod +x {current.parent}/tool/insert_dylib"
|
||||
sh = f"chmod +x {current.parent}/tool/optool"
|
||||
subprocess.run(sh, shell=True)
|
||||
|
||||
if useOptool:
|
||||
sh = f"sudo {current.parent}/tool/optool install -p '{current.parent}/tool/{dylibSelect}' -t '{dest}'"
|
||||
else:
|
||||
sh = f"sudo {current.parent}/tool/insert_dylib '{current.parent}/tool/{dylibSelect}' '{backup}' '{dest}'"
|
||||
|
||||
if need_copy_to_app_dir:
|
||||
source_dylib = f"{current.parent}/tool/{dylibSelect}"
|
||||
if isDevHome:
|
||||
# 开发者自己的prebuild库路径 直接在.zshrc设置环境变量这里就可以读取到。
|
||||
# export InjectLibDev="自己的路径/91QiuChenly.dylib"
|
||||
# 要设置全路径哦 并且不要用sudo python3 main.py 启动 否则读不到你的环境变量
|
||||
source_dylib = isDevHome
|
||||
destination_dylib = f"'{app_base_locate}{bridge_file}{dylibSelect}'"
|
||||
|
||||
command = "ln -f -s" if isDevHome else "cp"
|
||||
subprocess.run(
|
||||
f"{command} {source_dylib} {destination_dylib}",
|
||||
shell=True,
|
||||
)
|
||||
|
||||
# codesign
|
||||
subprocess.run(
|
||||
f"codesign -fs - --timestamp=none --all-architectures {destination_dylib}",
|
||||
shell=True,
|
||||
)
|
||||
|
||||
sh = []
|
||||
desireApp = [dest]
|
||||
if componentApp:
|
||||
desireApp.extend(
|
||||
[
|
||||
f"{app_base_locate}{i}/Contents/MacOS/{getAppMainExecutable(app_base_locate+i)}"
|
||||
for i in componentApp
|
||||
]
|
||||
)
|
||||
for it in desireApp:
|
||||
if useOptool:
|
||||
bsh = rf"sudo {current.parent}/tool/optool install -p {destination_dylib} -t '{it}'"
|
||||
else:
|
||||
bsh = rf"sudo {current.parent}/tool/insert_dylib {destination_dylib} '{backup}' '{it}'"
|
||||
sh.append(bsh)
|
||||
|
||||
if isinstance(sh, list):
|
||||
[subprocess.run(command, shell=True) for command in sh]
|
||||
else:
|
||||
subprocess.run(sh, shell=True)
|
||||
|
||||
sign_prefix = (
|
||||
"/usr/bin/codesign -f -s - --timestamp=none --all-architectures"
|
||||
)
|
||||
|
||||
if no_deep is None:
|
||||
print("Need Deep Sign.")
|
||||
sign_prefix += " --deep"
|
||||
|
||||
if entitlements is not None:
|
||||
sign_prefix += f" --entitlements {current.parent}/tool/{entitlements}"
|
||||
|
||||
if no_sign_target is None:
|
||||
print("开始签名...")
|
||||
subprocess.run(f"{sign_prefix} '{dest}'", shell=True)
|
||||
subprocess.run(f"{sign_prefix} '{app_base_locate}'", shell=True)
|
||||
|
||||
if disable_library_validate is not None:
|
||||
subprocess.run(
|
||||
"sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation.plist DisableLibraryValidation -bool true",
|
||||
shell=True,
|
||||
)
|
||||
|
||||
if extra_shell is not None:
|
||||
subprocess.run(
|
||||
f"sudo sh {current.parent}/tool/{extra_shell}", shell=True
|
||||
)
|
||||
|
||||
if deep_sign_app:
|
||||
subprocess.run(f"{sign_prefix} '{app_base_locate}'", shell=True)
|
||||
|
||||
if forceSignMainExecute:
|
||||
subprocess.run(f"cp '{dest}' /tmp/test && codesign -fs - /tmp/test && cp /tmp/test '{dest}'", shell=True)
|
||||
|
||||
subprocess.run(f"sudo xattr -cr '{dest}'", shell=True)
|
||||
if auto_handle_helper and helper_file:
|
||||
helpers = []
|
||||
|
||||
if isinstance(helper_file, list):
|
||||
helpers = helper_file
|
||||
else:
|
||||
helpers.append(helper_file)
|
||||
|
||||
for helper in helpers:
|
||||
handle_helper(
|
||||
app_base_locate,
|
||||
f"{app_base_locate}{helper}",
|
||||
componentApp,
|
||||
SMExtra,
|
||||
f"{app_base_locate}{bridge_file}",
|
||||
useOptool,
|
||||
helperNoInject,
|
||||
dylibSelect
|
||||
)
|
||||
if tccutil is not None:
|
||||
if tccutil := tccutil:
|
||||
# 如果componentApp不为空,则创建一个数组
|
||||
ids = [local_app["CFBundleIdentifier"]]
|
||||
if isinstance(componentApp, list):
|
||||
ids.extend(
|
||||
[getBundleID(app_base_locate + i) for i in componentApp]
|
||||
)
|
||||
|
||||
for id in ids:
|
||||
if isinstance(tccutil, str):
|
||||
subprocess.run(f"tccutil reset {tccutil} {id}", shell=True)
|
||||
else:
|
||||
if isinstance(tccutil, list):
|
||||
for i in tccutil:
|
||||
subprocess.run(
|
||||
f"tccutil reset {i} {id}", shell=True
|
||||
)
|
||||
|
||||
print("App处理完成。")
|
||||
except KeyboardInterrupt:
|
||||
print("\n用户手动退出程序,祝你使用愉快,再见.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
Reference in New Issue
Block a user