[AltServer] Handles EnableUnsignedCodeExecutionRequest

Allows sideloaded apps to connect to AltServer and enable JIT execution.
This commit is contained in:
Riley Testut
2021-06-04 13:01:42 -07:00
parent 07ef7ae18f
commit e0b50ac80c
5 changed files with 105 additions and 3 deletions

View File

@@ -16,6 +16,7 @@ NS_SWIFT_NAME(DebugConnection)
@property (nonatomic, copy, readonly) ALTDevice *device;
- (void)enableUnsignedCodeExecutionForProcessWithName:(NSString *)processName completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler;
- (void)enableUnsignedCodeExecutionForProcessWithID:(NSInteger)pid completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler;
- (void)disconnect;

View File

@@ -96,12 +96,36 @@ char *bin2hex(const unsigned char *bin, size_t length)
}
- (void)enableUnsignedCodeExecutionForProcessWithName:(NSString *)processName completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler
{
[self _enableUnsignedCodeExecutionForProcessWithName:processName pid:0 completionHandler:completionHandler];
}
- (void)enableUnsignedCodeExecutionForProcessWithID:(NSInteger)pid completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler
{
[self _enableUnsignedCodeExecutionForProcessWithName:nil pid:(int32_t)pid completionHandler:completionHandler];
}
- (void)_enableUnsignedCodeExecutionForProcessWithName:(nullable NSString *)processName pid:(int32_t)pid completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler
{
dispatch_async(self.connectionQueue, ^{
NSString *localizedFailure = [NSString stringWithFormat:NSLocalizedString(@"JIT could not be enabled for %@.", comment: @""), processName];
NSString *name = processName ?: NSLocalizedString(@"this app", @"");
NSString *localizedFailure = [NSString stringWithFormat:NSLocalizedString(@"JIT could not be enabled for %@.", comment: @""), name];
NSString *encodedName = @(bin2hex((const unsigned char *)processName.UTF8String, (size_t)strlen(processName.UTF8String)));
NSString *attachCommand = [NSString stringWithFormat:@"vAttachName;%@", encodedName];
NSString *attachCommand = nil;
if (processName)
{
NSString *encodedName = @(bin2hex((const unsigned char *)processName.UTF8String, (size_t)strlen(processName.UTF8String)));
attachCommand = [NSString stringWithFormat:@"vAttachName;%@", encodedName];
}
else
{
// Convert to Big-endian.
int32_t rawPID = CFSwapInt32HostToBig(pid);
NSString *encodedName = @(bin2hex((const unsigned char *)&rawPID, 4));
attachCommand = [NSString stringWithFormat:@"vAttach;%@", encodedName];
}
NSError *error = nil;
if (![self sendCommand:attachCommand arguments:nil error:&error])

View File

@@ -143,6 +143,37 @@ struct ServerRequestHandler: RequestHandler
}
}
}
func handleEnableUnsignedCodeExecutionRequest(_ request: EnableUnsignedCodeExecutionRequest, for connection: Connection, completionHandler: @escaping (Result<EnableUnsignedCodeExecutionResponse, Error>) -> Void)
{
guard let device = ALTDeviceManager.shared.availableDevices.first(where: { $0.identifier == request.udid }) else { return completionHandler(.failure(ALTServerError(.deviceNotFound))) }
ALTDeviceManager.shared.prepare(device) { result in
switch result
{
case .failure(let error): completionHandler(.failure(error))
case .success:
ALTDeviceManager.shared.startDebugConnection(to: device) { (connection, error) in
guard let connection = connection else { return completionHandler(.failure(error!)) }
connection.enableUnsignedCodeExecutionForProcess(withID: request.processID) { (success, error) in
if let error = error, !success
{
print("Failed to enable unsigned code execution for process \(request.processID):", error)
completionHandler(.failure(ALTServerError(error)))
}
else
{
print("Enabled unsigned code execution for process:", request.processID)
let response = EnableUnsignedCodeExecutionResponse()
completionHandler(.success(response))
}
}
}
}
}
}
}
private extension RequestHandler

View File

