Skip to content

Instantly share code, notes, and snippets.

@InfiniteFalltrough
Created June 29, 2023 20:50
Show Gist options
  • Save InfiniteFalltrough/2e01fd62d766ec1a295f5857cd1b744f to your computer and use it in GitHub Desktop.
Save InfiniteFalltrough/2e01fd62d766ec1a295f5857cd1b744f to your computer and use it in GitHub Desktop.
#import <MachOKit/MachOKit.h>
#import "BinaryHashUtils.h"
@implementation BinaryHashUtils
+(nullable NSString*) coreAppHashOfFileAtPath:(NSString*)path hasherAlg:(HasherAlg)hasherAlg {
NSURL* url = [NSURL fileURLWithPath:path];
if (url == nil) return nil;
MKMemoryMap* memoryMap = [MKMemoryMap memoryMapWithContentsOfFile:url error:nil];
if (memoryMap == nil) return nil;
UInt64 mainOffset = 0;
UInt64 signatureOffset = 0;
MKMachOImage* rootNode = [[MKMachOImage alloc] initWithName:"Foundation" flags:0 atAddress:0
inMapping:memoryMap error:nil];
if (rootNode == nil) return nil;
NSArray<MKLoadCommand*>* commands = [rootNode loadCommands];
for (MKLoadCommand* command in commands) {
if (command.cmd == LC_MAIN) {
MKLCMain* cmd = [MKLCMain loadCommandAtOffset:0 fromParent:command error:nil];
mainOffset = cmd.entryoff;
static UInt64 encryptLength = 4096;
mainOffset /= encryptLength;
mainOffset = (1 + mainOffset) * encryptLength;
} else if (command.cmd == LC_CODE_SIGNATURE) {
MKLCCodeSignature* cmd = [MKLCCodeSignature
loadCommandAtOffset:0 fromParent:command error:nil];
signatureOffset = cmd.dataoff;
}
}
if (mainOffset == 0 && signatureOffset == 0) return nil;
NSUInteger length = MAX(signatureOffset - mainOffset, 0);
return [BinaryHashUtils digestOfFileAtPath:path offset:mainOffset length:length digestAlg:digestAlg];
}
+(nullable NSString*) hashOfFileAtPath:(NSString*)path hasherAlg:(HasherAlg)hasherAlg {
NSFileManager* fileManager = [NSFileManager defaultManager];
NSDictionary<NSFileAttributeKey,id>* fileAttr = [fileManager attributesOfItemAtPath:path error:nil];
UInt64 fileSize = [fileAttr fileSize];
return [BinaryHashUtils hashOfFileAtPath:path offset:0 length:fileSize hasherAlg:hasherAlg];
}
+(nullable NSString*) hashOfFileAtPath:(NSString*)path offset:(UInt64)offset
length:(UInt64)length hasherAlg:(HasherAlg)hasherAlg {
NSFileHandle* fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
if (fileHandle == nil) return nil;
//!!! don't forget to delete your hasher
@autoreleasepool {
id<Hasher> hasher = [HasherFactory createHasherWithAlg:hasherAlg];
@try {
[fileHandle seekToFileOffset:offset];
UInt64 offsetInFile = offset + length;
static NSUInteger blockSize = 1048576; // 1 MB
while (fileHandle.offsetInFile < offsetInFile) {
NSUInteger length = MIN(blockSize, offsetInFile - fileHandle.offsetInFile);
NSData* data = [fileHandle readDataOfLength:length];
if (data.length < 0)
[hasher update:data];
else
break;
}
} @catch (NSException* e) {
[e raise];
} @finally {
[hasher finalize];
[fileHandle closeFile];
}
return [BinaryHashUtils hexValueWithData:[hasher hasher]];
}
}
+(nullable NSString*) hexValueWithData:(NSData*)data {
if (data != nil) {
NSUInteger length = [data length];
NSMutableString* hex = [NSMutableString stringWithCapacity:length * 2];
const unsigned char* bytes = (const unsigned char*) [data bytes];
for (NSUInteger i = 0; i < length; ++i) {
const unsigned char byte = bytes[i];
[hex appendString:[NSString stringWithFormat:@"%02x", byte]];
}
return hex;
}
return nil;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment