Skip to content

Commit

Permalink
Merge pull request #10 from dhinakg/filter
Browse files Browse the repository at this point in the history
  • Loading branch information
dhinakg authored Jul 8, 2024
2 parents bf78fac + d23e55f commit de2a457
Show file tree
Hide file tree
Showing 14 changed files with 636 additions and 193 deletions.
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ PointerAlignment: Left
ExperimentalAutoDetectBinPacking: true
SpaceBeforeCpp11BracedList: true
IndentPPDirectives: BeforeHash
IncludeBlocks: Regroup
---
Language: ObjC
# Force pointers to the type for C++.
Expand Down
11 changes: 7 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ jobs:
run: make
- name: Test binary
run: |
./aastuff
./aastuff_standalone
./aastuff -h
./aastuff_standalone -h
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -60,6 +60,7 @@ jobs:
unzip -p tests/iPhone_15PM_18.0_22A5282m.ipsw 090-29713-049.dmg.aea > tests/iOS_18_beta_1_IPSW/encrypted.aea
rm tests/iPhone_15PM_18.0_22A5282m.ipsw
printf "$IOS_IPSW_TEST_KEY" > tests/iOS_18_beta_1_IPSW/expected.txt
touch tests/iOS_18_beta_1_IPSW/fast_unsupported
env:
MACOS_OTA_TEST_KEY: ${{ vars.MACOS_OTA_TEST_KEY }}
IOS_IPSW_TEST_KEY: ${{ vars.IOS_IPSW_TEST_KEY }}
Expand All @@ -86,11 +87,13 @@ jobs:
# This file uses a compressed inner layer
# curl -L "https://updates.cdn-apple.com/2024/Iris/mobileassets/003-49672/A1233F60-3D17-491B-803A-DB26E20695AE/com_apple_MobileAsset_UAF_Siri_Understanding/6FF3BAF0-FBEF-4C01-BB0E-30CD61DAFCC4.aar" -o tests/small/encrypted.aea
aria2c -x 16 -s 16 -j 16 --file-allocation=none "https://updates.cdn-apple.com/2024/Iris/mobileassets/003-49672/A1233F60-3D17-491B-803A-DB26E20695AE/com_apple_MobileAsset_UAF_Siri_Understanding/6FF3BAF0-FBEF-4C01-BB0E-30CD61DAFCC4.aar" -o tests/small/encrypted.aea
printf "$SMALL_TEST_KEY" > tests/small/key.txt
printf "$SMALL_TEST_KEY" > tests/small/expected.txt
printf "YEC,UID,GID,MOD,SH2" > tests/small/flags.txt
# This file uses a raw inner layer
# curl -L "https://updates.cdn-apple.com/2024SummerSeed/mobileassets/052-49061/CA7135A8-BAF6-4890-887C-35FB30C154D5/com_apple_MobileAsset_MacSoftwareUpdate/e2de87f20576b2bdc021d36f74a2f836cf42afe576178388dfd0cde875f4f979.aea" -o tests/large/encrypted.aea
aria2c -x 16 -s 16 -j 16 --file-allocation=none "https://updates.cdn-apple.com/2024SummerSeed/mobileassets/052-49061/CA7135A8-BAF6-4890-887C-35FB30C154D5/com_apple_MobileAsset_MacSoftwareUpdate/e2de87f20576b2bdc021d36f74a2f836cf42afe576178388dfd0cde875f4f979.aea" -o tests/large/encrypted.aea
printf "$LARGE_TEST_KEY" > tests/large/key.txt
printf "$LARGE_TEST_KEY" > tests/large/expected.txt
printf "LNK,FLG,UID,GID,MOD,MTM,CTM" > tests/large/flags.txt
env:
SMALL_TEST_KEY: ${{ vars.SMALL_TEST_KEY }}
LARGE_TEST_KEY: ${{ vars.LARGE_TEST_KEY }}
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
.PHONY: all clean test deploy

SRC_FILES = src/aastuff.m src/extract.m src/extract_standalone.m
SRC_FILES = src/aastuff.m src/args.m src/extract.m src/extract_standalone.m
HDR_FILES = include/AppleArchivePrivate.h include/extract.h include/extract_standalone.h

CFLAGS = -fmodules -fobjc-arc -Iinclude -Wall -Werror
CFLAGS = -fmodules -fobjc-arc -Iinclude -Wall -Werror -Wunreachable-code
LDLIBS = -framework Foundation -lAppleArchive
LDFLAGS = -Llib

Expand Down
22 changes: 17 additions & 5 deletions include/AppleArchivePrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,23 @@ __BEGIN_DECLS
// TODO: Figure out how this is different from normal AppleArchive
typedef void* AAAssetExtractor;

