Skip to content

Instantly share code, notes, and snippets.

@t0rr3sp3dr0
Created April 7, 2024 11:01
Show Gist options
  • Save t0rr3sp3dr0/2e4b8a81bc631ff8f6f17bc59d7f6698 to your computer and use it in GitHub Desktop.
Save t0rr3sp3dr0/2e4b8a81bc631ff8f6f17bc59d7f6698 to your computer and use it in GitHub Desktop.
#include <dlfcn.h>
//#include <mach-o/dyld.h>
//#include <mach-o/getsect.h>
//#include <mach-o/ldsyms.h>
#include <stdio.h>
#include <string.h>
#include <sys/clonefile.h>
#include <sys/errno.h>
#include <sys/syslimits.h>
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import "DecryptOperation.h"
#import "PKArchive.h"
// % /usr/libexec/PlistBuddy -c 'Print :Program' /System/Library/LaunchAgents/com.apple.storedownloadd.plist
// /System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storedownloadd
//#define DO_OBJ "/System/Library/PrivateFrameworks/CommerceKit.framework/Resources/storedownloadd"
// % nm -U /System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storedownloadd
// 0000000100000000 T __mh_execute_header
//#define DO_SYM MH_EXECUTE_SYM
// % nm -arch x86_64 -U ./storedownloadd | awk '$2 == "T" && $3 == "__mh_execute_header" { print $1 }'
// 0000000100000000
//#define DO_BAS ((uintptr_t) &_mh_execute_header)
// % dyld_info -arch x86_64 -objc ./storedownloadd | awk '$1 == "class" && $4 == "DecryptOperation" { print $2 }'
// 0x1001157C8
//#define DO_OFF 0x00000001001157C8
int main(int argc, const char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <pkg-path>\n", argv[0]);
return EXIT_FAILURE;
}
const char *pkg_path = argv[1];
// TODO(t0rr3sp3dr0): allow inline base64-encoded dpInfo
// TODO(t0rr3sp3dr0): allow pkg from stdin
// TODO(t0rr3sp3dr0): allow pkg to stdout
// uintptr_t do_off = (uintptr_t) NULL;
//
// @autoreleasepool {
// NSError *error = nil;
//
// NSPipe *pipe = [NSPipe pipe];
//
// NSTask *task = [[NSTask alloc] init];
// [task setLaunchPath:@"/bin/sh"];
// [task setArguments:@[
// @"-c",
// @"dyld_info -arch \"$(uname -m)\" -objc '" @DO_OBJ @"' | awk '$1 == \"class\" && $4 == \"DecryptOperation\" { print $2 }'",
// ]];
// [task setStandardOutput:pipe];
// [task launchAndReturnError:&error];
// if (error) {
// NSLog(@"launchAndReturnError: %@", error);
// return EXIT_FAILURE;
// }
//
// NSData *data = [[pipe fileHandleForReading] readDataToEndOfFileAndReturnError:&error];
// if (error) {
// NSLog(@"readDataToEndOfFileAndReturnError: %@", error);
// return EXIT_FAILURE;
// }
//
// NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//
// unsigned long long ull = 0;
//
// NSScanner *scanner = [NSScanner scannerWithString:output];
// BOOL ret = [scanner scanHexLongLong:&ull];
// if (!ret) {
// NSLog(@"scanner: %hhd", ret);
// return EXIT_FAILURE;
// }
//
// if (ull == +HUGE_VAL) {
// NSLog(@"scanner: +HUGE_VAL");
// return EXIT_FAILURE;
// }
// if (ull == -HUGE_VAL) {
// NSLog(@"scanner: -HUGE_VAL");
// return EXIT_FAILURE;
// }
//
// do_off = ull;
// }
@autoreleasepool {
NSArray <NSString *> *args = [[NSProcessInfo processInfo] arguments];
NSString *pkgPath = args[1];
PKArchive *archive = [PKArchive archiveWithPath:pkgPath];
NSError *error = nil;
BOOL ok = [archive verifyReturningError:&error];
if (error) {
NSLog(@"%@", error);
return EXIT_FAILURE;
}
if (ok) {
NSLog(@"NOOP");
return EXIT_SUCCESS;
}
}
char dec_path[PATH_MAX] = { '\0' };
strcat(dec_path, pkg_path);
strcat(dec_path, ":tmp");
// TODO(t0rr3sp3dr0): check bounds before appending
// TODO(t0rr3sp3dr0): handle EEXIST
int ret0 = clonefile(pkg_path, dec_path, 0);
if (ret0) {
fprintf(stderr, "%s\n", strerror(errno));
return EXIT_FAILURE;
}
// TODO(t0rr3sp3dr0): clean up on failure
void *handle = dlopen("/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storedownloadd", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
return EXIT_FAILURE;
}
// void *symbol = dlsym(handle, DO_SYM);
// if (!symbol) {
// fprintf(stderr, "%s\n", dlerror());
// return EXIT_FAILURE;
// }
//
// unsigned long size = 0;
// void *data = getsectiondata(symbol, "__DATA_CONST", "__objc_classrefs__DATA_CONST", &size);
@autoreleasepool {
// Class _DecryptOperation = nil;
// for (size_t i = 0; i < size / sizeof(Class *); ++i) {
// Class class = (__bridge Class)(data + i * sizeof(Class *));
//
// NSString *name = NSStringFromClass(class);
// if ([name isEqual: @"DecryptOperation"]) {
// _DecryptOperation = class;
// break;
// }
// }
// NSArray <NSString *> *args = [[NSProcessInfo processInfo] arguments];
// NSString *pkgPath = args[1];
NSString *pkgPath = [NSString stringWithCString:dec_path encoding:NSUTF8StringEncoding];
NSError *err0 = nil;
NSData *dpInfo = [[NSFileHandle fileHandleWithStandardInput] readDataToEndOfFileAndReturnError:&err0];
if (err0) {
NSLog(@"%@", err0);
return EXIT_FAILURE;
}
// TODO(t0rr3sp3dr0): check lenght of dpInfo
DecryptOperation *decryptOperation = [[NSClassFromString(@"DecryptOperation") alloc] initWithLocalFilePath:pkgPath dpInfo:dpInfo storeClient:nil];
[decryptOperation run];
PKArchive *archive = [PKArchive archiveWithPath:pkgPath];
NSError *err1 = nil;
BOOL ok = [archive verifyReturningError:&err1];
if (err1) {
NSLog(@"%@", err1);
return EXIT_FAILURE;
}
if (!ok) {
NSLog(@"FAIL");
return EXIT_FAILURE;
}
}
int ret1 = dlclose(handle);
if (ret1) {
fprintf(stderr, "%s\n", dlerror());
return EXIT_FAILURE;
}
int ret2 = rename(dec_path, pkg_path);
if (ret2) {
fprintf(stderr, "%s\n", strerror(errno));
return EXIT_FAILURE;
}
fprintf(stderr, "SUCC\n");
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment