mirror of
https://github.com/StikDebug/StikDebug.git
synced 2026-10-15 20:10:30 +00:00
Compare commits
12 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1256c52803 | ||
|
|
3422fc4725 | ||
|
|
734361bb9d | ||
|
|
cd5e609387 | ||
|
|
e4665d74b5 | ||
|
|
300ebff50b | ||
|
|
775fba15f3 | ||
|
|
871f1461d9 | ||
|
|
4bdfc92aa7 | ||
|
|
4b3c8d6e88 | ||
| c03abcaa44 | |||
|
|
d4306e724b |
7 changed files with 73 additions and 76 deletions
35
README.md
35
README.md
|
|
@ -7,24 +7,17 @@
|
||||||
<p><i>An on-device debugger/JIT enabler for iOS versions 17.4+ powered by <a href="https://github.com/jkcoxson/idevice">idevice</a>.</i></p>
|
<p><i>An on-device debugger/JIT enabler for iOS versions 17.4+ powered by <a href="https://github.com/jkcoxson/idevice">idevice</a>.</i></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h6 align="center">
|
<h3 align="center">
|
||||||
<a href="https://discord.gg/ZnNcrRT3M8">
|
<a href="https://discord.gg/ZnNcrRT3M8"><img src="https://img.shields.io/badge/Discord-join%20us-7289DA?logo=discord&logoColor=white&style=for-the-badge&labelColor=23272A" /></a>
|
||||||
<img src="https://img.shields.io/badge/Discord-join%20us-7289DA?logo=discord&logoColor=white&style=for-the-badge&labelColor=23272A" />
|
<a href="https://github.com/StikDebug/StikDebug/blob/main/LICENSE"><img src="https://img.shields.io/github/license/StikDebug/StikDebug?label=License&color=5865F2&style=for-the-badge&labelColor=23272A" /></a>
|
||||||
</a>
|
<a href="https://github.com/StikDebug/StikDebug"><img src="https://img.shields.io/github/stars/StikDebug/StikDebug?label=Stars&color=FEE75C&style=for-the-badge&labelColor=23272A" /></a>
|
||||||
<a href="https://github.com/StikDebug/StikDebug/blob/main/LICENSE">
|
<a href="https://github.com/StikDebug/StikDebug/releases"><img src="https://img.shields.io/github/v/release/StikDebug/StikDebug?label=Latest&color=00BFFF&style=for-the-badge&labelColor=23272A" /></a>
|
||||||
<img src="https://img.shields.io/github/license/StikDebug/StikDebug?label=License&color=5865F2&style=for-the-badge&labelColor=23272A" />
|
<a href="https://deepwiki.com/StikDebug/StikDebug"><img src="https://img.shields.io/badge/Ask-DeepWiki-grey?style=for-the-badge&labelColor=23272A&color=007ec6" /></a>
|
||||||
</a>
|
<br />
|
||||||
<a href="https://github.com/StikDebug/StikDebug/stargazers">
|
</h3>
|
||||||
<img src="https://img.shields.io/github/stars/StikDebug/StikDebug?label=Stars&color=FEE75C&style=for-the-badge&labelColor=23272A" />
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/StikDebug/StikDebug/releases">
|
|
||||||
<img src="https://img.shields.io/github/v/release/StikDebug/StikDebug?label=Latest&color=00BFFF&style=for-the-badge&labelColor=23272A" />
|
|
||||||
</a>
|
|
||||||
<br />
|
|
||||||
</h6>
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- **JIT:** Enable Just In Time compilation for sideloaded apps that have the `get-task-allow` entitlement.
|
- **JIT:** Enable Just-In-Time compilation for sideloaded apps that have the `get-task-allow` entitlement.
|
||||||
- **App Launching:** Launch every app installed on your device.
|
- **App Launching:** Launch every app installed on your device.
|
||||||
- **Console:** Live app and system logs.
|
- **Console:** Live app and system logs.
|
||||||
- **Scripts:** Manage automation scripts (mainly used for iOS 26 JIT).
|
- **Scripts:** Manage automation scripts (mainly used for iOS 26 JIT).
|
||||||
|
|
@ -40,7 +33,7 @@
|
||||||
<h3 align="center">
|
<h3 align="center">
|
||||||
<a href="https://altdirect.app/?url=https://stikdebug.xyz/index.json" target="_blank"><img src="https://altdirect.app/assets/png/AltSource_Blue.png" alt="Add AltSource" width="200"></a>
|
<a href="https://altdirect.app/?url=https://stikdebug.xyz/index.json" target="_blank"><img src="https://altdirect.app/assets/png/AltSource_Blue.png" alt="Add AltSource" width="200"></a>
|
||||||
|
|
||||||
<a href="https://github.com/StikDebug/StikDebug/releases/download/3.1.9/StikDebug-3.1.9.ipa" target="_blank"><img src="https://altdirect.app/assets/png/Download_Blue.png" alt="Download .ipa" width="200"></a>
|
<a href="https://github.com/StikDebug/StikDebug/releases/latest/download/StikDebug-3.1.15.ipa" target="_blank"><img src="https://altdirect.app/assets/png/Download_Blue.png" alt="Download .ipa" width="200"></a>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
@ -69,12 +62,12 @@ StikDebug enables **JIT** for sideloaded apps on iOS 17.4+ without needing a com
|
||||||
- Launch LocalDevVPN and enable the VPN.
|
- Launch LocalDevVPN and enable the VPN.
|
||||||
|
|
||||||
4. **Enable JIT for an app**
|
4. **Enable JIT for an app**
|
||||||
- Launch StikDebug and tapp the `Enable JIT` button.
|
- Launch StikDebug and tap the `Enable JIT` button.
|
||||||
- Select your sideloaded app from the list in StikDebug.
|
- Select your sideloaded app from the list in StikDebug.
|
||||||
|
|
||||||
**Troubleshooting**
|
**Troubleshooting**
|
||||||
- "Connection dropped" or loopback errors → Check iOS version compatibility / beta warnings.
|
- "Connection dropped" or loopback errors → Check iOS version compatibility / beta warnings.
|
||||||
- Heartbeat errors → Ensure that the VPN is on and that you are connecected to Wi-Fi. It may be a pairing file issue.
|
- Heartbeat errors → Ensure that the VPN is on and that you are connected to Wi-Fi. It may be a pairing file issue.
|
||||||
- Pairing file issues → Replace file with device unlocked & trusted.
|
- Pairing file issues → Replace file with device unlocked & trusted.
|
||||||
- Still stuck? Join the [Discord](https://discord.gg/ZnNcrRT3M8) with logs/screenshots.
|
- Still stuck? Join the [Discord](https://discord.gg/ZnNcrRT3M8) with logs/screenshots.
|
||||||
|
|
||||||
|
|
@ -147,13 +140,11 @@ To propose a new feature, open a feature request issue and provide:
|
||||||
|
|
||||||
### Code Contributions (Best Practices)
|
### Code Contributions (Best Practices)
|
||||||
- Follow normal Swift and SwiftUI style.
|
- Follow normal Swift and SwiftUI style.
|
||||||
- Write clear and easy to understand code.
|
- Write clear and easy-to-understand code.
|
||||||
- Keep your changes consistent with how the project is already set up.
|
- Keep your changes consistent with how the project is already set up.
|
||||||
- Make sure everything builds and works without errors.
|
- Make sure everything builds and works without errors.
|
||||||
|
|
||||||
We appreciate your time and effort in helping improve this project.
|
We appreciate your time and effort in helping improve this project.
|
||||||
|
|
||||||
## Code Help
|
|
||||||
[](https://deepwiki.com/StikDebug/stikdebug)
|
|
||||||
## License
|
## License
|
||||||
StikDebug is licensed under **AGPL-3.0**. See [`LICENSE`](LICENSE) for details.
|
StikDebug is licensed under **AGPL-3.0**. See [`LICENSE`](LICENSE) for details.
|
||||||
|
|
|
||||||
|
|
@ -482,7 +482,7 @@
|
||||||
"$(PROJECT_DIR)/StikDebug/idevice",
|
"$(PROJECT_DIR)/StikDebug/idevice",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 15.1;
|
MACOSX_DEPLOYMENT_TARGET = 15.1;
|
||||||
MARKETING_VERSION = 3.1.12;
|
MARKETING_VERSION = 3.1.15;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stik.stikdebug;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stik.stikdebug;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
|
@ -544,7 +544,7 @@
|
||||||
"$(PROJECT_DIR)/StikDebug/idevice",
|
"$(PROJECT_DIR)/StikDebug/idevice",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 15.1;
|
MACOSX_DEPLOYMENT_TARGET = 15.1;
|
||||||
MARKETING_VERSION = 3.1.12;
|
MARKETING_VERSION = 3.1.15;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stik.stikdebug;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stik.stikdebug;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ private enum IdeviceBridge {
|
||||||
}
|
}
|
||||||
|
|
||||||
let code = Int(ffiError.pointee.code)
|
let code = Int(ffiError.pointee.code)
|
||||||
let message = string(from: ffiError.pointee.message) ?? fallback
|
let detail = string(from: ffiError.pointee.message) ?? fallback
|
||||||
|
let message = detail == fallback ? fallback : "\(fallback): \(detail)"
|
||||||
idevice_error_free(ffiError)
|
idevice_error_free(ffiError)
|
||||||
return makeError(domain: domain, code: code, message: message)
|
return makeError(domain: domain, code: code, message: message)
|
||||||
}
|
}
|
||||||
|
|
@ -264,45 +265,50 @@ private enum IdeviceBridge {
|
||||||
extension JITEnableContext {
|
extension JITEnableContext {
|
||||||
func isDeveloperDiskImageMounted() throws -> Bool {
|
func isDeveloperDiskImageMounted() throws -> Bool {
|
||||||
try IdeviceBridge.withTunnelHandles(for: self) { adapter, handshake in
|
try IdeviceBridge.withTunnelHandles(for: self) { adapter, handshake in
|
||||||
var installed: UnsafeMutablePointer<InstalledCryptexC>?
|
var cryptexQuerySucceeded = false
|
||||||
let ffiError = cryptexd_installed_ddi(adapter, handshake, &installed)
|
var cryptexQueryError: NSError?
|
||||||
let queryError = ffiError.map {
|
if DeveloperDiskImageService.usesCryptexDDI {
|
||||||
IdeviceBridge.consumeFFIError($0, fallback: "Failed to query installed DDI cryptex")
|
var installed: UnsafeMutablePointer<InstalledCryptexC>?
|
||||||
}
|
defer { cryptexd_free_installed_cryptex(installed) }
|
||||||
defer { cryptexd_free_installed_cryptex(installed) }
|
if let ffiError = cryptexd_installed_ddi(adapter, handshake, &installed) {
|
||||||
if installed != nil {
|
cryptexQueryError = IdeviceBridge.consumeFFIError(ffiError, fallback: "Failed to query installed DDI cryptex")
|
||||||
return true
|
} else {
|
||||||
|
cryptexQuerySucceeded = true
|
||||||
|
if installed != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let legacyMounted = (try? IdeviceBridge.withConnectedClient(
|
do {
|
||||||
fallback: "Failed to connect to image mounter",
|
return try IdeviceBridge.withConnectedClient(
|
||||||
missingClientMessage: "Image mounter client was not created",
|
fallback: "Failed to connect to image mounter",
|
||||||
connect: { image_mounter_connect_rsd(adapter, handshake, $0) },
|
missingClientMessage: "Image mounter client was not created",
|
||||||
cleanup: { image_mounter_free($0) }
|
connect: { image_mounter_connect_rsd(adapter, handshake, $0) },
|
||||||
) { client in
|
cleanup: { image_mounter_free($0) }
|
||||||
var devices: UnsafeMutablePointer<plist_t?>?
|
) { client in
|
||||||
var deviceCount = 0
|
var devices: UnsafeMutablePointer<plist_t?>?
|
||||||
if let error = image_mounter_copy_devices(client, &devices, &deviceCount) {
|
var deviceCount = 0
|
||||||
throw IdeviceBridge.consumeFFIError(error, fallback: "Failed to fetch mounted devices")
|
if let error = image_mounter_copy_devices(client, &devices, &deviceCount) {
|
||||||
}
|
throw IdeviceBridge.consumeFFIError(error, fallback: "Failed to fetch mounted devices")
|
||||||
if let devices {
|
|
||||||
for index in 0..<deviceCount {
|
|
||||||
plist_free(devices[index])
|
|
||||||
}
|
}
|
||||||
idevice_data_free(
|
if let devices {
|
||||||
UnsafeMutableRawPointer(devices).assumingMemoryBound(to: UInt8.self),
|
for index in 0..<deviceCount {
|
||||||
UInt(deviceCount * MemoryLayout<plist_t?>.stride)
|
plist_free(devices[index])
|
||||||
)
|
}
|
||||||
|
idevice_data_free(
|
||||||
|
UnsafeMutableRawPointer(devices).assumingMemoryBound(to: UInt8.self),
|
||||||
|
UInt(deviceCount * MemoryLayout<plist_t?>.stride)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return deviceCount > 0
|
||||||
}
|
}
|
||||||
return deviceCount > 0
|
} catch {
|
||||||
}) ?? false
|
if cryptexQuerySucceeded {
|
||||||
if legacyMounted {
|
return false
|
||||||
return true
|
}
|
||||||
|
throw cryptexQueryError ?? (error as NSError)
|
||||||
}
|
}
|
||||||
if let queryError {
|
|
||||||
throw queryError
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,8 @@ final class JITEnableContext {
|
||||||
guard let ffiError else {
|
guard let ffiError else {
|
||||||
return makeError(fallback)
|
return makeError(fallback)
|
||||||
}
|
}
|
||||||
let message = nsString(from: ffiError.pointee.message, fallback: fallback)
|
let detail = nsString(from: ffiError.pointee.message, fallback: fallback)
|
||||||
|
let message = detail == fallback ? fallback : "\(fallback): \(detail)"
|
||||||
let error = makeError(message, code: Int(ffiError.pointee.code))
|
let error = makeError(message, code: Int(ffiError.pointee.code))
|
||||||
idevice_error_free(ffiError)
|
idevice_error_free(ffiError)
|
||||||
return error
|
return error
|
||||||
|
|
@ -457,22 +458,19 @@ final class JITEnableContext {
|
||||||
private func withConnectedRemoteServer<T>(
|
private func withConnectedRemoteServer<T>(
|
||||||
_ body: (OpaquePointer) throws -> T
|
_ body: (OpaquePointer) throws -> T
|
||||||
) throws -> T {
|
) throws -> T {
|
||||||
try ensureTunnel()
|
try withFreshDebugTunnel(hostname: "StikDebugRemoteServer") { adapter, handshake in
|
||||||
guard let adapter, let handshake else {
|
var remoteServer: OpaquePointer?
|
||||||
throw makeError("Tunnel is not connected")
|
if let ffiError = remote_server_connect_rsd(adapter, handshake, &remoteServer) {
|
||||||
}
|
throw error(from: ffiError, fallback: "Failed to connect remote server")
|
||||||
|
}
|
||||||
|
|
||||||
var remoteServer: OpaquePointer?
|
guard let remoteServer else {
|
||||||
if let ffiError = remote_server_connect_rsd(adapter, handshake, &remoteServer) {
|
throw makeError("Remote server handle was not created")
|
||||||
throw error(from: ffiError, fallback: "Failed to connect remote server")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
guard let remoteServer else {
|
defer { remote_server_free(remoteServer) }
|
||||||
throw makeError("Remote server handle was not created")
|
return try body(remoteServer)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer { remote_server_free(remoteServer) }
|
|
||||||
return try body(remoteServer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func withProcessControl<T>(
|
private func withProcessControl<T>(
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ func checkMountStatus() -> MountCheckResult {
|
||||||
do {
|
do {
|
||||||
return try JITEnableContext.shared.isDeveloperDiskImageMounted() ? .mounted : .notMounted
|
return try JITEnableContext.shared.isDeveloperDiskImageMounted() ? .mounted : .notMounted
|
||||||
} catch {
|
} catch {
|
||||||
|
LogManager.shared.addErrorLog("Failed to check DDI mount status: \(error.localizedDescription)")
|
||||||
return .unreachable
|
return .unreachable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ extension ScriptStore {
|
||||||
"Amethyst",
|
"Amethyst",
|
||||||
"MeloNX",
|
"MeloNX",
|
||||||
"XeniOS",
|
"XeniOS",
|
||||||
"MeloCafe",
|
"MeloCafé",
|
||||||
"Manic EMU",
|
"Manic EMU",
|
||||||
"DukeX",
|
"DukeX",
|
||||||
"TachyonU",
|
"TachyonU",
|
||||||
|
|
@ -23,7 +23,8 @@ extension ScriptStore {
|
||||||
"HyperHLE",
|
"HyperHLE",
|
||||||
"Applesauce",
|
"Applesauce",
|
||||||
"RPCS3",
|
"RPCS3",
|
||||||
"AetherPS4"
|
"AetherPS4",
|
||||||
|
"Husk"
|
||||||
],
|
],
|
||||||
resource: ScriptResource(resourceName: "universal", fileName: "universal.js")
|
resource: ScriptResource(resourceName: "universal", fileName: "universal.js")
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import SwiftUI
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
private enum SettingsLinks {
|
private enum SettingsLinks {
|
||||||
static let githubStars = URL(string: "https://github.com/StikDebug/StikDebug/stargazers")!
|
static let githubStars = URL(string: "https://github.com/StikDebug/StikDebug")!
|
||||||
static let pairingFileGuide = URL(string: "https://github.com/StikDebug/StikDebug-Guide/blob/main/pairing_file.md")!
|
static let pairingFileGuide = URL(string: "https://github.com/StikDebug/StikDebug-Guide/blob/main/pairing_file.md")!
|
||||||
static let localDevVPN = URL(string: "https://apps.apple.com/us/app/localdevvpn/id6755608044")!
|
static let localDevVPN = URL(string: "https://apps.apple.com/us/app/localdevvpn/id6755608044")!
|
||||||
static let discord = URL(string: "https://discord.gg/qahjXNTDwS")!
|
static let discord = URL(string: "https://discord.gg/qahjXNTDwS")!
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue