Merge branch '0-Blu:main' into main

This commit is contained in:
se2crid 2025-03-28 14:54:58 +01:00 • committed by GitHub
commit 2e00f754d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 383 additions and 327 deletions

View file

@ -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 = "<group>";
};
@ -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";

19
StikJIT/Info.plist Normal file
View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.stik.StikJIT.enableJIT</string>
<key>CFBundleURLSchemes</key>
<array>
<string>stikjit</string>
</array>
</dict>
</array>
</dict>
</plist>

View file

@ -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"

View file

@ -106,8 +106,7 @@ struct HeartbeatApp: App {
func startHeartbeatInBackground() {
let heartBeat = Thread {
let cCompletionHandler: @convention(block) (Int32, UnsafePointer<CChar>?) -> 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<CChar>?) -> 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

View file

@ -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
}
}
}

View file

@ -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)

View file

@ -161,6 +161,9 @@ struct SettingsView: View {
Text("HugeBlack")
.foregroundColor(.primaryText)
}
}
Text("HugeBlack")
.foregroundColor(.primaryText)
}
.listRowBackground(Color.cardBackground)

View file

@ -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<NSString*, NSString*>*)getAppListWithError:(NSError**)error;
@end

View file

@ -0,0 +1,125 @@
//
// JITEnableContext.m
// StikJIT
//
// Created by s s on 2025/3/28.
//
#include "idevice.h"
#include <arpa/inet.h>
#include <stdlib.h>
#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<NSString*, NSString*>*)getAppListWithError:(NSError**)error {
if(!provider) {
NSLog(@"Provider not initialized!");
*error = [self errorWithStr:@"Provider not initialized!" code:-1];
return nil;
}
NSString* errorStr = nil;
NSDictionary<NSString*, NSString*>* 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

View file

@ -1,145 +0,0 @@
//
// applist.c
// StikJIT
//
// Created by Stephen on 3/27/25.
//
#include "idevice.h"
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
#include <limits.h>
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;
}

View file

@ -7,7 +7,8 @@
#ifndef APPLIST_H
#define APPLIST_H
@import Foundation;
char *list_installed_apps(void);
NSDictionary<NSString*, NSString*>* list_installed_apps(TcpProviderHandle* provider, NSString** error);
#endif /* APPLIST_H */

86
StikJIT/idevice/applist.m Normal file
View file

@ -0,0 +1,86 @@
//
// applist.c
// StikJIT
//
// Created by Stephen on 3/27/25.
//
#include "idevice.h"
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "applist.h"
NSDictionary<NSString*, NSString*>* 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<NSString*, NSString*>* 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;
}

View file

@ -9,11 +9,11 @@
#include <sys/_types/_u_int64_t.h>
#include <CoreFoundation/CoreFoundation.h>
#include <limits.h>
#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.");
}
}

View file

@ -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 */

View file

@ -8,6 +8,9 @@
#include <sys/socket.h>
#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 */

View file

@ -17,92 +17,40 @@
#include <CoreFoundation/CoreFoundation.h>
#include <limits.h>
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;
}

View file

@ -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 */