Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions PlayTools/MysticRunes/PlayedApple.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,95 @@ public class PlayKeychain: NSObject {

return errSecItemNotFound
}

@objc static public func keyCreateRandomKey(_ parameters: NSDictionary,
error: UnsafeMutablePointer<Unmanaged<CFError>?>?)
-> Unmanaged<SecKey>? {
// Check if kSecAttrIsPermanent is set to 1 in kSecPrivateKeyAttrs.
// If it is, set it to 0 before fowarding the call to SecKeyCreateRandomKey,
// and then add the key to the keychain db with the original attributes (with kSecAttrIsPermanent set to 1)
var privateKeyAttrs = parameters[kSecPrivateKeyAttrs as String] as? [String: Any] ?? [:]
let isPermanent = privateKeyAttrs[kSecAttrIsPermanent as String] as? Bool ?? false
if isPermanent {
privateKeyAttrs[kSecAttrIsPermanent as String] = false
}
var parametersCopy = parameters as! [String: Any] // swiftlint:disable:this force_cast
parametersCopy[kSecPrivateKeyAttrs as String] = privateKeyAttrs
var error: Unmanaged<CFError>?
guard let key = SecKeyCreateRandomKey(parametersCopy as CFDictionary, &error) else {
debugLogger("Failed to create random key: \(error!.takeRetainedValue())")
return nil
}
if isPermanent {
// Add the key to the keychain db with the original attributes
var keychainDict = [String: Any]()
keychainDict[kSecClass as String] = kSecClassKey
keychainDict[kSecAttrKeyType as String] = parameters[kSecAttrKeyType as String]
keychainDict[kSecAttrKeyClass as String] = parameters[kSecAttrKeyClass as String]
keychainDict["type"] = parameters[kSecAttrKeyType as String]
keychainDict["kcls"] = parameters[kSecAttrKeyClass as String]
keychainDict["v_Data"] = SecKeyCopyExternalRepresentation(key, nil) as? Data
keychainDict["r_Attributes"] = 1
guard playChainDB.insert(keychainDict as NSDictionary) != nil else {
debugLogger("Failed to write keychain file")
return nil
}
}
return Unmanaged.passRetained(key)
}

@objc static public func keyGeneratePair(_ parameters: NSDictionary,
publicKey: UnsafeMutablePointer<Unmanaged<SecKey>?>?,
privateKey: UnsafeMutablePointer<Unmanaged<SecKey>?>?) -> OSStatus {
// Same as above but we need to disable kSecAttrIsPermanent for both the public and private key.
var privateKeyAttrs = parameters[kSecPrivateKeyAttrs as String] as? [String: Any] ?? [:]
let isPrivatePermanent = privateKeyAttrs[kSecAttrIsPermanent as String] as? Bool ?? false
if isPrivatePermanent {
privateKeyAttrs[kSecAttrIsPermanent as String] = false
}
var publicKeyAttrs = parameters[kSecPublicKeyAttrs as String] as? [String: Any] ?? [:]
let isPublicPermanent = (publicKeyAttrs[kSecAttrIsPermanent as String] as? Bool) ?? false
if isPublicPermanent {
publicKeyAttrs[kSecAttrIsPermanent as String] = false
}
var parametersCopy = parameters as! [String: Any] // swiftlint:disable:this force_cast
parametersCopy[kSecPrivateKeyAttrs as String] = privateKeyAttrs
parametersCopy[kSecPublicKeyAttrs as String] = publicKeyAttrs
var newPublicKey: SecKey?
var newPrivateKey: SecKey?
guard SecKeyGeneratePair(parametersCopy as CFDictionary, &newPublicKey, &newPrivateKey) != 0 else {
debugLogger("Failed to generate key pair.")
return errSecMissingEntitlement
}
if isPrivatePermanent {
// Add the keys to the keychain db with the original attributes
let publicKeyRef = newPublicKey
let privateKeyRef = newPrivateKey
var publicKeyDict = [String: Any]()
publicKeyDict[kSecClass as String] = kSecClassKey
publicKeyDict[kSecAttrKeyType as String] = parameters[kSecAttrKeyType as String]
publicKeyDict[kSecAttrKeyClass as String] = kSecAttrKeyClassPublic
publicKeyDict["type"] = parameters[kSecAttrKeyType as String]
publicKeyDict["kcls"] = kSecAttrKeyClassPublic
publicKeyDict["v_Data"] = SecKeyCopyExternalRepresentation(publicKeyRef!, nil) as? Data
publicKeyDict["r_Attributes"] = 1
guard playChainDB.insert(publicKeyDict as NSDictionary) != nil else {
debugLogger("Failed to write public key to keychain db")
return errSecMissingEntitlement
}
var privateKeyDict = [String: Any]()
privateKeyDict[kSecClass as String] = kSecClassKey
privateKeyDict[kSecAttrKeyType as String] = parameters[kSecAttrKeyType as String]
privateKeyDict[kSecAttrKeyClass as String] = kSecAttrKeyClassPrivate
privateKeyDict["type"] = parameters[kSecAttrKeyType as String]
privateKeyDict["kcls"] = kSecAttrKeyClassPrivate
privateKeyDict["v_Data"] = SecKeyCopyExternalRepresentation(privateKeyRef!, nil) as? Data
privateKeyDict["r_Attributes"] = 1
guard playChainDB.insert(privateKeyDict as NSDictionary) != nil else {
debugLogger("Failed to write private key to keychain db")
return errSecMissingEntitlement
}
}
return errSecSuccess
}
}
48 changes: 48 additions & 0 deletions PlayTools/PlayLoader.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@
#import <PlayTools/PlayTools-Swift.h>
#import <sys/utsname.h>
#import "NSObject+Swizzle.h"
#import <dlfcn.h>

