mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-04-05 04:59:05 +08:00
Add tweakloader to jailbreak install flow (#173)
This commit is contained in:
committed by
GitHub
parent
97f96a86e0
commit
cd389412ec
@@ -127,6 +127,7 @@
|
||||
| 6 | LaunchDaemons | bash/dropbear/trollvnc/rpcserver_ios/vphoned plists | Y | Y | Y |
|
||||
| 7 | Procursus bootstrap | Bootstrap filesystem + optional Sileo deb | - | - | Y |
|
||||
| 8 | BaseBin hooks | `systemhook.dylib` / `launchdhook.dylib` / `libellekit.dylib` -> `/cores/` plus `/b` alias for `launchdhook.dylib` | - | - | Y |
|
||||
| 9 | `TweakLoader.dylib` | Lean user-tweak loader built from source and installed to `/var/jb/usr/lib/TweakLoader.dylib` | - | - | Y |
|
||||
|
||||
### CFW Installer Flow Matrix (Script-Level)
|
||||
|
||||
@@ -140,6 +141,7 @@
|
||||
|
||||
| Procursus bootstrap deployment | - | - | Y (JB-2) |
|
||||
| BaseBin hook deployment (`*.dylib` -> `/mnt1/cores`) | - | - | Y (JB-3) |
|
||||
| First-boot JB finalization (`vphone_jb_setup.sh`) | - | - | Y (post-boot; now fails before done marker if TrollStore Lite install does not complete) |
|
||||
| Additional input resources | `cfw_input` | `cfw_input` + `resources/cfw_dev/rpcserver_ios` | `cfw_input` + `cfw_jb_input` |
|
||||
| Extra tool requirement beyond base | - | - | `zstd` |
|
||||
| Halt behavior | Halts unless `CFW_SKIP_HALT=1` | Halts unless `CFW_SKIP_HALT=1` | Always halts after JB phases |
|
||||
@@ -157,9 +159,9 @@
|
||||
| Kernel (JB methods) | - | - | 59 |
|
||||
| Boot chain total | 41 | 52 | 112 |
|
||||
| CFW binary patches | 4 | 5 | 6 |
|
||||
| CFW installed components | 6 | 7 | 8 |
|
||||
| CFW total | 10 | 12 | 14 |
|
||||
| Grand total | 51 | 64 | 126 |
|
||||
| CFW installed components | 6 | 7 | 9 |
|
||||
| CFW total | 10 | 12 | 15 |
|
||||
| Grand total | 51 | 64 | 127 |
|
||||
|
||||
## Ramdisk Variant Matrix
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ check_prerequisites() {
|
||||
local missing=()
|
||||
command -v sshpass &>/dev/null || missing+=("sshpass")
|
||||
command -v ldid &>/dev/null || missing+=("ldid (brew install ldid-procursus)")
|
||||
command -v xcrun &>/dev/null || missing+=("xcrun (Xcode command line tools)")
|
||||
if ((${#missing[@]} > 0)); then
|
||||
die "Missing required tools: ${missing[*]}. Run: make setup_tools"
|
||||
fi
|
||||
@@ -110,6 +111,29 @@ ldid_sign_ent() {
|
||||
ldid "${args[@]}" "$file"
|
||||
}
|
||||
|
||||
build_tweakloader() {
|
||||
local src="$SCRIPT_DIR/tweakloader/TweakLoader.m"
|
||||
local out="$TEMP_DIR/TweakLoader.dylib"
|
||||
local sdk cc
|
||||
|
||||
[[ -f "$src" ]] || die "Missing tweak loader source at $src"
|
||||
|
||||
sdk="$(xcrun --sdk iphoneos --show-sdk-path)"
|
||||
cc="$(xcrun --sdk iphoneos -f clang)"
|
||||
|
||||
"$cc" -isysroot "$sdk" \
|
||||
-arch arm64 -arch arm64e \
|
||||
-miphoneos-version-min=15.0 \
|
||||
-dynamiclib \
|
||||
-fobjc-arc -O3 \
|
||||
-framework Foundation \
|
||||
-o "$out" \
|
||||
"$src"
|
||||
|
||||
ldid_sign "$out"
|
||||
echo "$out"
|
||||
}
|
||||
|
||||
remote_mount() {
|
||||
local dev="$1" mnt="$2" opts="${3:-rw}"
|
||||
ssh_cmd "/bin/mkdir -p $mnt"
|
||||
@@ -320,6 +344,18 @@ if [[ -d "$BASEBIN_DIR" ]]; then
|
||||
echo " [+] BaseBin hooks deployed"
|
||||
fi
|
||||
|
||||
# ═══════════ JB-4 INSTALL TWEAKLOADER ════════════════════════════
|
||||
echo ""
|
||||
echo "[JB-4] Building and installing TweakLoader..."
|
||||
|
||||
TWEAKLOADER_OUT="$(build_tweakloader)"
|
||||
ssh_cmd "/bin/mkdir -p /mnt5/$BOOT_HASH/$JB_DIR_NAME/procursus/usr/lib"
|
||||
scp_to "$TWEAKLOADER_OUT" "/mnt5/$BOOT_HASH/$JB_DIR_NAME/procursus/usr/lib/TweakLoader.dylib"
|
||||
ssh_cmd "/usr/sbin/chown 0:0 /mnt5/$BOOT_HASH/$JB_DIR_NAME/procursus/usr/lib/TweakLoader.dylib"
|
||||
ssh_cmd "/bin/chmod 0755 /mnt5/$BOOT_HASH/$JB_DIR_NAME/procursus/usr/lib/TweakLoader.dylib"
|
||||
|
||||
echo " [+] TweakLoader installed to procursus/usr/lib/TweakLoader.dylib"
|
||||
|
||||
# ═══════════ JB-5 DEPLOY FIRST-BOOT SETUP ══════════════════════
|
||||
echo ""
|
||||
echo "[JB-5] Deploying first-boot setup..."
|
||||
|
||||
18
scripts/tweakloader/README.md
Normal file
18
scripts/tweakloader/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
Lean TweakLoader
|
||||
================
|
||||
|
||||
Purpose
|
||||
- Provide the `/var/jb/usr/lib/TweakLoader.dylib` component expected by the
|
||||
vphone JB basebin runtime (`systemhook.dylib`).
|
||||
- Load user tweak dylibs from
|
||||
`/var/jb/Library/MobileSubstrate/DynamicLibraries` into matching processes.
|
||||
|
||||
Current behavior
|
||||
- Enumerates substrate-style `.plist` files in the tweak directory.
|
||||
- Supports:
|
||||
- `Filter.Bundles`
|
||||
- `Filter.Executables`
|
||||
- `dlopen`s the corresponding `.dylib` when the current process matches.
|
||||
|
||||
Logging
|
||||
- Writes to `/var/jb/var/mobile/Library/TweakLoader/tweakloader.log`.
|
||||
155
scripts/tweakloader/TweakLoader.m
Normal file
155
scripts/tweakloader/TweakLoader.m
Normal file
@@ -0,0 +1,155 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <dlfcn.h>
|
||||
#import <fcntl.h>
|
||||
#import <stdarg.h>
|
||||
#import <unistd.h>
|
||||
|
||||
static NSString *const kTweakDir = @"/var/jb/Library/MobileSubstrate/DynamicLibraries";
|
||||
static NSString *const kLogDir = @"/var/jb/var/mobile/Library/TweakLoader";
|
||||
static NSString *const kLogPath = @"/var/jb/var/mobile/Library/TweakLoader/tweakloader.log";
|
||||
|
||||
static void TLLog(NSString *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
||||
va_end(args);
|
||||
|
||||
if (!message.length) return;
|
||||
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:kLogDir
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:nil];
|
||||
|
||||
NSString *line = [NSString stringWithFormat:@"%@ [TweakLoader] %@\n",
|
||||
[NSDate.date description],
|
||||
message];
|
||||
NSData *data = [line dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (!data.length) return;
|
||||
|
||||
int fd = open(kLogPath.fileSystemRepresentation, O_WRONLY | O_CREAT | O_APPEND, 0644);
|
||||
if (fd < 0) return;
|
||||
(void)write(fd, data.bytes, data.length);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static NSString *TLExecutableName(void) {
|
||||
NSString *argv0 = NSProcessInfo.processInfo.arguments.firstObject;
|
||||
if (argv0.length) return argv0.lastPathComponent;
|
||||
return NSProcessInfo.processInfo.processName ?: @"unknown";
|
||||
}
|
||||
|
||||
static NSString *TLExecutablePath(void) {
|
||||
NSString *argv0 = NSProcessInfo.processInfo.arguments.firstObject;
|
||||
return argv0 ?: @"";
|
||||
}
|
||||
|
||||
static BOOL TLShouldRunInCurrentProcess(void) {
|
||||
NSString *execPath = TLExecutablePath();
|
||||
if (!execPath.length) return NO;
|
||||
|
||||
// vphone's hook runtime injects broadly, including launch-critical daemons
|
||||
// like xpcproxy, logd, notifyd, sshd, shells, and helper tools. Restrict the
|
||||
// user tweak loader to app binaries only so it does not destabilize boot or
|
||||
// process launch paths.
|
||||
if ([execPath containsString:@".app/"]) return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
static BOOL TLArrayContainsString(id obj, NSString *value) {
|
||||
if (![obj isKindOfClass:[NSArray class]] || !value.length) return NO;
|
||||
for (id item in (NSArray *)obj) {
|
||||
if ([item isKindOfClass:[NSString class]] &&
|
||||
[(NSString *)item isEqualToString:value]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
static BOOL TLFilterMatches(NSDictionary *plist, NSString *bundleID, NSString *executableName) {
|
||||
NSDictionary *filter = [plist isKindOfClass:[NSDictionary class]] ? plist[@"Filter"] : nil;
|
||||
if (![filter isKindOfClass:[NSDictionary class]]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
id bundles = filter[@"Bundles"];
|
||||
if ([bundles isKindOfClass:[NSArray class]]) {
|
||||
if (!bundleID.length || !TLArrayContainsString(bundles, bundleID)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
id executables = filter[@"Executables"];
|
||||
if ([executables isKindOfClass:[NSArray class]]) {
|
||||
if (!executableName.length || !TLArrayContainsString(executables, executableName)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
static void TLLoadTweaks(void) {
|
||||
NSFileManager *fm = NSFileManager.defaultManager;
|
||||
NSString *execPath = TLExecutablePath();
|
||||
NSString *bundleID = NSBundle.mainBundle.bundleIdentifier ?: @"";
|
||||
NSString *executableName = TLExecutableName();
|
||||
|
||||
if (!TLShouldRunInCurrentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray<NSString *> *files = [fm contentsOfDirectoryAtPath:kTweakDir error:nil];
|
||||
if (!files.count) {
|
||||
TLLog(@"No tweak files found for bundle=%@ exec=%@ path=%@",
|
||||
bundleID, executableName, execPath);
|
||||
return;
|
||||
}
|
||||
|
||||
TLLog(@"Scanning %lu tweak entries for bundle=%@ exec=%@ path=%@",
|
||||
(unsigned long)files.count, bundleID, executableName, execPath);
|
||||
|
||||
for (NSString *filename in files) {
|
||||
if (![filename.pathExtension isEqualToString:@"plist"]) continue;
|
||||
|
||||
NSString *plistPath = [kTweakDir stringByAppendingPathComponent:filename];
|
||||
NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistPath];
|
||||
if (![plist isKindOfClass:[NSDictionary class]]) {
|
||||
TLLog(@"Skipping unreadable plist %@", plistPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!TLFilterMatches(plist, bundleID, executableName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSString *baseName = filename.stringByDeletingPathExtension;
|
||||
NSString *dylibPath = [[kTweakDir stringByAppendingPathComponent:baseName]
|
||||
stringByAppendingPathExtension:@"dylib"];
|
||||
|
||||
if (![fm isExecutableFileAtPath:dylibPath]) {
|
||||
TLLog(@"Skipping %@ because dylib is missing or not executable", dylibPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
void *handle = dlopen(dylibPath.fileSystemRepresentation, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (handle) {
|
||||
TLLog(@"Loaded %@", dylibPath);
|
||||
} else {
|
||||
const char *err = dlerror();
|
||||
TLLog(@"Failed to load %@: %s", dylibPath, err ?: "unknown error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
static void TweakLoaderInit(void) {
|
||||
@autoreleasepool {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
TLLoadTweaks();
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user