mirror of
https://github.com/NohamR/TrollDecrypt-tvOS.git
synced 2026-07-11 22:41:37 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
badb4f4784 | ||
|
|
05b73595d8 | ||
|
|
869e625770 | ||
|
|
5af58eda88 | ||
|
|
3d40efe291 | ||
|
|
26e6ed4c8d | ||
|
|
8c96736b94 | ||
|
|
491e53072f | ||
|
|
7449682883 | ||
|
|
46184fa020 |
2
Makefile
2
Makefile
@@ -1,4 +1,4 @@
|
||||
TARGET := appletv:clang:16.4:14.0
|
||||
TARGET := appletv:clang:26.2:14.0
|
||||
INSTALL_TARGET_PROCESSES = TrollDecrypt
|
||||
|
||||
GO_EASY_ON_ME = 1
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# TrollDecrypt
|
||||
iOS IPA Decrypter for TrollStore
|
||||
tvOS IPA Decrypter for TrollStore
|
||||
|
||||
## How to use
|
||||
1. Download and install TrollDecrypt from [here](https://github.com/donato-fiore/TrollDecrypt/releases)
|
||||
1. Download and install TrollDecrypt from [here](https://github.com/NohamR/TrollDecrypt-tvOS/releases)
|
||||
2. Choose app you want to decrypt.
|
||||
3. Once finished decrypting, you can get the `.ipa` file from inside the app.
|
||||
|
||||
@@ -10,12 +10,14 @@ iOS IPA Decrypter for TrollStore
|
||||
1. Install [theos](https://theos.dev/docs/installation)
|
||||
2. Run the commands below
|
||||
```
|
||||
git clone https://github.com/donato-fiore/TrollDecrypt.git
|
||||
git clone https://github.com/NohamR/TrollDecrypt-tvOS.git
|
||||
cd TrollDecrypt
|
||||
make package
|
||||
```
|
||||
|
||||
## Credits / Thanks
|
||||
- [TrollDecrypt-tvOS](https://github.com/straight-tamago/TrollDecrypt-tvOS) by straight-tamago for the original tvOS version of TrollDecrypt
|
||||
- [TrollDecrypt](https://github.com/donato-fiore/TrollDecrypt) by donato-fiore for the original version of TrollDecrypt
|
||||
- [TrollDecryptor](https://github.com/wh1te4ever/TrollDecryptor) by wh1te4ever
|
||||
- [dumpdecrypted](https://github.com/stefanesser/dumpdecrypted) by Stefan Esser
|
||||
- [bfdecrypt](https://github.com/BishopFox/bfdecrypt) by BishopFox
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<string>App Icon</string>
|
||||
</dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.fiore.trolldecrypt</string>
|
||||
<string>com.nohamr.trolldecrypt</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
@@ -18,7 +18,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.1</string>
|
||||
<string>1.4</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
|
||||
- (id)initWithPathToBinary:(NSString *)pathToBinary appName:(NSString *)appName appVersion:(NSString *)appVersion;
|
||||
- (void)createIPAFile:(pid_t)pid;
|
||||
- (BOOL)dumpDecryptedImage:(const struct mach_header *)image_mh fileName:(const char *)encryptedImageFilenameStr image:(int)imageNum task:(vm_map_t)targetTask;
|
||||
- (BOOL)dumpDecryptedImage:(vm_address_t)imageAddress fileName:(const char *)encryptedImageFilenameStr image:(int)imageNum task:(vm_map_t)targetTask;
|
||||
- (NSString *)IPAPath;
|
||||
@end
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <spawn.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
@@ -357,9 +358,9 @@ int find_off_cryptid(const char *filePath) {
|
||||
[self makeDirectories:encryptedImageFilenameStr];
|
||||
|
||||
//0x1518
|
||||
uint32_t aslr_slide = 0;
|
||||
uint64_t aslr_slide = 0;
|
||||
get_image_size(imageAddress, targetTask, &aslr_slide);
|
||||
NSLog(@"[trolldecrypt] aslr_slide= 0x%x", aslr_slide);
|
||||
NSLog(@"[trolldecrypt] aslr_slide= 0x%llx", aslr_slide);
|
||||
|
||||
off_cryptid=find_off_cryptid(encryptedImageFilenameStr);
|
||||
|
||||
@@ -504,14 +505,14 @@ int find_off_cryptid(const char *filePath) {
|
||||
if (task_for_pid(mach_task_self(), pid, &targetTask))
|
||||
{
|
||||
NSLog(@"[trolldecrypt] Can't execute task_for_pid! Do you have the right permissions/entitlements?\n");
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
//numberOfImages
|
||||
struct task_dyld_info dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
|
||||
if(task_info(targetTask, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count) != KERN_SUCCESS) exit(1);
|
||||
if(task_info(targetTask, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count) != KERN_SUCCESS) return;
|
||||
|
||||
mach_msg_type_number_t size = sizeof(struct dyld_all_image_infos);
|
||||
uint8_t* data = readProcessMemory(targetTask, dyld_info.all_image_info_addr, &size);
|
||||
@@ -524,6 +525,9 @@ int find_off_cryptid(const char *filePath) {
|
||||
uint32_t numberOfImages = infos->infoArrayCount;
|
||||
mach_vm_address_t imageAddress = 0;
|
||||
const char *appPath = [[self appPath] UTF8String];
|
||||
if(strstr(appPath, "/private") == appPath) {
|
||||
appPath += 8;
|
||||
}
|
||||
|
||||
NSLog(@"[trolldecrypt] There are %d images mapped.", numberOfImages);
|
||||
|
||||
@@ -532,8 +536,8 @@ int find_off_cryptid(const char *filePath) {
|
||||
mach_msg_type_number_t size3 = PATH_MAX;
|
||||
uint8_t *fpath_addr = readProcessMemory(targetTask, (mach_vm_address_t) info[i].imageFilePath, &size3);
|
||||
|
||||
imageAddress = (struct mach_header *)info[i].imageLoadAddress;
|
||||
const char *imageName = fpath_addr;
|
||||
imageAddress = (mach_vm_address_t)info[i].imageLoadAddress;
|
||||
const char *imageName = (const char *)fpath_addr;
|
||||
|
||||
if(!imageName || !imageAddress)
|
||||
continue;
|
||||
@@ -553,7 +557,7 @@ int find_off_cryptid(const char *filePath) {
|
||||
}
|
||||
|
||||
-(NSString *)IPAPath {
|
||||
return [NSString stringWithFormat:@"%@/%@_%@_decrypted.ipa", [self docPath], self.appName, self.appVersion];
|
||||
return [NSString stringWithFormat:@"%@/%@_%@_decrypted.tipa", [self docPath], self.appName, self.appVersion];
|
||||
}
|
||||
|
||||
-(void) createIPAFile:(pid_t)pid {
|
||||
@@ -583,6 +587,108 @@ int find_off_cryptid(const char *filePath) {
|
||||
// Replace encrypted binaries with decrypted versions
|
||||
NSLog(@"[trolldecrypt] ======== START DECRYPTION PROCESS ========");
|
||||
[self dumpDecrypted:pid];
|
||||
|
||||
// Find embedded app extensions (.appex) and decrypt them
|
||||
NSLog(@"[trolldecrypt] ======== START APP EXTENSION DECRYPTION ========");
|
||||
NSString *pluginsPath = [appDir stringByAppendingPathComponent:@"PlugIns"];
|
||||
NSLog(@"[trolldecrypt] Looking for app extensions in: %@", pluginsPath);
|
||||
if ([fm fileExistsAtPath:pluginsPath]) {
|
||||
NSArray *plugins = [fm contentsOfDirectoryAtPath:pluginsPath error:nil];
|
||||
for (NSString *plugin in plugins) {
|
||||
if ([plugin hasSuffix:@".appex"]) {
|
||||
NSString *appexPath = [pluginsPath stringByAppendingPathComponent:plugin];
|
||||
NSString *executableName = [plugin stringByDeletingPathExtension];
|
||||
NSString *executablePath = [appexPath stringByAppendingPathComponent:executableName];
|
||||
|
||||
if ([fm fileExistsAtPath:executablePath]) {
|
||||
NSLog(@"[trolldecrypt] Found app extension: %@", executablePath);
|
||||
pid_t appex_pid = -1;
|
||||
|
||||
void *handle = dlopen("/usr/lib/libSystem.dylib", RTLD_NOW);
|
||||
int (*my_posix_spawnattr_init)(posix_spawnattr_t *) = (int (*)(posix_spawnattr_t *))dlsym(handle, "posix_spawnattr_init");
|
||||
int (*my_posix_spawnattr_setflags)(posix_spawnattr_t *, short) = (int (*)(posix_spawnattr_t *, short))dlsym(handle, "posix_spawnattr_setflags");
|
||||
int (*my_posix_spawnattr_destroy)(posix_spawnattr_t *) = (int (*)(posix_spawnattr_t *))dlsym(handle, "posix_spawnattr_destroy");
|
||||
int (*my_posix_spawn)(pid_t *, const char *, void *, const posix_spawnattr_t *, char *const *, char *const *) = (int (*)(pid_t *, const char *, void *, const posix_spawnattr_t *, char *const *, char *const *))dlsym(handle, "posix_spawn");
|
||||
|
||||
if (my_posix_spawn && my_posix_spawnattr_init && my_posix_spawnattr_setflags) {
|
||||
posix_spawnattr_t attr;
|
||||
my_posix_spawnattr_init(&attr);
|
||||
my_posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED);
|
||||
|
||||
const char *argv[] = {[executablePath UTF8String], NULL};
|
||||
extern char **environ;
|
||||
int envCount = 0;
|
||||
while (environ[envCount] != NULL) envCount++;
|
||||
char **new_environ = malloc((envCount + 2) * sizeof(char *));
|
||||
for (int i = 0; i < envCount; i++) {
|
||||
new_environ[i] = environ[i];
|
||||
}
|
||||
new_environ[envCount] = "XPC_SERVICE_NAME=appex_decryption";
|
||||
new_environ[envCount + 1] = NULL;
|
||||
|
||||
int ret = my_posix_spawn(&appex_pid, [executablePath UTF8String], NULL, &attr, (char *const *)argv, new_environ);
|
||||
free(new_environ);
|
||||
if(my_posix_spawnattr_destroy) my_posix_spawnattr_destroy(&attr);
|
||||
|
||||
if (ret == 0 && appex_pid > 0) {
|
||||
NSLog(@"[trolldecrypt] Spawned appex with PID %d, waiting for dyld...", appex_pid);
|
||||
|
||||
vm_map_t targetTask = 0;
|
||||
if (task_for_pid(mach_task_self(), appex_pid, &targetTask) == KERN_SUCCESS) {
|
||||
// Resume the suspended process so dyld can map the binaries into memory
|
||||
kill(appex_pid, SIGCONT);
|
||||
|
||||
BOOL dyld_ready = NO;
|
||||
for (int k = 0; k < 500; k++) {
|
||||
struct task_dyld_info dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
|
||||
if (task_info(targetTask, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count) == KERN_SUCCESS) {
|
||||
if (dyld_info.all_image_info_addr != 0) {
|
||||
mach_msg_type_number_t size = sizeof(struct dyld_all_image_infos);
|
||||
uint8_t* data = readProcessMemory(targetTask, dyld_info.all_image_info_addr, &size);
|
||||
|
||||
if (data != NULL) {
|
||||
struct dyld_all_image_infos* infos = (struct dyld_all_image_infos *) data;
|
||||
if (infos->infoArrayCount > 0) {
|
||||
// dyld mapped the images! Suspend the process immediately.
|
||||
kill(appex_pid, SIGSTOP);
|
||||
dyld_ready = YES;
|
||||
// Clean up allocated memory by vm_read in readProcessMemory
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)data, size);
|
||||
break;
|
||||
}
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)data, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
usleep(1000); // 1ms
|
||||
}
|
||||
|
||||
if (dyld_ready) {
|
||||
NSLog(@"[trolldecrypt] Appex dyld mapping caught successfully, dumping!");
|
||||
[self dumpDecrypted:appex_pid];
|
||||
} else {
|
||||
NSLog(@"[trolldecrypt] Failed to catch dyld mapping in time for appex.");
|
||||
}
|
||||
} else {
|
||||
NSLog(@"[trolldecrypt] Can't execute task_for_pid on appex_pid %d", appex_pid);
|
||||
}
|
||||
|
||||
kill(appex_pid, SIGKILL);
|
||||
// Wait for the child to exit
|
||||
int status;
|
||||
waitpid(appex_pid, &status, WNOHANG);
|
||||
} else {
|
||||
NSLog(@"[trolldecrypt] Failed to spawn appex (error %d)", ret);
|
||||
}
|
||||
}
|
||||
dlclose(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSLog(@"[trolldecrypt] ======== DECRYPTION COMPLETE ========");
|
||||
|
||||
// ZIP it up
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#import "TDFileManagerViewController.h"
|
||||
#import "TDUtils.h"
|
||||
#import "LSApplicationProxy+AltList.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation TDFileManagerViewController
|
||||
|
||||
@@ -48,12 +50,12 @@
|
||||
|
||||
cell.textLabel.text = self.fileList[indexPath.row];
|
||||
cell.detailTextLabel.text = [dateFormatter stringFromDate:date];
|
||||
cell.detailTextLabel.textColor = [UIColor systemGray2Color];
|
||||
cell.detailTextLabel.textColor = [UIColor grayColor];
|
||||
cell.imageView.image = [UIImage systemImageNamed:@"doc.fill"];
|
||||
|
||||
UILabel *label = [[UILabel alloc] init];
|
||||
label.text = [NSString stringWithFormat:@"%.2f MB", [fileSize doubleValue] / 1000000.0f];
|
||||
label.textColor = [UIColor systemGray2Color];
|
||||
label.textColor = [UIColor grayColor];
|
||||
label.font = [UIFont systemFontOfSize:12.0f];
|
||||
[label sizeToFit];
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
@@ -71,6 +73,7 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UIContextualAction *deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"Delete" handler:^(UIContextualAction *action, UIView *sourceView, void (^completionHandler)(BOOL)) {
|
||||
NSString *file = self.fileList[indexPath.row];
|
||||
@@ -82,16 +85,54 @@
|
||||
UISwipeActionsConfiguration *swipeActions = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction]];
|
||||
return swipeActions;
|
||||
}
|
||||
#endif
|
||||
|
||||
UIWindow *kw2 = NULL;
|
||||
UIAlertController *doneController2 = NULL;
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSString *file = self.fileList[indexPath.row];
|
||||
NSString *path = [docPath() stringByAppendingPathComponent:file];
|
||||
NSURL *url = [NSURL fileURLWithPath:path];
|
||||
|
||||
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[url] applicationActivities:nil];
|
||||
[self presentViewController:activityViewController animated:YES completion:nil];
|
||||
doneController2 = [UIAlertController alertControllerWithTitle:file message:[NSString stringWithFormat:@"Location:\n%@", path] preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Ok", @"Ok") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[kw2 removeFromSuperview];
|
||||
kw2.hidden = YES;
|
||||
}];
|
||||
[doneController2 addAction:okAction];
|
||||
|
||||
UIAlertAction *openAction = [UIAlertAction actionWithTitle:@"Share IPA with Airdrop" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
NSString *filePath = path;
|
||||
NSURL *url = [NSURL fileURLWithPath:filePath];
|
||||
|
||||
NSBundle *bundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/Sharing.framework"];
|
||||
[bundle load];
|
||||
|
||||
NSBundle *sharingUI = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/SharingUI.framework"];
|
||||
[sharingUI load];
|
||||
|
||||
id sharingView = [[objc_getClass("SFAirDropSharingViewControllerTV") alloc] initWithSharingItems:@[url]];
|
||||
[self dismissViewControllerAnimated:NO completion:^{
|
||||
[self presentViewController:sharingView animated:YES completion:nil];
|
||||
[sharingView setCompletionHandler:^(NSError *error) {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}];
|
||||
}];
|
||||
|
||||
[self presentViewController:sharingView animated:true completion:nil];
|
||||
}];
|
||||
[doneController2 addAction:openAction];
|
||||
|
||||
UIAlertAction *deleteFileAction = [UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {
|
||||
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
|
||||
[self refresh];
|
||||
[kw2 removeFromSuperview];
|
||||
kw2.hidden = YES;
|
||||
}];
|
||||
[doneController2 addAction:deleteFileAction];
|
||||
|
||||
[self presentViewController:doneController2 animated:YES completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -9,13 +9,17 @@
|
||||
|
||||
self.apps = appList();
|
||||
self.title = @"TrollDecrypt";
|
||||
#if !TARGET_OS_TV
|
||||
self.navigationController.navigationBar.prefersLargeTitles = YES;
|
||||
#endif
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"info.circle"] style:UIBarButtonItemStylePlain target:self action:@selector(about:)];
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"folder"] style:UIBarButtonItemStylePlain target:self action:@selector(openDocs:)];
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
|
||||
[refreshControl addTarget:self action:@selector(refreshApps:) forControlEvents:UIControlEventValueChanged];
|
||||
self.refreshControl = refreshControl;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(bool)animated {
|
||||
@@ -48,16 +52,18 @@
|
||||
}
|
||||
|
||||
- (void)about:(id)sender {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"TrollDecrypt" message:@"by fiore\nIcon by @super.user\nbfdecrypt by @bishopfox\ndumpdecrypted by @i0n1c\nUpdated for TrollStore by @wh1te4ever" preferredStyle:UIAlertControllerStyleAlert];
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"TrollDecrypt" message:@"by fiore\nIcon by @super.user\nbfdecrypt by @bishopfox\ndumpdecrypted by @i0n1c\nUpdated for TrollStore by @wh1te4ever\nPorting to tvOS by @straight-tamago\nFixed by NohamR" preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
- (void)refreshApps:(UIRefreshControl *)refreshControl {
|
||||
self.apps = appList();
|
||||
[self.tableView reloadData];
|
||||
[refreshControl endRefreshing];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return 1;
|
||||
@@ -129,4 +135,4 @@
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -42,4 +42,9 @@ NSArray *decryptedFileList(void);
|
||||
NSString *docPath(void);
|
||||
void fetchLatestTrollDecryptVersion(void (^completionHandler)(NSString *version));
|
||||
void github_fetchLatedVersion(NSString *repo, void (^completionHandler)(NSString *latestVersion));
|
||||
NSString *trollDecryptVersion(void);
|
||||
NSString *trollDecryptVersion(void);
|
||||
|
||||
@interface SFAirDropSharingViewControllerTV : UIViewController
|
||||
-(id)initWithSharingItems:(id)arg1;
|
||||
-(void)setCompletionHandler:(void (^)(NSError *error))arg1;
|
||||
@end
|
||||
32
TDUtils.m
32
TDUtils.m
@@ -3,13 +3,6 @@
|
||||
#import "LSApplicationProxy+AltList.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@interface SFAirDropSharingViewControllerTV : UIViewController
|
||||
-(id)initWithSharingItems:(id)arg1;
|
||||
-(void)setCompletionHandler:(void (^)(NSError *error))arg1;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
UIWindow *alertWindow = NULL;
|
||||
UIWindow *kw = NULL;
|
||||
UIViewController *root = NULL;
|
||||
@@ -210,29 +203,20 @@ void bfinject_rocknroll(pid_t pid, NSString *appName, NSString *version) {
|
||||
|
||||
UIAlertAction *openAction = [UIAlertAction actionWithTitle:@"Share IPA with Airdrop" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
NSString *filePath = [dd IPAPath];
|
||||
NSDictionary* airdropDictionary;
|
||||
NSURL *url = [NSURL fileURLWithPath:filePath];
|
||||
|
||||
NSBundle *bundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/Sharing.framework"];
|
||||
[bundle load];
|
||||
|
||||
NSString *suf = @"/System/Library/PrivateFrameworks/SharingUI.framework";
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:suf]){
|
||||
NSBundle *sharingUI = [NSBundle bundleWithPath:suf];
|
||||
[sharingUI load];
|
||||
}
|
||||
|
||||
UIViewController *rvc = [[[UIApplication sharedApplication] keyWindow] rootViewController];
|
||||
NSURL *url = [NSURL fileURLWithPath:filePath];
|
||||
NSBundle *sharingUI = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/SharingUI.framework"];
|
||||
[sharingUI load];
|
||||
|
||||
id sharingView = [[objc_getClass("SFAirDropSharingViewControllerTV") alloc] initWithSharingItems:@[url]];
|
||||
[sharingView setCompletionHandler:^(NSError *error) {
|
||||
NSString *sender = airdropDictionary[@"sender"];
|
||||
if (sender) {
|
||||
id defaultWorkspace = [objc_getClass("LSApplicationWorkspace") defaultWorkspace];
|
||||
[defaultWorkspace performSelector:@selector(openApplicationWithBundleID:) withObject:(id)sender];
|
||||
}
|
||||
[root dismissViewControllerAnimated:true completion:nil];
|
||||
}];
|
||||
|
||||
[rvc presentViewController:sharingView animated:true completion:nil];
|
||||
[root presentViewController:sharingView animated:true completion:nil];
|
||||
}];
|
||||
[doneController addAction:openAction];
|
||||
|
||||
@@ -257,7 +241,7 @@ NSArray *decryptedFileList(void) {
|
||||
|
||||
NSString *file;
|
||||
while (file = [directoryEnumerator nextObject]) {
|
||||
if ([[file pathExtension] isEqualToString:@"ipa"]) {
|
||||
if ([[file pathExtension] isEqualToString:@"ipa"] || [[file pathExtension] isEqualToString:@"tipa"]) {
|
||||
NSString *filePath = [[docPath() stringByAppendingPathComponent:file] stringByStandardizingPath];
|
||||
|
||||
NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:filePath error:nil];
|
||||
@@ -402,7 +386,7 @@ void github_fetchLatedVersion(NSString *repo, void (^completionHandler)(NSString
|
||||
}
|
||||
|
||||
void fetchLatestTrollDecryptVersion(void (^completionHandler)(NSString *version)) {
|
||||
github_fetchLatedVersion(@"donato-fiore/TrollDecrypt", completionHandler);
|
||||
github_fetchLatedVersion(@"straight-tamago/TrollDecrypt-tvOS", completionHandler);
|
||||
}
|
||||
|
||||
NSString *trollDecryptVersion(void) {
|
||||
|
||||
8
control
8
control
@@ -1,8 +1,8 @@
|
||||
Package: com.fiore.trolldecrypt
|
||||
Package: com.nohamr.trolldecrypt
|
||||
Name: TrollDecrypt
|
||||
Version: 1.1
|
||||
Version: 1.2
|
||||
Architecture: iphoneos-arm
|
||||
Description: An awesome application!
|
||||
Maintainer: fiore
|
||||
Author: fiore
|
||||
Maintainer: nohamr
|
||||
Author: nohamr
|
||||
Section: Utilities
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<key>platform-application</key>
|
||||
<true/>
|
||||
<key>application-identifier</key>
|
||||
<string>com.fiore.trolldecrypt</string>
|
||||
<string>com.nohamr.trolldecrypt</string>
|
||||
<key>com.apple.security.exception.files.absolute-path.read-write</key>
|
||||
<array>
|
||||
<string>/</string>
|
||||
|
||||
Reference in New Issue
Block a user