@import MachO;

// Get device model from playcover .plist
// With a null terminator
#define DEVICE_MODEL [[[PlaySettings shared] deviceModel] cStringUsingEncoding:NSUTF8StringEncoding]
#define OEM_ID [[[PlaySettings shared] oemID] cStringUsingEncoding:NSUTF8StringEncoding]
#define PLATFORM_IOS 2

// Original implementations of the functions we interpose so we can call them in our implementations
uint32_t (*orig_dyld_image_count)(void) = _dyld_image_count;

// Define dyld_get_active_platform function for interpose
int dyld_get_active_platform(void);
int pt_dyld_get_active_platform(void) { return PLATFORM_IOS; }
Expand Down Expand Up @@ -170,10 +176,46 @@ static OSStatus pt_SecItemDelete(CFDictionaryRef query) {
return retval;
}

static SecKeyRef pt_SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) {
SecKeyRef result;
if ([[PlaySettings shared] playChain]) {
result = [PlayKeychain keyCreateRandomKey:(__bridge NSDictionary * _Nonnull)(parameters) error:error];
} else {
result = SecKeyCreateRandomKey(parameters, (void *)error);
}

if ([[PlaySettings shared] playChainDebugging]) {
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyCreateRandomKey: %@", parameters]];
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyCreateRandomKey result: %@", result]];
}

return result;
}

// Deprecated, but some apps might still use it.
static OSStatus pt_SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
OSStatus retval;
if ([[PlaySettings shared] playChain]) {
retval = [PlayKeychain keyGeneratePair:(__bridge NSDictionary * _Nonnull)(parameters) publicKey:(void *)publicKey privateKey:(void *)privateKey];
} else {
retval = SecKeyGeneratePair(parameters, (void *)publicKey, (void *)privateKey);
}

if ([[PlaySettings shared] playChainDebugging]) {
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyGeneratePair: %@", parameters]];
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyGeneratePair public key result: %@", publicKey != NULL ? *publicKey : nil]];
[PlayKeychain debugLogger: [NSString stringWithFormat:@"SecKeyGeneratePair private key result: %@", privateKey != NULL ? *privateKey : nil]];
}

return retval;
}

DYLD_INTERPOSE(pt_SecItemCopyMatching, SecItemCopyMatching)
DYLD_INTERPOSE(pt_SecItemAdd, SecItemAdd)
DYLD_INTERPOSE(pt_SecItemUpdate, SecItemUpdate)
DYLD_INTERPOSE(pt_SecItemDelete, SecItemDelete)
DYLD_INTERPOSE(pt_SecKeyCreateRandomKey, SecKeyCreateRandomKey)
DYLD_INTERPOSE(pt_SecKeyGeneratePair, SecKeyGeneratePair)

static uint8_t ue_status = 0;

Expand Down Expand Up @@ -276,12 +318,18 @@ static int pt_usleep(useconds_t time) {
return usleep(time);
}

static uint32_t pt_dyld_image_count(void) {
return orig_dyld_image_count() - 1; // No, PlayTools doesn't exist what are you talking about?
}


DYLD_INTERPOSE(pt_open, open)
DYLD_INTERPOSE(pt_stat, stat)
DYLD_INTERPOSE(pt_access, access)
DYLD_INTERPOSE(pt_rename, rename)
DYLD_INTERPOSE(pt_unlink, unlink)
DYLD_INTERPOSE(pt_usleep, usleep)
DYLD_INTERPOSE(pt_dyld_image_count, _dyld_image_count)

@implementation PlayLoader

Expand Down