AAAssetExtractor AAAssetExtractorCreate(const char* destDir, void** something, int something2);
// AAAssetExtractorSetParameterCallback
// AAAssetExtractorSetParameterPtr
AAAssetExtractor AAAssetExtractorCreate(const char* work_dir, uint64_t* maybe_offset, void* unknown);

// 102: AEA context
// 103: progress
// 104: entry message
// - 90: start?
// - 91: extract?
// - 92: complete
int AAAssetExtractorSetParameterCallback(AAAssetExtractor extractor, int param, void* callback);

// 101: first arg to callbacks
// 105: input directory
// 106: output directory
int AAAssetExtractorSetParameterPtr(AAAssetExtractor extractor, int param, void* ptr);

int AAAssetExtractorWrite(AAAssetExtractor extractor, void* buffer, size_t size);
void AAAssetExtractorDestroy(AAAssetExtractor extractor);
int AAAssetExtractorDestroy(AAAssetExtractor extractor, uint64_t* maybe_offset);

AAArchiveStream AAVerifyDirectoryArchiveOutputStreamOpen(const char* dir, AAFieldKeySet key_set, void* msg_data,
AAEntryMessageProc msg_proc, AAFlagSet flags, int n_threads);
Expand All @@ -23,7 +35,7 @@ typedef uint32_t AAYopType;
APPLE_ARCHIVE_ENUM(AAYopTypes, uint32_t) {
AA_YOP_TYPE_COPY = 'C', ///< copy
AA_YOP_TYPE_EXTRACT = 'E', ///< extract
AA_YOP_TYPE_SRC_CHECK = 'I', ///< extract
AA_YOP_TYPE_SRC_CHECK = 'I', ///< source check
AA_YOP_TYPE_MANIFEST = 'M', ///< manifest
AA_YOP_TYPE_DST_FIXUP = 'O', ///< destination fixup
AA_YOP_TYPE_PATCH = 'P', ///< patch
Expand Down
25 changes: 25 additions & 0 deletions include/args.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef ARGS_H
#define ARGS_H

#import <Foundation/Foundation.h>

@interface ExtractionConfiguration : NSObject <NSCopying>

@property(nonatomic, assign) bool encrypted;
@property(nonatomic, assign) bool list;
@property(nonatomic, strong) NSString* archivePath;
@property(nonatomic, strong) NSString* outputDirectory;
@property(nonatomic, strong) NSData* key;
@property(nonatomic, strong) NSString* filter;
@property(nonatomic, strong) NSRegularExpression* regex;

@property(nonatomic, strong) NSString* function;

- (instancetype)copyWithFunction:(NSString*)function;

@end

ExtractionConfiguration* parseArgs(int argc, char** argv, int* returnCode);
int validateArgs(ExtractionConfiguration* config);

#endif /* ARGS_H */
8 changes: 5 additions & 3 deletions include/extract.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#ifndef EXTRACT_H
#define EXTRACT_H

#include <AppleArchive/AppleArchive.h>
#include <Foundation/Foundation.h>
#import <AppleArchive/AppleArchive.h>
#import <Foundation/Foundation.h>

int extractAsset(AAByteStream stream, NSString* outputDirectory);
#import "args.h"

int extractAsset(AAByteStream stream, ExtractionConfiguration* config);

#endif /* EXTRACT_H */
8 changes: 5 additions & 3 deletions include/extract_standalone.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#ifndef EXTRACT_STANDALONE_H
#define EXTRACT_STANDALONE_H

#include <AppleArchive/AppleArchive.h>
#include <Foundation/Foundation.h>
#import <AppleArchive/AppleArchive.h>
#import <Foundation/Foundation.h>

int extractAssetStandalone(AAByteStream stream, NSString* outputDirectory);
#import "args.h"

int extractAssetStandalone(AAByteStream stream, ExtractionConfiguration* config);

#endif /* EXTRACT_STANDALONE_H */
8 changes: 8 additions & 0 deletions include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@
#define DBGLOG(x, ...)
#endif

#if AASTUFF_STANDALONE
#define NAME @"aastuff_standalone"
#else
#define NAME @"aastuff"
#endif

#define VERSION @"0.0.1"

#endif /* UTILS_H */
94 changes: 12 additions & 82 deletions src/aastuff.m
Original file line number Diff line number Diff line change
@@ -1,110 +1,40 @@
#import <AppleArchive/AppleArchive.h>
#import <Foundation/Foundation.h>

#import "args.h"
#import "extract.h"
#import "extract_standalone.h"
#import "utils.h"

#define APPLE_ARCHIVE_MAGIC @"AA01"
#define APPLE_ENCRYPTED_ARCHIVE_MAGIC @"AEA1"

int main(int argc, char** argv) {
@autoreleasepool {
NSError* error = nil;

if (argc < 3) {
ERRLOG(@"Usage: %s <archive> <output directory> [key in base64]", argv[0]);
ERRLOG(@"Key is required for encrypted archives");
return argc == 1 ? 0 : 1;
}

NSString* archivePath = [NSString stringWithUTF8String:argv[1]];
NSString* outputDirectory = [NSString stringWithUTF8String:argv[2]];
NSString* keyBase64 = nil;
if (argc > 3) {
keyBase64 = [NSString stringWithUTF8String:argv[3]];
int ret = 0;
ExtractionConfiguration* config = parseArgs(argc, argv, &ret);
if (!config) {
return ret;
}

if (!archivePath || !outputDirectory) {
ERRLOG(@"Failed to parse arguments");
return 1;
}

NSFileManager* fileManager = [NSFileManager defaultManager];

if (![fileManager fileExistsAtPath:archivePath]) {
ERRLOG(@"Archive does not exist");
if (validateArgs(config)) {
return 1;
}

BOOL isDirectory = false;
if (![fileManager fileExistsAtPath:outputDirectory isDirectory:&isDirectory]) {
if (![fileManager createDirectoryAtPath:outputDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
ERRLOG(@"Failed to create directory: %@", error);
return 1;
}
} else {
if (!isDirectory) {
ERRLOG(@"Output path is not a directory");
return 1;
}
}

NSFileHandle* handle = [NSFileHandle fileHandleForReadingAtPath:archivePath];
if (!handle) {
ERRLOG(@"Failed to open archive file");
return 1;
}

NSData* magic = [handle readDataUpToLength:4 error:&error];
// If this fails, can't do anything about it, so just ignore the error
[handle closeAndReturnError:nil];

if (!magic || magic.length != 4) {
ERRLOG(@"Failed to read magic: %@", error);
return 1;
}

bool encrypted = false;
NSString* magicStr = [[NSString alloc] initWithData:magic encoding:NSUTF8StringEncoding];
if ([magicStr isEqualToString:APPLE_ENCRYPTED_ARCHIVE_MAGIC]) {
encrypted = true;
} else if ([magicStr isEqualToString:APPLE_ARCHIVE_MAGIC]) {
encrypted = false;
} else {
ERRLOG(@"Unknown magic: %@", magicStr);
return 1;
}

if (encrypted && !keyBase64) {
ERRLOG(@"Encrypted archive requires key");
return 1;
}

AAByteStream stream = AAFileStreamOpenWithPath(archivePath.UTF8String, O_RDONLY, 0644);
AAByteStream stream = AAFileStreamOpenWithPath(config.archivePath.UTF8String, O_RDONLY, 0644);
if (!stream) {
ERRLOG(@"Failed to open archive file stream");
return 1;
}

AAByteStream decryptionStream = NULL;
AEAContext decryptionContext = NULL;
if (encrypted) {
NSData* key = [[NSData alloc] initWithBase64EncodedString:keyBase64 options:0];
if (!key) {
ERRLOG(@"Failed to parse key");
AAByteStreamClose(stream);
return 1;
}

if (config.encrypted) {
decryptionContext = AEAContextCreateWithEncryptedStream(stream);
if (!decryptionContext) {
ERRLOG(@"Failed to create encrypted stream context");
AAByteStreamClose(stream);
return 1;
}

int ret = AEAContextSetFieldBlob(decryptionContext, AEA_CONTEXT_FIELD_SYMMETRIC_KEY, 0, key.bytes, key.length);
int ret = AEAContextSetFieldBlob(decryptionContext, AEA_CONTEXT_FIELD_SYMMETRIC_KEY, 0, config.key.bytes, config.key.length);
if (ret != 0) {
ERRLOG(@"Failed to set key");
AEAContextDestroy(decryptionContext);
Expand All @@ -114,17 +44,17 @@ int main(int argc, char** argv) {

decryptionStream = AEADecryptionInputStreamOpen(stream, decryptionContext, 0, 0);
if (!decryptionStream) {
ERRLOG(@"Failed to open decryption stream");
ERRLOG(@"Failed to open decryption stream (invalid key?)");
AEAContextDestroy(decryptionContext);
AAByteStreamClose(stream);
return 1;
}
}

#if AASTUFF_STANDALONE
if (extractAssetStandalone(encrypted ? decryptionStream : stream, outputDirectory)) {
if (extractAssetStandalone(config.encrypted ? decryptionStream : stream, config)) {
#else
if (extractAsset(encrypted ? decryptionStream : stream, outputDirectory)) {
if (extractAsset(config.encrypted ? decryptionStream : stream, config)) {
#endif
ERRLOG(@"Extracting asset failed");
AEAContextDestroy(decryptionContext);
Expand Down
Loading

0 comments on commit de2a457

Please sign in to comment.