From 8bf1742a8dc7364f87d71216337efcadcb0563e5 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Thu, 3 Dec 2020 01:32:25 -0500 Subject: Initial --- .gitignore | 3 ++ Makefile | 13 +++++++ NSTask.h | 43 ++++++++++++++++++++++ ent.xml | 17 +++++++++ snaprestore.m | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 188 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 NSTask.h create mode 100644 ent.xml create mode 100644 snaprestore.m diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..79aa634 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +snaprestore +compile_commands.json +.cache diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..90edba3 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +CC = aarch64-apple-darwin-clang +STRIP = aarch64-apple-darwin-strip +LDID = ldid +CFLAGS = -arch arm64 -isysroot /home/cameron/Documents/SDK/iPhoneOS14.2.sdk -miphoneos-version-min=13.0 -isystem /home/cameron/Documents/Procursus/build_base/iphoneos-arm64/1600/usr/include -isystem /home/cameron/Documents/Procursus/build_base/iphoneos-arm64/1600/usr/local/include -F/home/cameron/Documents/Procursus/build_base/iphoneos-arm64/1600/System/Library/Frameworks + +all: snaprestore + +snaprestore: snaprestore.m ent.xml NSTask.h + $(CC) $(CFLAGS) -o snaprestore snaprestore.m -framework IOKit -framework Foundation -fobjc-arc + $(LDID) -Sent.xml snaprestore + +clean: + rm -f snaprestore diff --git a/NSTask.h b/NSTask.h new file mode 100644 index 0000000..7b51c23 --- /dev/null +++ b/NSTask.h @@ -0,0 +1,43 @@ +/* +* This header is generated by classdump-dyld 1.0 +* on Thursday, January 25, 2018 at 11:20:38 PM Eastern European Standard Time +* Operating System: Version 11.1.2 (Build 15B202) +* Image Source: /System/Library/Frameworks/Foundation.framework/Foundation +* classdump-dyld is licensed under GPLv3, Copyright © 2013-2016 by Elias Limneos. +*/ + +#import + +@interface NSTask : NSObject + +@property (copy) NSURL * executableURL; +@property (copy) NSArray * arguments; +@property (copy) NSDictionary * environment; +@property (copy) NSURL * currentDirectoryURL; +@property (retain) id standardInput; +@property (retain) id standardOutput; +@property (retain) id standardError; +@property (readonly) int processIdentifier; +@property (getter=isRunning, readonly) BOOL running; +@property (readonly) int terminationStatus; +@property (readonly) long long terminationReason; +@property (copy) id terminationHandler; +@property (assign) long long qualityOfService; ++ (id)currentTaskDictionary; ++ (id)launchedTaskWithDictionary:(id)arg1; ++ (id)launchedTaskWithLaunchPath:(id)arg1 arguments:(id)arg2; ++ (id)launchedTaskWithExecutableURL:(id)arg1 arguments:(id)arg2 error:(out id*)arg3 terminationHandler:(/*^block*/id)arg4; +- (void)waitUntilExit; +- (id)currentDirectoryPath; +- (void)setCurrentDirectoryPath:(id)arg1; +- (id)launchPath; +- (void)setLaunchPath:(id)arg1; +- (void)launch; +- (BOOL)launchAndReturnError:(id*)arg1; +- (void)interrupt; +- (long long)suspendCount; +- (BOOL)suspend; +- (BOOL)resume; +- (void)terminate; +- (NSArray *)arguments; +@end diff --git a/ent.xml b/ent.xml new file mode 100644 index 0000000..ea437c4 --- /dev/null +++ b/ent.xml @@ -0,0 +1,17 @@ + + + + platform-application + + com.apple.private.security.no-container + + com.apple.private.skip-library-validation + + com.apple.private.apfs.revert-to-snapshot + + com.apple.private.security.disk-device-access + + com.apple.private.vfs.snapshot + + + diff --git a/snaprestore.m b/snaprestore.m new file mode 100644 index 0000000..96e7b4d --- /dev/null +++ b/snaprestore.m @@ -0,0 +1,112 @@ +#import +#import +#import +#import +#import +#import "NSTask.h" + +void usage(char *name) { + printf( + "Usage: %s [volume] [snapshot]\n", name); +} + +NSString *bootsnapshot() { + const io_registry_entry_t chosen = IORegistryEntryFromPath(0, "IODeviceTree:/chosen"); + const NSData *data = (__bridge const NSData *)IORegistryEntryCreateCFProperty(chosen, (__bridge CFStringRef)@"boot-manifest-hash", kCFAllocatorDefault, 0); + IOObjectRelease(chosen); + + NSMutableString *manifestHash = [NSMutableString stringWithString:@""]; + NSUInteger len = [data length]; + Byte *buf = (Byte*)malloc(len); + memcpy(buf, [data bytes], len); + int buf2; + for (buf2 = 0; buf2 <= 19; buf2++) { + [manifestHash appendFormat:@"%02X", buf[buf2]]; + } + // add com.apple.os.update- + return [NSString stringWithFormat:@"%@%@", @"com.apple.os.update-", manifestHash]; +} + +int restore(const char *vol, const char *snap) { + int fd = open(vol, O_RDONLY, 0); + + int ret = fs_snapshot_revert(fd, snap, 0); + return ret; +} + +int mount(const char *vol, const char *snap, const char *mnt) { + int fd = open(vol, O_RDONLY, 0); + + BOOL isDir; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if(![fileManager fileExistsAtPath:[NSString stringWithUTF8String:mnt] isDirectory:&isDir]) + if(![fileManager createDirectoryAtPath:[NSString stringWithUTF8String:mnt] withIntermediateDirectories:YES attributes:nil error:NULL]) + NSLog(@"Error: Create folder failed %s", mnt); + + int ret = fs_snapshot_mount(fd, mnt, snap, 0); + + return ret; +} + +NSMutableSet *findApps(const char *root, const char *mnt) { + NSMutableString *rootApplications = [NSMutableString stringWithUTF8String:root]; + rootApplications = [[rootApplications stringByAppendingString:@"/Applications"] mutableCopy]; + + NSMutableString *mntApplications = [NSMutableString stringWithUTF8String:mnt]; + mntApplications = [[mntApplications stringByAppendingString:@"/Applications"] mutableCopy]; + + NSArray *rootApps = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:rootApplications error:nil]; + NSArray *mntApps = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:mntApplications error:nil]; + + NSMutableSet *ret = [[NSMutableSet alloc] init]; + for (NSString *app in rootApps) { + if (![mntApps containsObject:app]) { + [ret addObject:[@"/Applications/" stringByAppendingString:app]]; + } + } + + return ret; +} + +int rename(const char *vol, const char *snap) { + int fd = open(vol, O_RDONLY, 0); + + int ret = fs_snapshot_rename(fd, snap, [bootsnapshot() UTF8String], 0); + return ret; +} + +int main(int argc, char *argv[]) { + if (argc != 3) { + usage(argv[0]); + return 0; + } + + char *vol = argv[1]; + char *snap = argv[2]; + char *mnt = "/tmp/rootfsmnt"; + + printf("Restoring snapshot %s...\n", snap); + restore(vol, snap); + printf("Restored snapshot...\n"); + printf("Mounting rootfs...\n"); + mount(vol, snap, mnt); + printf("Mounted %s at %s\n", snap, mnt); + NSMutableSet *appSet = findApps(vol, mnt); + if (appSet) { + printf("Refreshing icon cache...\n"); + NSMutableArray *argArray = [[NSMutableArray alloc] init]; + for (NSString *app in appSet) { + [argArray addObject:@"-u"]; + [argArray addObject:app]; + } + NSTask *task = [[NSTask alloc] init]; + [task setLaunchPath:@"/usr/bin/uicache"]; + [task setArguments:argArray]; + [task launch]; + [task waitUntilExit]; + } + printf("Renaming snapshot...\n"); + rename(vol, snap); + printf("Restoring %s on %s has succeeded\n", snap, vol); + return 0; +} -- cgit v1.2.3-56-ge451