diff --git a/StikJIT.xcodeproj/project.pbxproj b/StikJIT.xcodeproj/project.pbxproj index ca76c558..d4d4a9b5 100644 --- a/StikJIT.xcodeproj/project.pbxproj +++ b/StikJIT.xcodeproj/project.pbxproj @@ -49,9 +49,22 @@ DC6F1D522D94EADF0071B2B6 /* StikJITUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StikJITUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + 1775D3612D9644FD00DFA8E0 /* Exceptions for "StikJIT" folder in "StikJIT" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = DC6F1D362D94EADD0071B2B6 /* StikJIT */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + /* Begin PBXFileSystemSynchronizedRootGroup section */ DC6F1D392D94EADD0071B2B6 /* StikJIT */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + 1775D3612D9644FD00DFA8E0 /* Exceptions for "StikJIT" folder in "StikJIT" target */, + ); path = StikJIT; sourceTree = ""; }; @@ -429,6 +442,7 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = StikJIT/Info.plist; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; @@ -439,6 +453,7 @@ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportsDocumentBrowser = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.4; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; @@ -475,6 +490,7 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = StikJIT/Info.plist; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; @@ -485,6 +501,7 @@ "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportsDocumentBrowser = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.4; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; diff --git a/StikJIT/Info.plist b/StikJIT/Info.plist new file mode 100644 index 00000000..3ab09f6d --- /dev/null +++ b/StikJIT/Info.plist @@ -0,0 +1,19 @@ + + + + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + com.stik.StikJIT.enableJIT + CFBundleURLSchemes + + stikjit + + + + + diff --git a/StikJIT/StikJIT-Bridging-Header.h b/StikJIT/StikJIT-Bridging-Header.h index 9bc29b70..c0423477 100644 --- a/StikJIT/StikJIT-Bridging-Header.h +++ b/StikJIT/StikJIT-Bridging-Header.h @@ -2,7 +2,5 @@ // Use this file to import your target's public headers that you would like to expose to Swift. // -#include "idevice.h" -#include "heartbeat.h" -#include "jit.h" -#include "applist.h" +#include "idevice/JITEnableContext.h" +#include "idevice/idevice.h" diff --git a/StikJIT/StikJITApp.swift b/StikJIT/StikJITApp.swift index 2be8cdd8..8d495d00 100644 --- a/StikJIT/StikJITApp.swift +++ b/StikJIT/StikJITApp.swift @@ -106,8 +106,7 @@ struct HeartbeatApp: App { func startHeartbeatInBackground() { let heartBeat = Thread { - let cCompletionHandler: @convention(block) (Int32, UnsafePointer?) -> Void = { result, messagePointer in - let message: String? = messagePointer != nil ? String(cString: messagePointer!) : nil + let completionHandler: @convention(block) (Int32, String?) -> Void = { result, message in if result == 0 { print("Heartbeat started successfully: \(message ?? "")") @@ -122,7 +121,7 @@ struct HeartbeatApp: App { } } - startHeartbeat(cCompletionHandler) + JITEnableContext.shared().startHeartbeat(completionHandler: completionHandler, logger: nil) } heartBeat.qualityOfService = .background @@ -135,8 +134,7 @@ struct HeartbeatApp: App { func startHeartbeatInBackground() { let heartBeat = Thread { - let cCompletionHandler: @convention(block) (Int32, UnsafePointer?) -> Void = { result, messagePointer in - let message: String? = messagePointer != nil ? String(cString: messagePointer!) : nil + let completionHandler: @convention(block) (Int32, String?) -> Void = { result, message in if result == 0 { print("Heartbeat started successfully: \(message ?? "")") @@ -149,7 +147,7 @@ func startHeartbeatInBackground() { } } - startHeartbeat(cCompletionHandler) + JITEnableContext.shared().startHeartbeat(completionHandler: completionHandler, logger: nil) } heartBeat.qualityOfService = .background diff --git a/StikJIT/Views/HomeView.swift b/StikJIT/Views/HomeView.swift index 3bc78bb5..2b0d5e91 100644 --- a/StikJIT/Views/HomeView.swift +++ b/StikJIT/Views/HomeView.swift @@ -28,6 +28,9 @@ struct HomeView: View { @State private var pairingFileIsValid = false @State private var isImportingFile = false @State private var importProgress: Float = 0.0 + + @State private var viewDidAppeared = false + @State private var pendingBundleIdToEnableJIT : String? = nil var body: some View { ZStack { @@ -209,8 +212,33 @@ struct HomeView: View { startJITInBackground(with: selectedBundle) } } + .onOpenURL { url in + print(url.path()) + if url.host() != "enable-jit" { + return + } + + let components = URLComponents(url: url, resolvingAgainstBaseURL: false) + if let bundleId = components?.queryItems?.first(where: { $0.name == "bundle-id" })?.value { + if viewDidAppeared { + startJITInBackground(with: bundleId) + } else { + pendingBundleIdToEnableJIT = bundleId + } + } + + } + .onAppear() { + viewDidAppeared = true + if let pendingBundleIdToEnableJIT { + startJITInBackground(with: pendingBundleIdToEnableJIT) + self.pendingBundleIdToEnableJIT = nil + } + } } + + private func checkPairingFileExists() { pairingFileExists = FileManager.default.fileExists(atPath: URL.documentsDirectory.appendingPathComponent("pairingFile.plist").path) } @@ -222,14 +250,9 @@ struct HomeView: View { private func startJITInBackground(with bundleID: String) { isProcessing = true DispatchQueue.global(qos: .background).async { - guard let cBundleID = strdup(bundleID) else { - DispatchQueue.main.async { isProcessing = false } - return - } - _ = debug_app(cBundleID) + JITEnableContext.shared().debugApp(withBundleID: bundleID, logger: nil) - free(cBundleID) DispatchQueue.main.async { isProcessing = false } @@ -245,38 +268,13 @@ class InstalledAppsViewModel: ObservableObject { } func loadApps() { - guard let rawPointer = list_installed_apps() else { - self.apps = [:] - return - } - - let output = String(cString: rawPointer) - free(rawPointer) - - guard let jsonData = output.data(using: .utf8) else { - print("Error: Failed to convert string to data") - self.apps = [:] - return - } - - print(output) - - // Decode the JSON into a Swift dictionary do { - let decoder = JSONDecoder() - let apps = try decoder.decode([String: String].self, from: jsonData) - if let app = apps.first, app.key == "error" { - self.apps = [:] - } else { - self.apps = apps - } - return + self.apps = try JITEnableContext.shared().getAppList() } catch { - print("Error: Failed to decode JSON - \(error)") + print(error) self.apps = [:] - return } - + } } diff --git a/StikJIT/Views/InstalledAppsListView.swift b/StikJIT/Views/InstalledAppsListView.swift index d20654eb..b4b399b3 100644 --- a/StikJIT/Views/InstalledAppsListView.swift +++ b/StikJIT/Views/InstalledAppsListView.swift @@ -18,7 +18,7 @@ struct InstalledAppsListView: View { NavigationView { ScrollView { LazyVStack(spacing: 0) { - ForEach(viewModel.apps.sorted(by: { $0.key < $1.key }), id: \.key) { appName, bundleID in + ForEach(viewModel.apps.sorted(by: { $0.key < $1.key }), id: \.key) { bundleID, appName in Button(action: { withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) { onSelectApp(bundleID) diff --git a/StikJIT/idevice/JITEnableContext.h b/StikJIT/idevice/JITEnableContext.h new file mode 100644 index 00000000..85df85a2 --- /dev/null +++ b/StikJIT/idevice/JITEnableContext.h @@ -0,0 +1,20 @@ +// +// JITEnableContext.h +// StikJIT +// +// Created by s s on 2025/3/28. +// +@import Foundation; +#include "idevice.h" + +typedef void (^HeartbeatCompletionHandler)(int result, NSString *message); +typedef void (^LogFuncC)(const char* message, ...); +typedef void (^LogFunc)(NSString *message); + +@interface JITEnableContext : NSObject ++ (instancetype)shared; +- (IdevicePairingFile*)getPairingFileWithError:(NSError**)error; +- (void)startHeartbeatWithCompletionHandler:(HeartbeatCompletionHandler)completionHandler logger:(LogFunc)logger; +- (void)debugAppWithBundleID:(NSString*)bundleID logger:(LogFunc)logger; +- (NSDictionary*)getAppListWithError:(NSError**)error; +@end diff --git a/StikJIT/idevice/JITEnableContext.m b/StikJIT/idevice/JITEnableContext.m new file mode 100644 index 00000000..83e985f3 --- /dev/null +++ b/StikJIT/idevice/JITEnableContext.m @@ -0,0 +1,125 @@ +// +// JITEnableContext.m +// StikJIT +// +// Created by s s on 2025/3/28. +// +#include "idevice.h" +#include +#include + +#include "heartbeat.h" +#include "jit.h" +#include "applist.h" + +#include "JITEnableContext.h" + +JITEnableContext* sharedJITContext = nil; + +@implementation JITEnableContext { + int heartbeatSessionId; + TcpProviderHandle* provider; +} + ++ (instancetype)shared { + if(!sharedJITContext) { + sharedJITContext = [[JITEnableContext alloc] init]; + } + return sharedJITContext; +} + +- (NSError*)errorWithStr:(NSString*)str code:(int)code { + return [NSError errorWithDomain:@"StikJIT" code:code userInfo:@{NSLocalizedDescriptionKey: str}]; +} + +- (LogFuncC)createCLogger:(LogFunc)logger { + return ^(const char* format, ...) { + va_list args; + va_start(args, format); + NSString* formatStr = [NSString stringWithCString:format encoding:NSASCIIStringEncoding]; + + NSString *message = [[NSString alloc] initWithFormat:formatStr arguments:args]; + NSLog(@"%@", message); + + if(logger) { + logger(message); + } + + va_end(args); + }; +} + +- (IdevicePairingFile*)getPairingFileWithError:(NSError**)error { + NSFileManager* fm = [NSFileManager defaultManager]; + NSURL* docPathUrl = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject; + NSURL* pairingFileURL = [docPathUrl URLByAppendingPathComponent:@"pairingFile.plist"]; + if(![fm fileExistsAtPath:pairingFileURL.path]) { + NSLog(@"Pairing file not found!"); + *error = [self errorWithStr:@"Pairing file not found!" code:-17]; + return false; + } + + IdevicePairingFile* pairingFile = NULL; + IdeviceErrorCode err = idevice_pairing_file_read(pairingFileURL.fileSystemRepresentation, &pairingFile); + if (err != IdeviceSuccess) { + *error = [self errorWithStr:@"Failed to read pairing file!" code:err]; + return nil; + } + return pairingFile; +} + +- (void)startHeartbeatWithCompletionHandler:(HeartbeatCompletionHandler)completionHandler logger:(LogFunc)logger { + NSError* err = nil; + IdevicePairingFile* pairingFile = [self getPairingFileWithError:&err]; + if(err) { + if(logger) { + logger(err.localizedDescription); + } + + completionHandler(-17, err.localizedDescription); + return; + } + self->heartbeatSessionId = arc4random(); + startHeartbeat(pairingFile, &(self->provider), &(self->heartbeatSessionId), ^(int result, const char *message) { + completionHandler(result,[NSString stringWithCString:message encoding:NSASCIIStringEncoding]); + }, [self createCLogger:logger]); +} +- (void)debugAppWithBundleID:(NSString*)bundleID logger:(LogFunc)logger { + if(!provider) { + if(logger) { + logger(@"Provider not initialized!"); + } + NSLog(@"Provider not initialized!"); + return; + } + + debug_app(provider, [bundleID UTF8String], [self createCLogger:logger]); +} + + +// apps may have different name, so we must use BnudleId as key. [bundleId:name] +- (NSDictionary*)getAppListWithError:(NSError**)error { + if(!provider) { + NSLog(@"Provider not initialized!"); + *error = [self errorWithStr:@"Provider not initialized!" code:-1]; + return nil; + } + + NSString* errorStr = nil; + NSDictionary* ans = list_installed_apps(provider, &errorStr); + if(errorStr){ + *error = [self errorWithStr:errorStr code:-17]; + return nil; + } else { + return ans; + } +} + +- (void)dealloc { + self->heartbeatSessionId = arc4random(); + if(provider) { + tcp_provider_free(provider); + } +} + +@end diff --git a/StikJIT/idevice/applist.c b/StikJIT/idevice/applist.c deleted file mode 100644 index b018c7d3..00000000 --- a/StikJIT/idevice/applist.c +++ /dev/null @@ -1,145 +0,0 @@ -// -// applist.c -// StikJIT -// -// Created by Stephen on 3/27/25. -// - -#include "idevice.h" -#include -#include -#include -#include -#include -#include - -char *list_installed_apps() { - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(LOCKDOWN_PORT); - if (inet_pton(AF_INET, "10.7.0.1", &addr.sin_addr) <= 0) { - return strdup("{\"error\": \"Invalid IP address\"}"); - } - - char pairingFilePath[1024]; - CFURLRef url = CFCopyHomeDirectoryURL(); - if (url) { - CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); - if (path) { - CFStringGetCString(path, pairingFilePath, sizeof(pairingFilePath), kCFStringEncodingUTF8); - strncat(pairingFilePath, "/Documents/pairingFile.plist", sizeof(pairingFilePath) - strlen(pairingFilePath) - 1); - CFRelease(path); - } - CFRelease(url); - } - - IdevicePairingFile *pairing_file = NULL; - IdeviceErrorCode err = idevice_pairing_file_read(pairingFilePath, &pairing_file); - if (err != IdeviceSuccess) { - return strdup("{\"error\": \"Failed to read pairing file\"}"); - } - - TcpProviderHandle *provider = NULL; - err = idevice_tcp_provider_new((struct sockaddr *)&addr, pairing_file, "ExampleProvider", &provider); - if (err != IdeviceSuccess) { - idevice_pairing_file_free(pairing_file); - return strdup("{\"error\": \"Failed to create TCP provider\"}"); - } - - InstallationProxyClientHandle *client = NULL; - err = installation_proxy_connect_tcp(provider, &client); - if (err != IdeviceSuccess) { - tcp_provider_free(provider); - return strdup("{\"error\": \"Failed to connect to installation proxy\"}"); - } - - void *apps = NULL; - size_t apps_len = 0; - err = installation_proxy_get_apps(client, NULL, NULL, 0, &apps, &apps_len); - if (err != IdeviceSuccess) { - installation_proxy_client_free(client); - tcp_provider_free(provider); - return strdup("{\"error\": \"Failed to get apps\"}"); - } - - plist_t *app_list = (plist_t *)apps; - char *result = malloc(8192); // Allocate memory for output - result[0] = '\0'; - strcat(result, "{\n"); - - int first_entry = 1; - for (size_t i = 0; i < apps_len; i++) { - plist_t app = app_list[i]; - // Check if the app has an "Entitlements" dictionary. - plist_t entitlements = plist_dict_get_item(app, "Entitlements"); - if (entitlements) { - // Look for the "get-task-allow" key. - plist_t taskAllowNode = plist_dict_get_item(entitlements, "get-task-allow"); - if (taskAllowNode) { - int isAllowed = 0; - plist_get_bool_val(taskAllowNode, &isAllowed); - if (isAllowed) { - // Retrieve the bundle identifier if the entitlement is true. - plist_t bundle_id_node = plist_dict_get_item(app, "CFBundleIdentifier"); - if (bundle_id_node) { - char *bundle_id = NULL; - plist_get_string_val(bundle_id_node, &bundle_id); - - // Skip if bundle ID is empty - if (bundle_id == NULL || strlen(bundle_id) == 0) { - free(bundle_id); - continue; - } - - // Retrieve the app name - plist_t app_name_node = plist_dict_get_item(app, "CFBundleName"); - char *app_name = NULL; - if (app_name_node) { - plist_get_string_val(app_name_node, &app_name); - } else { - app_name = strdup("Unknown"); - } - - // Escape special characters in app name and bundle ID - char escaped_app_name[1024] = {0}; - char escaped_bundle_id[1024] = {0}; - for (int j = 0, k = 0; app_name[j] != '\0'; j++, k++) { - if (app_name[j] == '"' || app_name[j] == '\\') { - escaped_app_name[k++] = '\\'; - } - escaped_app_name[k] = app_name[j]; - } - for (int j = 0, k = 0; bundle_id[j] != '\0'; j++, k++) { - if (bundle_id[j] == '"' || bundle_id[j] == '\\') { - escaped_bundle_id[k++] = '\\'; - } - escaped_bundle_id[k] = bundle_id[j]; - } - - // Add the app name and bundle ID to the result in JSON format - if (!first_entry) { - strcat(result, ",\n"); - } - strcat(result, " \""); - strcat(result, escaped_app_name); - strcat(result, "\": \""); - strcat(result, escaped_bundle_id); - strcat(result, "\""); - - first_entry = 0; - free(bundle_id); - free(app_name); - } - } - } - } - } - - strcat(result, "\n}\n"); - - installation_proxy_client_free(client); - tcp_provider_free(provider); - - return result; -} diff --git a/StikJIT/idevice/applist.h b/StikJIT/idevice/applist.h index 051c4591..13818d42 100644 --- a/StikJIT/idevice/applist.h +++ b/StikJIT/idevice/applist.h @@ -7,7 +7,8 @@ #ifndef APPLIST_H #define APPLIST_H +@import Foundation; -char *list_installed_apps(void); +NSDictionary* list_installed_apps(TcpProviderHandle* provider, NSString** error); #endif /* APPLIST_H */ diff --git a/StikJIT/idevice/applist.m b/StikJIT/idevice/applist.m new file mode 100644 index 00000000..ab947d1b --- /dev/null +++ b/StikJIT/idevice/applist.m @@ -0,0 +1,86 @@ +// +// applist.c +// StikJIT +// +// Created by Stephen on 3/27/25. +// + +#include "idevice.h" +#include +#include +#include +#include +#include + +#include "applist.h" + +NSDictionary* list_installed_apps(TcpProviderHandle* provider, NSString** error) { + IdeviceErrorCode err = IdeviceSuccess; + + InstallationProxyClientHandle *client = NULL; + err = installation_proxy_connect_tcp(provider, &client); + if (err != IdeviceSuccess) { + *error = @"Failed to connect to installation proxy"; + return nil; + } + + void *apps = NULL; + size_t apps_len = 0; + err = installation_proxy_get_apps(client, NULL, NULL, 0, &apps, &apps_len); + if (err != IdeviceSuccess) { + installation_proxy_client_free(client); + *error = @"Failed to get apps"; + return nil; + } + + plist_t *app_list = (plist_t *)apps; + + NSMutableDictionary* ans = [[NSMutableDictionary alloc] init]; + + for (size_t i = 0; i < apps_len; i++) { + plist_t app = app_list[i]; + // Check if the app has an "Entitlements" dictionary. + plist_t entitlements = plist_dict_get_item(app, "Entitlements"); + if (entitlements) { + // Look for the "get-task-allow" key. + plist_t taskAllowNode = plist_dict_get_item(entitlements, "get-task-allow"); + if (taskAllowNode) { + uint8_t isAllowed = 0; + plist_get_bool_val(taskAllowNode, &isAllowed); + if (isAllowed) { + // Retrieve the bundle identifier if the entitlement is true. + plist_t bundle_id_node = plist_dict_get_item(app, "CFBundleIdentifier"); + if (bundle_id_node) { + char *bundle_id = NULL; + plist_get_string_val(bundle_id_node, &bundle_id); + + // Skip if bundle ID is empty + if (bundle_id == NULL || strlen(bundle_id) == 0) { + free(bundle_id); + continue; + } + + // Retrieve the app name + plist_t app_name_node = plist_dict_get_item(app, "CFBundleName"); + char *app_name = NULL; + if (app_name_node) { + plist_get_string_val(app_name_node, &app_name); + } else { + app_name = strdup("Unknown"); + } + + ans[[NSString stringWithCString:bundle_id encoding:NSASCIIStringEncoding]] = [NSString stringWithCString:app_name encoding:NSASCIIStringEncoding]; + + free(bundle_id); + free(app_name); + } + } + } + } + } + + + installation_proxy_client_free(client); + + return ans; +} diff --git a/StikJIT/idevice/heartbeat.c b/StikJIT/idevice/heartbeat.c index a36908d6..e44b9f62 100644 --- a/StikJIT/idevice/heartbeat.c +++ b/StikJIT/idevice/heartbeat.c @@ -9,11 +9,11 @@ #include #include #include +#include "heartbeat.h" -typedef void (^HeartbeatCompletionHandler)(int result, const char *message); - -void startHeartbeat(HeartbeatCompletionHandler completion) { - printf("DEBUG: Initializing logger...\n"); +void startHeartbeat(IdevicePairingFile* pairing_file, TcpProviderHandle** provider, int* heartbeatSessionId, HeartbeatCompletionHandlerC completion, LogFuncC logger) { + int currentSessionId = *heartbeatSessionId; + logger("DEBUG: Initializing logger..."); idevice_init_logger(Debug, Disabled, NULL); struct sockaddr_in addr; @@ -21,80 +21,59 @@ void startHeartbeat(HeartbeatCompletionHandler completion) { addr.sin_family = AF_INET; addr.sin_port = htons(LOCKDOWN_PORT); if (inet_pton(AF_INET, "10.7.0.1", &addr.sin_addr) <= 0) { - fprintf(stderr, "DEBUG: Error converting IP address.\n"); + logger("DEBUG: Error converting IP address."); return; } - printf("DEBUG: Socket address created for IP 10.7.0.1 on port %d.\n", LOCKDOWN_PORT); + logger("DEBUG: Socket address created for IP 10.7.0.1 on port %d.", LOCKDOWN_PORT); - printf("DEBUG: Searching the app bundle for pairing_file.plist...\n"); - char pairingFilePath[1024]; - CFURLRef url = CFCopyHomeDirectoryURL(); - if (url) { - CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); - if (path) { - CFStringGetCString(path, pairingFilePath, sizeof(pairingFilePath), kCFStringEncodingUTF8); - strncat(pairingFilePath, "/Documents/pairingFile.plist", sizeof(pairingFilePath) - strlen(pairingFilePath) - 1); - CFRelease(path); - } - CFRelease(url); - } - printf("Pairing file found at path: %s\n", pairingFilePath); + IdeviceErrorCode err = IdeviceSuccess; - printf("DEBUG: Reading pairing file...\n"); - IdevicePairingFile *pairing_file = NULL; - IdeviceErrorCode err = idevice_pairing_file_read(pairingFilePath, &pairing_file); - if (err != IdeviceSuccess) { - fprintf(stderr, "DEBUG: Failed to read pairing file: %d\n", err); - completion(err, "Failed to read pairing file"); - return; - } - printf("DEBUG: Pairing file read successfully.\n"); - - printf("DEBUG: Creating TCP provider...\n"); - TcpProviderHandle *provider = NULL; + logger("DEBUG: Creating TCP provider..."); err = idevice_tcp_provider_new((struct sockaddr *)&addr, pairing_file, - "ExampleProvider", &provider); + "ExampleProvider", provider); if (err != IdeviceSuccess) { - fprintf(stderr, "DEBUG: Failed to create TCP provider: %d\n", err); - idevice_pairing_file_free(pairing_file); + logger("DEBUG: Failed to create TCP provider: %d", err); completion(err, "Failed to create TCP provider"); return; } - printf("DEBUG: TCP provider created successfully.\n"); + logger("DEBUG: TCP provider created successfully."); - printf("DEBUG: Connecting to installation proxy...\n"); + logger("DEBUG: Connecting to installation proxy..."); HeartbeatClientHandle *client = NULL; - err = heartbeat_connect_tcp(provider, &client); + err = heartbeat_connect_tcp(*provider, &client); if (err != IdeviceSuccess) { completion(err, "Failed to connect to Heartbeat"); - fprintf(stderr, "DEBUG: Failed to connect to installation proxy: %d\n", err); + logger("DEBUG: Failed to connect to installation proxy: %d", err); return; } - tcp_provider_free(provider); - printf("DEBUG: Connected to installation proxy successfully.\n"); + logger("DEBUG: Connected to installation proxy successfully."); completion(0, "Heartbeat Completed"); u_int64_t current_interval = 15; while (1) { + if(*heartbeatSessionId != currentSessionId) { + break; + } + u_int64_t new_interval = 0; - printf("DEBUG: Sending heartbeat with current interval: %llu seconds...\n", current_interval); + logger("DEBUG: Sending heartbeat with current interval: %llu seconds...", current_interval); err = heartbeat_get_marco(client, current_interval, &new_interval); if (err != IdeviceSuccess) { - fprintf(stderr, "DEBUG: Failed to get marco: %d\n", err); + logger("DEBUG: Failed to get marco: %d", err); heartbeat_client_free(client); return; } - printf("DEBUG: Received new interval: %llu seconds.\n", new_interval); + logger("DEBUG: Received new interval: %llu seconds.", new_interval); current_interval = new_interval + 5; - printf("DEBUG: Sending polo reply...\n"); + logger("DEBUG: Sending polo reply..."); err = heartbeat_send_polo(client); if (err != IdeviceSuccess) { - fprintf(stderr, "DEBUG: Failed to send polo: %d\n", err); + logger("DEBUG: Failed to send polo: %d", err); heartbeat_client_free(client); return; } - printf("DEBUG: Polo reply sent successfully.\n"); + logger("DEBUG: Polo reply sent successfully."); } } diff --git a/StikJIT/idevice/heartbeat.h b/StikJIT/idevice/heartbeat.h index 5d31d58b..1f20e5d2 100644 --- a/StikJIT/idevice/heartbeat.h +++ b/StikJIT/idevice/heartbeat.h @@ -8,9 +8,11 @@ // heartbeat.h #ifndef HEARTBEAT_H #define HEARTBEAT_H +#include "idevice.h" -typedef void (^HeartbeatCompletionHandler)(int result, const char *message); +typedef void (^HeartbeatCompletionHandlerC)(int result, const char *message); +typedef void (^LogFuncC)(const char* message, ...); -void startHeartbeat(HeartbeatCompletionHandler completion); +void startHeartbeat(IdevicePairingFile* pairintFile, TcpProviderHandle** provider, int* heartbeatSessionId, HeartbeatCompletionHandlerC completion, LogFuncC logger); #endif /* HEARTBEAT_H */ diff --git a/StikJIT/idevice/idevice.h b/StikJIT/idevice/idevice.h index 855dde88..27b8ab7c 100644 --- a/StikJIT/idevice/idevice.h +++ b/StikJIT/idevice/idevice.h @@ -8,6 +8,9 @@ #include #include "plist.h" +#ifndef IDEVICE_H +#define IDEVICE_H + #define LOCKDOWN_PORT 62078 typedef enum IdeviceErrorCode { @@ -1629,3 +1632,5 @@ enum IdeviceErrorCode idevice_usbmuxd_unix_addr_new(const char *addr, * or NULL (in which case this function does nothing) */ void idevice_usbmuxd_addr_free(struct UsbmuxdAddrHandle *usbmuxd_addr); + +#endif /* IDEVICE_H */ diff --git a/StikJIT/idevice/jit.c b/StikJIT/idevice/jit.c index 895eb00e..c47f8517 100644 --- a/StikJIT/idevice/jit.c +++ b/StikJIT/idevice/jit.c @@ -17,92 +17,40 @@ #include #include -int debug_app(const char *bundle_id) { +#include "jit.h" + +int debug_app(TcpProviderHandle* tcp_provider, const char *bundle_id, LogFuncC logger) { // Initialize logger idevice_init_logger(Debug, Disabled, NULL); - - // Hardcode device IP - const char *device_ip = "10.7.0.1"; - - - /***************************************************************** - * Locate pairing file in app bundle - *****************************************************************/ - char pairingFilePath[1024]; - CFURLRef url = CFCopyHomeDirectoryURL(); - if (url) { - CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); - if (path) { - CFStringGetCString(path, pairingFilePath, sizeof(pairingFilePath), kCFStringEncodingUTF8); - strncat(pairingFilePath, "/Documents/pairingFile.plist", sizeof(pairingFilePath) - strlen(pairingFilePath) - 1); - CFRelease(path); - } - CFRelease(url); - } - printf("Pairing file found at path: %s\n", pairingFilePath); - - /***************************************************************** - * CoreDeviceProxy Setup - *****************************************************************/ - printf("=== Setting up CoreDeviceProxy ===\n"); - - // Create socket address - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(LOCKDOWN_PORT); - if (inet_pton(AF_INET, device_ip, &addr.sin_addr) != 1) { - fprintf(stderr, "Invalid IP address\n"); - return 1; - } - - // Read pairing file from the bundle - IdevicePairingFile *pairing = NULL; - IdeviceErrorCode err = idevice_pairing_file_read(pairingFilePath, &pairing); - if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to read pairing file: %d\n", err); - return 1; - } - - // Create TCP provider - TcpProviderHandle *tcp_provider = NULL; - err = idevice_tcp_provider_new((struct sockaddr *)&addr, pairing, - "ProcessDebugTest", &tcp_provider); - if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to create TCP provider: %d\n", err); - idevice_pairing_file_free(pairing); - return 1; - } + IdeviceErrorCode err = IdeviceSuccess; // Connect to CoreDeviceProxy CoreDeviceProxyHandle *core_device = NULL; err = core_device_proxy_connect_tcp(tcp_provider, &core_device); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to connect to CoreDeviceProxy: %d\n", err); - tcp_provider_free(tcp_provider); + logger("Failed to connect to CoreDeviceProxy: %d", err); return 1; } - tcp_provider_free(tcp_provider); // Get server RSD port uint16_t rsd_port; err = core_device_proxy_get_server_rsd_port(core_device, &rsd_port); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to get server RSD port: %d\n", err); + logger("Failed to get server RSD port: %d", err); core_device_proxy_free(core_device); return 1; } - printf("Server RSD Port: %d\n", rsd_port); + logger("Server RSD Port: %d", rsd_port); /***************************************************************** * Create TCP Tunnel Adapter *****************************************************************/ - printf("\n=== Creating TCP Tunnel Adapter ===\n"); + logger("=== Creating TCP Tunnel Adapter ==="); AdapterHandle *adapter = NULL; err = core_device_proxy_create_tcp_adapter(core_device, &adapter); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to create TCP adapter: %d\n", err); + logger("Failed to create TCP adapter: %d", err); core_device_proxy_free(core_device); return 1; } @@ -110,22 +58,22 @@ int debug_app(const char *bundle_id) { // Connect to RSD port err = adapter_connect(adapter, rsd_port); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to connect to RSD port: %d\n", err); + logger("Failed to connect to RSD port: %d", err); adapter_free(adapter); core_device_proxy_free(core_device); return 1; } - printf("Successfully connected to RSD port\n"); + logger("Successfully connected to RSD port"); /***************************************************************** * XPC Device Setup *****************************************************************/ - printf("\n=== Setting up XPC Device ===\n"); + logger("=== Setting up XPC Device ==="); XPCDeviceAdapterHandle *xpc_device = NULL; err = xpc_device_new(adapter, &xpc_device); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to create XPC device: %d\n", err); + logger("Failed to create XPC device: %d", err); adapter_free(adapter); core_device_proxy_free(core_device); return 1; @@ -135,7 +83,7 @@ int debug_app(const char *bundle_id) { XPCServiceHandle *debug_service = NULL; err = xpc_device_get_service(xpc_device, "com.apple.internal.dt.remote.debugproxy", &debug_service); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to get debug proxy service: %d\n", err); + logger("Failed to get debug proxy service: %d", err); return 1; } @@ -143,7 +91,7 @@ int debug_app(const char *bundle_id) { XPCServiceHandle *pc_service = NULL; err = xpc_device_get_service(xpc_device, "com.apple.instruments.dtservicehub", &pc_service); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to get process control service: %d\n", err); + logger("Failed to get process control service: %d", err); xpc_device_free(xpc_device); core_device_proxy_free(core_device); return 1; @@ -152,13 +100,13 @@ int debug_app(const char *bundle_id) { /***************************************************************** * Process Control - Launch App *****************************************************************/ - printf("\n=== Launching App ===\n"); + logger("=== Launching App ==="); // Get the adapter back from the XPC device AdapterHandle *pc_adapter = NULL; err = xpc_device_adapter_into_inner(xpc_device, &pc_adapter); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to extract adapter: %d\n", err); + logger("Failed to extract adapter: %d", err); xpc_device_free(xpc_device); core_device_proxy_free(core_device); return 1; @@ -167,19 +115,19 @@ int debug_app(const char *bundle_id) { // Connect to process control port err = adapter_connect(pc_adapter, pc_service->port); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to connect to process control port: %d\n", err); + logger("Failed to connect to process control port: %d", err); adapter_free(pc_adapter); xpc_service_free(pc_service); core_device_proxy_free(core_device); return 1; } - printf("Successfully connected to process control port\n"); + logger("Successfully connected to process control port"); // Create RemoteServerClient RemoteServerAdapterHandle *remote_server = NULL; err = remote_server_adapter_new(pc_adapter, &remote_server); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to create remote server: %d\n", err); + logger("Failed to create remote server: %d", err); adapter_free(pc_adapter); xpc_service_free(pc_service); core_device_proxy_free(core_device); @@ -190,7 +138,7 @@ int debug_app(const char *bundle_id) { ProcessControlAdapterHandle *process_control = NULL; err = process_control_new(remote_server, &process_control); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to create process control client: %d\n", err); + logger("Failed to create process control client: %d", err); remote_server_free(remote_server); xpc_service_free(pc_service); core_device_proxy_free(core_device); @@ -202,25 +150,25 @@ int debug_app(const char *bundle_id) { err = process_control_launch_app(process_control, bundle_id, NULL, 0, NULL, 0, true, false, &pid); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to launch app: %d\n", err); + logger("Failed to launch app: %d", err); process_control_free(process_control); remote_server_free(remote_server); xpc_service_free(pc_service); core_device_proxy_free(core_device); return 1; } - printf("Successfully launched app with PID: %" PRIu64 "\n", pid); + logger("Successfully launched app with PID: %" PRIu64 "", pid); /***************************************************************** * Debug Proxy - Attach to Process *****************************************************************/ - printf("\n=== Attaching Debugger ===\n"); + logger("=== Attaching Debugger ==="); // Get the adapter back from the remote server AdapterHandle *debug_adapter = NULL; err = remote_server_adapter_into_inner(remote_server, &debug_adapter); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to extract adapter: %d\n", err); + logger("Failed to extract adapter: %d", err); xpc_service_free(debug_service); process_control_free(process_control); remote_server_free(remote_server); @@ -232,7 +180,7 @@ int debug_app(const char *bundle_id) { // Connect to debug proxy port err = adapter_connect(debug_adapter, debug_service->port); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to connect to debug proxy port: %d\n", err); + logger("Failed to connect to debug proxy port: %d", err); adapter_free(debug_adapter); xpc_service_free(debug_service); process_control_free(process_control); @@ -241,13 +189,13 @@ int debug_app(const char *bundle_id) { core_device_proxy_free(core_device); return 1; } - printf("Successfully connected to debug proxy port\n"); + logger("Successfully connected to debug proxy port"); // Create DebugProxyClient DebugProxyAdapterHandle *debug_proxy = NULL; err = debug_proxy_adapter_new(debug_adapter, &debug_proxy); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to create debug proxy client: %d\n", err); + logger("Failed to create debug proxy client: %d", err); adapter_free(debug_adapter); xpc_service_free(debug_service); process_control_free(process_control); @@ -263,7 +211,7 @@ int debug_app(const char *bundle_id) { DebugserverCommandHandle *attach_cmd = debugserver_command_new(attach_command, NULL, 0); if (attach_cmd == NULL) { - fprintf(stderr, "Failed to create attach command\n"); + logger("Failed to create attach command"); debug_proxy_free(debug_proxy); adapter_free(debug_adapter); xpc_service_free(debug_service); @@ -279,16 +227,16 @@ int debug_app(const char *bundle_id) { debugserver_command_free(attach_cmd); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to attach to process: %d\n", err); + logger("Failed to attach to process: %d", err); } else if (attach_response != NULL) { - printf("Attach response: %s\n", attach_response); + logger("Attach response: %s", attach_response); idevice_string_free(attach_response); } // Send detach command DebugserverCommandHandle *detach_cmd = debugserver_command_new("D", NULL, 0); if (detach_cmd == NULL) { - fprintf(stderr, "Failed to create detach command\n"); + logger("Failed to create detach command"); } else { char *detach_response = NULL; err = debug_proxy_send_command(debug_proxy, detach_cmd, &detach_response); @@ -297,9 +245,9 @@ int debug_app(const char *bundle_id) { debugserver_command_free(detach_cmd); if (err != IdeviceSuccess) { - fprintf(stderr, "Failed to detach from process: %d\n", err); + logger("Failed to detach from process: %d", err); } else if (detach_response != NULL) { - printf("Detach response: %s\n", detach_response); + logger("Detach response: %s", detach_response); idevice_string_free(detach_response); } } @@ -310,6 +258,6 @@ int debug_app(const char *bundle_id) { debug_proxy_free(debug_proxy); xpc_service_free(debug_service); - printf("\nDebug session completed\n"); + logger("Debug session completed"); return 0; } diff --git a/StikJIT/idevice/jit.h b/StikJIT/idevice/jit.h index dbfcb4a9..c42f2fc2 100644 --- a/StikJIT/idevice/jit.h +++ b/StikJIT/idevice/jit.h @@ -8,7 +8,9 @@ // jit.h #ifndef JIT_H #define JIT_H +#include "idevice.h" -int debug_app(const char *bundle_id); +typedef void (^LogFuncC)(const char* message, ...); +int debug_app(TcpProviderHandle* provider, const char *bundle_id, LogFuncC logger); #endif /* JIT_H */