@@ -20,6 +20,8 @@ public protocol RequestHandler
completionHandler: @escaping (Result<RemoveProvisioningProfilesResponse, Error>) -> Void)
func handleRemoveAppRequest(_ request: RemoveAppRequest, for connection: Connection, completionHandler: @escaping (Result<RemoveAppResponse, Error>) -> Void)
func handleEnableUnsignedCodeExecutionRequest(_ request: EnableUnsignedCodeExecutionRequest, for connection: Connection, completionHandler: @escaping (Result<EnableUnsignedCodeExecutionResponse, Error>) -> Void)
}
public protocol ConnectionHandler: AnyObject
@@ -152,6 +154,11 @@ private extension ConnectionManager
finish(result)
}
case .success(.enableUnsignedCodeExecution(let request)):
self.requestHandler.handleEnableUnsignedCodeExecutionRequest(request, for: connection) { (result) in
finish(result)
}
case .success(.unknown):
finish(Result<ErrorResponse, Error>.failure(ALTServerError(.unknownRequest)))
}

View File

@@ -25,6 +25,7 @@ public enum ServerRequest: Decodable
case installProvisioningProfiles(InstallProvisioningProfilesRequest)
case removeProvisioningProfiles(RemoveProvisioningProfilesRequest)
case removeApp(RemoveAppRequest)
case enableUnsignedCodeExecution(EnableUnsignedCodeExecutionRequest)
case unknown(identifier: String, version: Int)
var identifier: String {
@@ -36,6 +37,7 @@ public enum ServerRequest: Decodable
case .installProvisioningProfiles(let request): return request.identifier
case .removeProvisioningProfiles(let request): return request.identifier
case .removeApp(let request): return request.identifier
case .enableUnsignedCodeExecution(let request): return request.identifier
case .unknown(let identifier, _): return identifier
}
}
@@ -49,6 +51,7 @@ public enum ServerRequest: Decodable
case .installProvisioningProfiles(let request): return request.version
case .removeProvisioningProfiles(let request): return request.version
case .removeApp(let request): return request.version
case .enableUnsignedCodeExecution(let request): return request.version
case .unknown(_, let version): return version
}
}
@@ -92,6 +95,10 @@ public enum ServerRequest: Decodable
let request = try RemoveAppRequest(from: decoder)
self = .removeApp(request)
case "EnableUnsignedCodeExecutionRequest":
let request = try EnableUnsignedCodeExecutionRequest(from: decoder)
self = .enableUnsignedCodeExecution(request)
default:
self = .unknown(identifier: identifier, version: version)
}
@@ -105,6 +112,7 @@ public enum ServerResponse: Decodable
case installProvisioningProfiles(InstallProvisioningProfilesResponse)
case removeProvisioningProfiles(RemoveProvisioningProfilesResponse)
case removeApp(RemoveAppResponse)
case enableUnsignedCodeExecution(EnableUnsignedCodeExecutionResponse)
case error(ErrorResponse)
case unknown(identifier: String, version: Int)
@@ -116,6 +124,7 @@ public enum ServerResponse: Decodable
case .installProvisioningProfiles(let response): return response.identifier
case .removeProvisioningProfiles(let response): return response.identifier
case .removeApp(let response): return response.identifier
case .enableUnsignedCodeExecution(let response): return response.identifier
case .error(let response): return response.identifier
case .unknown(let identifier, _): return identifier
}
@@ -129,6 +138,7 @@ public enum ServerResponse: Decodable
case .installProvisioningProfiles(let response): return response.version
case .removeProvisioningProfiles(let response): return response.version
case .removeApp(let response): return response.version
case .enableUnsignedCodeExecution(let response): return response.version
case .error(let response): return response.version
case .unknown(_, let version): return version
}
@@ -169,6 +179,10 @@ public enum ServerResponse: Decodable
let response = try RemoveAppResponse(from: decoder)
self = .removeApp(response)
case "EnableUnsignedCodeExecutionResponse":
let response = try EnableUnsignedCodeExecutionResponse(from: decoder)
self = .enableUnsignedCodeExecution(response)
case "ErrorResponse":
let response = try ErrorResponse(from: decoder)
self = .error(response)
@@ -424,3 +438,28 @@ public struct RemoveAppResponse: ServerMessageProtocol
{
}
}
public struct EnableUnsignedCodeExecutionRequest: ServerMessageProtocol
{
public var version = 1
public var identifier = "EnableUnsignedCodeExecutionRequest"
public var udid: String
public var processID: Int
public init(udid: String, processID: Int)
{
self.udid = udid
self.processID = processID
}
}
public struct EnableUnsignedCodeExecutionResponse: ServerMessageProtocol
{
public var version = 1
public var identifier = "EnableUnsignedCodeExecutionResponse"
public init()
{
}
}