Remove em_proxy, add pid support, fix alert position issue when app is not in fullscreen mode, remove get-task-allow alert and replace with "No Debuggable App Found" screen (#184)

This commit is contained in:
Huge_Black 2025-05-25 11:04:46 +08:00 • committed by GitHub
parent 61754b60cc
commit 1efae6001c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 508 additions and 245 deletions

View file

@ -50,7 +50,6 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
DC5716242D9564760099302E /* em_proxy.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = em_proxy.xcframework; sourceTree = "<group>"; };
DC6F1D372D94EADD0071B2B6 /* StikDebug.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StikDebug.app; sourceTree = BUILT_PRODUCTS_DIR; };
DC6F1D482D94EADF0071B2B6 /* StikDebugTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StikDebugTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
DC6F1D522D94EADF0071B2B6 /* StikDebugUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StikDebugUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@ -62,6 +61,7 @@
1775D3612D9644FD00DFA8E0 /* Exceptions for "StikJIT" folder in "StikDebug" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
idevice/libem_proxy.a,
Info.plist,
);
target = DC6F1D362D94EADD0071B2B6 /* StikDebug */;
@ -163,7 +163,6 @@
DC6F1D752D94EB620071B2B6 /* Frameworks */ = {
isa = PBXGroup;
children = (
DC5716242D9564760099302E /* em_proxy.xcframework */,
DCA690112DAF660E007C91A8 /* NetworkExtension.framework */,
);
name = Frameworks;

View file

@ -520,39 +520,32 @@ struct HeartbeatApp: App {
LoadingView(showAlert: $show_alert, alertTitle: $alert_title, alertMessage: $alert_string)
.onAppear {
dnsChecker.checkDNS()
startProxy() { result, error in
checkVPNConnection() { result, vpn_error in
if result {
checkVPNConnection() { result, vpn_error in
if result {
if FileManager.default.fileExists(atPath: URL.documentsDirectory.appendingPathComponent("pairingFile.plist").path) {
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in
if pubHeartBeat {
isLoading2 = false
timer.invalidate()
} else {
if let error {
if error == -9 { // InvalidHostID is -9
isPairing = true
} else {
startHeartbeatInBackground()
}
self.error = nil
}
}
}
startHeartbeatInBackground()
} else {
if FileManager.default.fileExists(atPath: URL.documentsDirectory.appendingPathComponent("pairingFile.plist").path) {
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in
if pubHeartBeat {
isLoading2 = false
}
} else if let vpn_error {
showAlert(title: "Error", message: "EM Proxy failed to connect: \(vpn_error)", showOk: true) { _ in
exit(0)
timer.invalidate()
} else {
if let error {
if error == -9 { // InvalidHostID is -9
isPairing = true
} else {
startHeartbeatInBackground()
}
self.error = nil
}
}
}
startHeartbeatInBackground()
} else {
isLoading2 = false
}
} else if let vpn_error {
showAlert(title: "Error", message: "EM Proxy failed to connect: \(vpn_error)", showOk: true) { _ in
exit(0)
}
} else if let error {
showAlert(title: "Error", message: "EM Proxy Failed to start \(error)", showOk: true) { _ in }
}
}
}
@ -658,24 +651,6 @@ struct HeartbeatApp: App {
}
}
func startProxy(callback: @escaping (Bool, Int?) -> Void) {
let port = 51820
let bindAddr = "127.0.0.1:\(port)"
DispatchQueue.global(qos: .background).async {
let result = start_emotional_damage(bindAddr)
DispatchQueue.main.async {
if result == 0 {
print("DEBUG: em_proxy started successfully on port \(port)")
callback(true, nil)
} else {
print("DEBUG: Failed to start em_proxy")
callback(false, Int(result))
}
}
}
}
private func checkVPNConnection(callback: @escaping (Bool, String?) -> Void) {
let host = NWEndpoint.Host("10.7.0.1")
let port = NWEndpoint.Port(rawValue: 62078)!
@ -948,10 +923,12 @@ struct LoadingView: View {
}
}
public func showAlert(title: String, message: String, showOk: Bool, showTryAgain: Bool = false, primaryButtonText: String? = nil, completion: @escaping (Bool) -> Void) {
public func showAlert(title: String, message: String, showOk: Bool, showTryAgain: Bool = false, primaryButtonText: String? = nil, messageType: MessageType = .error, completion: @escaping (Bool) -> Void) {
DispatchQueue.main.async {
let rootViewController = UIApplication.shared.windows.last?.rootViewController
guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
return
}
let rootViewController = scene.windows.first?.rootViewController
if showTryAgain {
let customErrorView = CustomErrorView(
title: title,
@ -964,7 +941,8 @@ public func showAlert(title: String, message: String, showOk: Bool, showTryAgain
primaryButtonText: primaryButtonText ?? "Try Again",
onPrimaryButtonTap: {
completion(true)
}
},
messageType: messageType
)
let hostingController = UIHostingController(rootView: customErrorView)
hostingController.modalPresentationStyle = .overFullScreen
@ -984,7 +962,8 @@ public func showAlert(title: String, message: String, showOk: Bool, showTryAgain
onPrimaryButtonTap: {
rootViewController?.presentedViewController?.dismiss(animated: true)
completion(true)
}
},
messageType: messageType
)
let hostingController = UIHostingController(rootView: customErrorView)
hostingController.modalPresentationStyle = .overFullScreen
@ -999,7 +978,8 @@ public func showAlert(title: String, message: String, showOk: Bool, showTryAgain
rootViewController?.presentedViewController?.dismiss(animated: true)
completion(false)
},
showButton: false
showButton: false,
messageType: messageType
)
let hostingController = UIHostingController(rootView: customErrorView)
hostingController.modalPresentationStyle = .overFullScreen

View file

@ -7,6 +7,12 @@
import SwiftUI
public enum MessageType {
case error
case success
case info
}
struct CustomErrorView: View {
var title: String
var message: String
@ -32,11 +38,6 @@ struct CustomErrorView: View {
}
}
enum MessageType {
case error
case success
case info
}
var body: some View {
ZStack {

View file

@ -33,8 +33,12 @@ struct HomeView: View {
@State private var showingConsoleLogsView = false
@State private var importProgress: Float = 0.0
@State private var pidTextAlertShow = false
@State private var pidStr = ""
@State private var viewDidAppeared = false
@State private var pendingBundleIdToEnableJIT : String? = nil
@State private var pendingPIDToEnableJIT : Int? = nil
private var accentColor: Color {
if customAccentColorHex.isEmpty {
@ -99,6 +103,27 @@ struct HomeView: View {
}
.padding(.horizontal, 20)
if pairingFileExists {
Button(action: {
pidTextAlertShow = true
}) {
HStack {
Image(systemName: "cable.connector.horizontal")
.font(.system(size: 20))
Text("Connect by PID")
.font(.system(.title3, design: .rounded))
.fontWeight(.semibold)
}
.frame(maxWidth: .infinity)
.padding()
.background(accentColor)
.foregroundColor(accentColor.contrastText())
.cornerRadius(16)
.shadow(color: accentColor.opacity(0.3), radius: 8, x: 0, y: 4)
}
.padding(.horizontal, 20)
}
Button(action: {
showingConsoleLogsView = true
}) {
@ -271,6 +296,28 @@ struct HomeView: View {
startJITInBackground(with: selectedBundle)
}
}
.textFieldAlert(
isPresented: $pidTextAlertShow,
title: "Please enter the PID of the process you want to connect to",
text: $pidStr,
placeholder: "",
action: { newText in
guard let pidStr = newText, pidStr != "" else {
return
}
guard let pid = Int(pidStr) else {
showAlert(title: "", message: "Invalid PID", showOk: true, completion: { _ in })
return
}
startJITInBackground(with: pid)
},
actionCancel: {_ in
pidStr = ""
}
)
.onOpenURL { url in
print(url.path())
if url.host() != "enable-jit" {
@ -284,6 +331,12 @@ struct HomeView: View {
} else {
pendingBundleIdToEnableJIT = bundleId
}
} else if let pidStr = components?.queryItems?.first(where: { $0.name == "pid" })?.value, let pid = Int(pidStr) {
if viewDidAppeared {
startJITInBackground(with: pid)
} else {
pendingPIDToEnableJIT = pid
}
}
}
@ -293,6 +346,10 @@ struct HomeView: View {
startJITInBackground(with: pendingBundleIdToEnableJIT)
self.pendingBundleIdToEnableJIT = nil
}
if let pendingPIDToEnableJIT {
startJITInBackground(with: pendingPIDToEnableJIT)
self.pendingPIDToEnableJIT = nil
}
}
}
@ -342,6 +399,34 @@ struct HomeView: View {
}
}
}
private func startJITInBackground(with pid: Int) {
isProcessing = true
// Add log message
LogManager.shared.addInfoLog("Starting JIT for pid \(pid)")
DispatchQueue.global(qos: .background).async {
let success = JITEnableContext.shared.debugApp(withPID: Int32(pid), logger: { message in
if let message = message {
// Log messages from the JIT process
LogManager.shared.addInfoLog(message)
}
})
DispatchQueue.main.async {
LogManager.shared.addInfoLog("JIT process completed for \(pid)")
showAlert(title: "Success", message: "JIT has been enabled for pid \(pid).", showOk: true, messageType: .success, completion: { _ in })
isProcessing = false
if success && doAutoQuitAfterEnablingJIT {
exit(0)
}
}
}
}
}
class InstalledAppsViewModel: ObservableObject {

View file

@ -15,47 +15,80 @@ struct InstalledAppsListView: View {
var onSelectApp: (String) -> Void
var body: some View {
NavigationView {
List {
if !recentApps.isEmpty {
Section {
ForEach(recentApps, id: \.self) { bundleID in
AppButton(bundleID: bundleID, appName: viewModel.apps[bundleID] ?? "", recentApps: $recentApps, appIcons: $appIcons, onSelectApp: onSelectApp)
.swipeActions(edge: .trailing) {
Button(role: .destructive) {
withAnimation {
recentApps.removeAll(where: { $0 == bundleID })
if viewModel.apps.isEmpty {
NavigationView {
VStack(spacing: 16) {
Image(systemName: "magnifyingglass")
.resizable()
.scaledToFit()
.frame(width: 60, height: 60)
.foregroundColor(.gray)
Text("No Debuggable App Found")
.font(.title2)
.fontWeight(.semibold)
.foregroundColor(.primary)
Text("StikDebug can only connect to apps with the \"**get-task-allow**\" entitlement. Please check if the app you want to connect to is signed with a **development** certificate.")
.font(.body)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(.systemBackground))
.toolbar(content: {
Button("Done") {
dismiss()
}
})
}
} else {
NavigationView {
List {
if !recentApps.isEmpty {
Section {
ForEach(recentApps, id: \.self) { bundleID in
AppButton(bundleID: bundleID, appName: viewModel.apps[bundleID] ?? "", recentApps: $recentApps, appIcons: $appIcons, onSelectApp: onSelectApp)
.swipeActions(edge: .trailing) {
Button(role: .destructive) {
withAnimation {
recentApps.removeAll(where: { $0 == bundleID })
}
} label: {
Label("Delete", systemImage: "trash")
}
} label: {
Label("Delete", systemImage: "trash")
}
}
}
} header: {
Text("Recents")
}
}
Section {
ForEach(viewModel.apps.sorted(by: { $0.key < $1.key }), id: \.key) { bundleID, appName in
AppButton(bundleID: bundleID, appName: appName, recentApps: $recentApps, appIcons: $appIcons, onSelectApp: onSelectApp)
}
} header: {
Text("Recents")
if !recentApps.isEmpty {
Text("All applications")
} else {
EmptyView()
}
}
}
Section {
ForEach(viewModel.apps.sorted(by: { $0.key < $1.key }), id: \.key) { bundleID, appName in
AppButton(bundleID: bundleID, appName: appName, recentApps: $recentApps, appIcons: $appIcons, onSelectApp: onSelectApp)
.listStyle(.plain)
.navigationTitle("Installed Apps")
.toolbar(content: {
Button("Done") {
dismiss()
}
} header: {
if !recentApps.isEmpty {
Text("All applications")
} else {
EmptyView()
}
}
})
}
.listStyle(.plain)
.navigationTitle("Installed Apps")
.toolbar(content: {
Button("Done") {
dismiss()
}
})
.background(Color(UIColor.systemGroupedBackground).edgesIgnoringSafeArea(.all))
}
.background(Color(UIColor.systemGroupedBackground).edgesIgnoringSafeArea(.all))
}
}

View file

@ -12,7 +12,7 @@ struct SettingsView: View {
@AppStorage("customAccentColor") private var customAccentColorHex: String = ""
@AppStorage("selectedAppIcon") private var selectedAppIcon: String = "AppIcon"
@AppStorage("autoQuitAfterEnablingJIT") private var doAutoQuitAfterEnablingJIT = false
@AppStorage("skipGetTaskAllowCheck") private var doSkipGetTaskAllowCheck = true
@State private var isShowingPairingFilePicker = false
@Environment(\.colorScheme) private var colorScheme
@ -119,21 +119,6 @@ struct SettingsView: View {
.padding(.horizontal, 16)
}
// Behavior section
SettingsCard {
VStack(alignment: .leading, spacing: 20) {
Text("Behavior")
.font(.headline)
.foregroundColor(.primary)
.padding(.bottom, 4)
Toggle("Skip get-task-allow Check", isOn: $doSkipGetTaskAllowCheck)
.foregroundColor(.primary)
.padding(.vertical, 6)
}
.padding(.vertical, 20)
.padding(.horizontal, 16)
}
// Pairing File section
SettingsCard {
VStack(alignment: .leading, spacing: 20) {

View file

@ -0,0 +1,77 @@
//
// TextAlert.swift
// StikJIT
//
// Created by s s on 2025/5/11.
//
import SwiftUI
import UIKit
public struct TextFieldAlertModifier: ViewModifier {
@State private var alertController: UIAlertController?
@Binding var isPresented: Bool
let title: String
let text: Binding<String>
let placeholder: String
let action: (String?) -> Void
let actionCancel: (String?) -> Void
public func body(content: Content) -> some View {
content.onChange(of: isPresented) { isPresented in
if isPresented, alertController == nil {
let alertController = makeAlertController()
self.alertController = alertController
guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
return
}
scene.windows.first?.rootViewController?.present(alertController, animated: true)
} else if !isPresented, let alertController = alertController {
alertController.dismiss(animated: true)
self.alertController = nil
}
}
}
private func makeAlertController() -> UIAlertController {
let controller = UIAlertController(title: title, message: nil, preferredStyle: .alert)
controller.addTextField {
$0.placeholder = self.placeholder
$0.text = self.text.wrappedValue
$0.clearButtonMode = .always
}
controller.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
self.actionCancel(nil)
shutdown()
})
controller.addAction(UIAlertAction(title: "OK", style: .default) { _ in
self.action(controller.textFields?.first?.text)
shutdown()
})
return controller
}
private func shutdown() {
isPresented = false
alertController = nil
}
}
extension View {
public func textFieldAlert(
isPresented: Binding<Bool>,
title: String,
text: Binding<String>,
placeholder: String = "",
action: @escaping (String?) -> Void,
actionCancel: @escaping (String?) -> Void
) -> some View {
self.modifier(TextFieldAlertModifier(isPresented: isPresented, title: title, text: text, placeholder: placeholder, action: action, actionCancel: actionCancel))
}
}

View file

@ -17,6 +17,7 @@ typedef void (^LogFunc)(NSString *message);
- (IdevicePairingFile*)getPairingFileWithError:(NSError**)error;
- (void)startHeartbeatWithCompletionHandler:(HeartbeatCompletionHandler)completionHandler logger:(LogFunc)logger;
- (BOOL)debugAppWithBundleID:(NSString*)bundleID logger:(LogFunc)logger;
- (BOOL)debugAppWithPID:(int)pid logger:(LogFunc)logger;
- (NSDictionary<NSString*, NSString*>*)getAppListWithError:(NSError**)error;
- (UIImage*)getAppIconWithBundleId:(NSString*)bundleId error:(NSError**)error;
@end

View file

@ -4,7 +4,6 @@
//
// Created by s s on 2025/3/28.
//
#include "idevice.h"
#include <arpa/inet.h>
#include <stdlib.h>
@ -134,6 +133,19 @@ JITEnableContext* sharedJITContext = nil;
[self createCLogger:logger]) == 0;
}
- (BOOL)debugAppWithPID:(int)pid logger:(LogFunc)logger {
if (!provider) {
if (logger) {
logger(@"Provider not initialized!");
}
NSLog(@"Provider not initialized!");
return NO;
}
return debug_app_pid(provider,
pid,
[self createCLogger:logger]) == 0;
}
- (NSDictionary<NSString*, NSString*>*)getAppListWithError:(NSError**)error {
if (!provider) {
NSLog(@"Provider not initialized!");

View file

@ -263,3 +263,229 @@ int debug_app(TcpProviderHandle* tcp_provider, const char *bundle_id, LogFuncC l
logger("Debug session completed");
return 0;
}
int debug_app_pid(TcpProviderHandle* tcp_provider, int pid, LogFuncC logger) {
// Connect to CoreDeviceProxy
CoreDeviceProxyHandle *core_device = NULL;
IdeviceErrorCode err = core_device_proxy_connect_tcp(tcp_provider, &core_device);
if (err != IdeviceSuccess) {
logger("Failed to connect to CoreDeviceProxy: %d", err);
return 1;
}
// Get server RSD port
uint16_t rsd_port;
err = core_device_proxy_get_server_rsd_port(core_device, &rsd_port);
if (err != IdeviceSuccess) {
logger("Failed to get server RSD port: %d", err);
core_device_proxy_free(core_device);
return 1;
}
logger("Server RSD Port: %d", rsd_port);
/*****************************************************************
* Create TCP Tunnel Adapter
*****************************************************************/
logger("=== Creating TCP Tunnel Adapter ===");
AdapterHandle *adapter = NULL;
err = core_device_proxy_create_tcp_adapter(core_device, &adapter);
if (err != IdeviceSuccess) {
logger("Failed to create TCP adapter: %d", err);
core_device_proxy_free(core_device);
return 1;
}
// Connect to RSD port
err = adapter_connect(adapter, rsd_port);
if (err != IdeviceSuccess) {
logger("Failed to connect to RSD port: %d", err);
adapter_free(adapter);
return 1;
}
logger("Successfully connected to RSD port");
/*****************************************************************
* XPC Device Setup
*****************************************************************/
logger("=== Setting up XPC Device ===");
XPCDeviceAdapterHandle *xpc_device = NULL;
err = xpc_device_new(adapter, &xpc_device);
if (err != IdeviceSuccess) {
logger("Failed to create XPC device: %d", err);
adapter_free(adapter);
return 1;
}
// Get DebugProxy service
XPCServiceHandle *debug_service = NULL;
err = xpc_device_get_service(xpc_device, "com.apple.internal.dt.remote.debugproxy", &debug_service);
if (err != IdeviceSuccess) {
logger("Failed to get debug proxy service: %d", err);
xpc_device_free(xpc_device);
return 1;
}
// Get ProcessControl service
XPCServiceHandle *pc_service = NULL;
err = xpc_device_get_service(xpc_device, "com.apple.instruments.dtservicehub", &pc_service);
if (err != IdeviceSuccess) {
logger("Failed to get process control service: %d", err);
xpc_device_free(xpc_device);
return 1;
}
/*****************************************************************
* Process Control - Launch App
*****************************************************************/
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) {
logger("Failed to extract adapter: %d", err);
xpc_device_free(xpc_device);
return 1;
}
// Connect to process control port
err = adapter_connect(pc_adapter, pc_service->port);
if (err != IdeviceSuccess) {
logger("Failed to connect to process control port: %d", err);
adapter_free(pc_adapter);
xpc_service_free(pc_service);
xpc_service_free(debug_service);
return 1;
}
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) {
logger("Failed to create remote server: %d", err);
adapter_free(pc_adapter);
xpc_service_free(pc_service);
xpc_service_free(debug_service);
return 1;
}
// Create ProcessControlClient
ProcessControlAdapterHandle *process_control = NULL;
err = process_control_new(remote_server, &process_control);
if (err != IdeviceSuccess) {
logger("Failed to create process control client: %d", err);
remote_server_free(remote_server);
xpc_service_free(pc_service);
xpc_service_free(debug_service);
return 1;
}
// Disable memory limit for PID
err = process_control_disable_memory_limit(process_control, pid);
if (err != IdeviceSuccess) {
logger("failed to disable memory limit: %d", err);
}
/*****************************************************************
* Debug Proxy - Attach to Process
*****************************************************************/
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) {
logger("Failed to extract adapter: %d", err);
xpc_service_free(debug_service);
process_control_free(process_control);
remote_server_free(remote_server);
xpc_service_free(pc_service);
return 1;
}
// Connect to debug proxy port
err = adapter_connect(debug_adapter, debug_service->port);
if (err != IdeviceSuccess) {
logger("Failed to connect to debug proxy port: %d", err);
adapter_free(debug_adapter);
xpc_service_free(debug_service);
process_control_free(process_control);
remote_server_free(remote_server);
xpc_service_free(pc_service);
return 1;
}
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) {
logger("Failed to create debug proxy client: %d", err);
adapter_free(debug_adapter);
xpc_service_free(debug_service);
process_control_free(process_control);
remote_server_free(remote_server);
xpc_service_free(pc_service);
return 1;
}
// Send vAttach command with PID in hex
char attach_command[64];
snprintf(attach_command, sizeof(attach_command), "vAttach;%" PRIx64, pid);
DebugserverCommandHandle *attach_cmd = debugserver_command_new(attach_command, NULL, 0);
if (attach_cmd == NULL) {
logger("Failed to create attach command");
debug_proxy_free(debug_proxy);
xpc_service_free(debug_service);
process_control_free(process_control);
remote_server_free(remote_server);
xpc_service_free(pc_service);
return 1;
}
char *attach_response = NULL;
err = debug_proxy_send_command(debug_proxy, attach_cmd, &attach_response);
debugserver_command_free(attach_cmd);
if (err != IdeviceSuccess) {
logger("Failed to attach to process: %d", err);
} else if (attach_response != NULL) {
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) {
logger("Failed to create detach command");
} else {
char *detach_response = NULL;
err = debug_proxy_send_command(debug_proxy, detach_cmd, &detach_response);
err = debug_proxy_send_command(debug_proxy, detach_cmd, &detach_response);
err = debug_proxy_send_command(debug_proxy, detach_cmd, &detach_response);
debugserver_command_free(detach_cmd);
if (err != IdeviceSuccess) {
logger("Failed to detach from process: %d", err);
} else if (detach_response != NULL) {
logger("Detach response: %s", detach_response);
idevice_string_free(detach_response);
}
}
/*****************************************************************
* Cleanup
*****************************************************************/
debug_proxy_free(debug_proxy);
xpc_service_free(debug_service);
xpc_service_free(pc_service);
logger("Debug session completed");
return 0;
}

View file

@ -12,5 +12,6 @@
typedef void (^LogFuncC)(const char* message, ...);
int debug_app(TcpProviderHandle* provider, const char *bundle_id, LogFuncC logger);
int debug_app_pid(TcpProviderHandle* provider, int pid, LogFuncC logger);
#endif /* JIT_H */

View file

@ -1,47 +0,0 @@
<?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>AvailableLibraries</key>
<array>
<dict>
<key>BinaryPath</key>
<string>libem_proxy.a</string>
<key>HeadersPath</key>
<string>Headers</string>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>libem_proxy.a</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>libem_proxy.a</string>
<key>HeadersPath</key>
<string>Headers</string>
<key>LibraryIdentifier</key>
<string>ios-arm64-simulator</string>
<key>LibraryPath</key>
<string>libem_proxy.a</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
</array>
<key>CFBundlePackageType</key>
<string>XFWK</string>
<key>XCFrameworkFormatVersion</key>
<string>1.0</string>
</dict>
</plist>

View file

@ -1,40 +0,0 @@
// Jackson Coxson
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
/**
* Starts your emotional damage
* # Arguments
* * `bind_addr` - The UDP socket to listen to
* # Returns
* A handle to stop further emotional damage.
* Null on failure
* # Safety
* Don't be stupid
*/
int start_emotional_damage(const char *bind_addr);
/**
* Stops further emotional damage
* # Arguments
* * `handle` - The coping mechanism generated by start_emotional_damage
* # Returns
* The knowledge of knowing that you couldn't handle failure
* # Safety
* Don't be stupid
*/
void stop_emotional_damage(void);
/**
* Blocks until Wireguard is ready
* # Arguments
* * `timeout` - The timeout in miliseconds to wait for Wireguard
* # Returns
* 0 on success, -1 on failure
*/
int test_emotional_damage(int timeout);

View file

@ -1,5 +0,0 @@
module em_proxy {
header "em_proxy.h"
export *
}

View file

@ -1,40 +0,0 @@
// Jackson Coxson
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
/**
* Starts your emotional damage
* # Arguments
* * `bind_addr` - The UDP socket to listen to
* # Returns
* A handle to stop further emotional damage.
* Null on failure
* # Safety
* Don't be stupid
*/
int start_emotional_damage(const char *bind_addr);
/**
* Stops further emotional damage
* # Arguments
* * `handle` - The coping mechanism generated by start_emotional_damage
* # Returns
* The knowledge of knowing that you couldn't handle failure
* # Safety
* Don't be stupid
*/
void stop_emotional_damage(void);
/**
* Blocks until Wireguard is ready
* # Arguments
* * `timeout` - The timeout in miliseconds to wait for Wireguard
* # Returns
* 0 on success, -1 on failure
*/
int test_emotional_damage(int timeout);

View file

@ -1,5 +0,0 @@
module em_proxy {
header "em_proxy.h"
export *
}