Index: class-dump/src/CDLCSegment.m |
=================================================================== |
--- class-dump/src/CDLCSegment.m (revision 0) |
+++ class-dump/src/CDLCSegment.m (revision 0) |
@@ -0,0 +1,329 @@ |
+// -*- mode: ObjC -*- |
+ |
+// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. |
+// Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard. |
+ |
+#import "CDLCSegment.h" |
+ |
+#import "CDMachOFile.h" |
+#import "CDSection.h" |
+#include <openssl/aes.h> |
+#include <openssl/blowfish.h> |
+ |
+NSString *CDSegmentEncryptionTypeName(CDSegmentEncryptionType type) |
+{ |
+ switch (type) { |
+ case CDSegmentEncryptionTypeNone: return @"None"; |
+ case CDSegmentEncryptionType1: return @"Protected Segment Type 1 (prior to 10.6)"; |
+ case CDSegmentEncryptionType2: return @"Protected Segment Type 2 (10.6)"; |
+ } |
+ |
+ return @"Unknown"; |
+} |
+ |
+@implementation CDLCSegment |
+ |
+- (id)initWithDataCursor:(CDDataCursor *)cursor machOFile:(CDMachOFile *)aMachOFile; |
+{ |
+ if ([super initWithDataCursor:cursor machOFile:aMachOFile] == nil) |
+ return nil; |
+ |
+ name = nil; |
+ sections = [[NSMutableArray alloc] init]; |
+ decryptedData = nil; |
+ |
+ return self; |
+} |
+ |
+- (void)dealloc; |
+{ |
+ [name release]; |
+ [sections release]; |
+ [decryptedData release]; |
+ |
+ [super dealloc]; |
+} |
+ |
+- (NSString *)name; |
+{ |
+ return name; |
+} |
+ |
+- (void)setName:(NSString *)newName; |
+{ |
+ if (newName == name) |
+ return; |
+ |
+ [name release]; |
+ name = [newName retain]; |
+} |
+ |
+- (NSArray *)sections; |
+{ |
+ return sections; |
+} |
+ |
+- (NSUInteger)vmaddr; |
+{ |
+ // Implement in subclasses. |
+ return 0; |
+} |
+ |
+- (NSUInteger)fileoff; |
+{ |
+ // Implement in subclasses. |
+ return 0; |
+} |
+ |
+- (NSUInteger)filesize; |
+{ |
+ // Implement in subclasses. |
+ return 0; |
+} |
+ |
+- (vm_prot_t)initprot; |
+{ |
+ // Implement in subclsses. |
+ return 0; |
+} |
+ |
+- (uint32_t)flags; |
+{ |
+ // Implement in subclsses. |
+ return 0; |
+} |
+ |
+- (BOOL)isProtected; |
+{ |
+ return ([self flags] & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1; |
+} |
+ |
+- (CDSegmentEncryptionType)encryptionType; |
+{ |
+ //NSLog(@"%s, isProtected? %u, filesize: %lu, fileoff: %lu", _cmd, [self isProtected], [self filesize], [self fileoff]); |
+ if ([self isProtected]) { |
+ if ([self filesize] <= 3 * PAGE_SIZE) { |
+ // First three pages aren't encrypted, so we can't tell. Let's pretent it's something we can decrypt. |
+ return CDSegmentEncryptionType1; |
+ } else { |
+ const void *src; |
+ uint32_t magic; |
+ |
+ src = [nonretained_machOFile machODataBytes] + [self fileoff] + 3 * PAGE_SIZE; |
+ |
+ magic = OSReadLittleInt32(src, 0); |
+ //NSLog(@"%s, magic= 0x%08x", _cmd, magic); |
+ switch (magic) { |
+ case CDSegmentProtectedMagicTypeNone: return CDSegmentEncryptionTypeNone; |
+ case CDSegmentProtectedMagicType1: return CDSegmentEncryptionType1; |
+ case CDSegmentProtectedMagicType2: return CDSegmentEncryptionType2; |
+ } |
+ |
+ return CDSegmentEncryptionTypeUnknown; |
+ } |
+ } |
+ |
+ return CDSegmentEncryptionTypeNone; |
+} |
+ |
+- (BOOL)canDecrypt; |
+{ |
+ CDSegmentEncryptionType encryptionType = [self encryptionType]; |
+ |
+ return (encryptionType == CDSegmentEncryptionTypeNone) |
+ || (encryptionType == CDSegmentEncryptionType1) |
+ || (encryptionType == CDSegmentEncryptionType2); |
+} |
+ |
+- (NSString *)flagDescription; |
+{ |
+ NSMutableArray *setFlags; |
+ unsigned long flags; |
+ |
+ setFlags = [NSMutableArray array]; |
+ flags = [self flags]; |
+ if (flags & SG_HIGHVM) |
+ [setFlags addObject:@"HIGHVM"]; |
+ if (flags & SG_FVMLIB) |
+ [setFlags addObject:@"FVMLIB"]; |
+ if (flags & SG_NORELOC) |
+ [setFlags addObject:@"NORELOC"]; |
+ if (flags & SG_PROTECTED_VERSION_1) |
+ [setFlags addObject:@"PROTECTED_VERSION_1"]; |
+ |
+ if ([setFlags count] == 0) |
+ return @"(none)"; |
+ |
+ return [setFlags componentsJoinedByString:@" "]; |
+} |
+ |
+- (NSString *)description; |
+{ |
+ NSString *extra = [self extraDescription]; |
+ |
+ if (extra == nil) { |
+ return [NSString stringWithFormat:@"<%@:%p> name: %@", |
+ NSStringFromClass([self class]), self, |
+ name]; |
+ } |
+ |
+ return [NSString stringWithFormat:@"<%@:%p> name: %@, %@", |
+ NSStringFromClass([self class]), self, |
+ name, extra]; |
+} |
+ |
+- (NSString *)extraDescription; |
+{ |
+ // Implement in subclasses |
+ return nil; |
+} |
+ |
+- (BOOL)containsAddress:(NSUInteger)address; |
+{ |
+ // Implement in subclasses |
+ return NO; |
+} |
+ |
+- (CDSection *)sectionContainingAddress:(NSUInteger)address; |
+{ |
+ for (CDSection *section in sections) { |
+ if ([section containsAddress:address]) |
+ return section; |
+ } |
+ |
+ return nil; |
+} |
+ |
+- (CDSection *)sectionWithName:(NSString *)aName; |
+{ |
+ for (CDSection *section in sections) { |
+ if ([[section sectionName] isEqual:aName]) |
+ return section; |
+ } |
+ |
+ return nil; |
+} |
+ |
+- (NSUInteger)fileOffsetForAddress:(NSUInteger)address; |
+{ |
+ return [[self sectionContainingAddress:address] fileOffsetForAddress:address]; |
+} |
+ |
+- (NSUInteger)segmentOffsetForAddress:(NSUInteger)address; |
+{ |
+ return [self fileOffsetForAddress:address] - [self fileoff]; |
+} |
+ |
+- (void)appendToString:(NSMutableString *)resultString verbose:(BOOL)isVerbose; |
+{ |
+ [super appendToString:resultString verbose:isVerbose]; |
+#if 0 |
+ [resultString appendFormat:@" segname %@\n", [self name]]; |
+ [resultString appendFormat:@" vmaddr 0x%08x\n", segmentCommand.vmaddr]; |
+ [resultString appendFormat:@" vmsize 0x%08x\n", segmentCommand.vmsize]; |
+ [resultString appendFormat:@" fileoff %d\n", segmentCommand.fileoff]; |
+ [resultString appendFormat:@" filesize %d\n", segmentCommand.filesize]; |
+ [resultString appendFormat:@" maxprot 0x%08x\n", segmentCommand.maxprot]; |
+ [resultString appendFormat:@" initprot 0x%08x\n", segmentCommand.initprot]; |
+ [resultString appendFormat:@" nsects %d\n", segmentCommand.nsects]; |
+ |
+ if (isVerbose) |
+ [resultString appendFormat:@" flags %@\n", [self flagDescription]]; |
+ else |
+ [resultString appendFormat:@" flags 0x%x\n", segmentCommand.flags]; |
+#endif |
+ // Implement in subclasses |
+} |
+ |
+- (void)writeSectionData; |
+{ |
+ unsigned int index = 0; |
+ |
+ for (CDSection *section in sections) { |
+ [[section data] writeToFile:[NSString stringWithFormat:@"/tmp/%02d-%@", index, [section sectionName]] atomically:NO]; |
+ index++; |
+ } |
+} |
+ |
+- (NSData *)decryptedData; |
+{ |
+ if ([self isProtected] == NO) |
+ return nil; |
+ |
+ if (decryptedData == nil) { |
+ const void *src; |
+ void *dest; |
+ |
+ //NSLog(@"filesize: %08x, pagesize: %04x", [self filesize], PAGE_SIZE); |
+ NSParameterAssert(([self filesize] % PAGE_SIZE) == 0); |
+ decryptedData = [[NSMutableData alloc] initWithLength:[self filesize]]; |
+ |
+ src = [nonretained_machOFile machODataBytes] + [self fileoff]; |
+ dest = [decryptedData mutableBytes]; |
+ |
+ if ([self filesize] <= PAGE_SIZE * 3) { |
+ memcpy(dest, src, [self filesize]); |
+ } else { |
+ uint32_t magic; |
+ unsigned int index, count; |
+ uint8_t keyData[64] = { 0x6f, 0x75, 0x72, 0x68, 0x61, 0x72, 0x64, 0x77, 0x6f, 0x72, 0x6b, 0x62, 0x79, 0x74, 0x68, 0x65, |
+ 0x73, 0x65, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x67, 0x75, 0x61, 0x72, 0x64, 0x65, 0x64, 0x70, 0x6c, |
+ 0x65, 0x61, 0x73, 0x65, 0x64, 0x6f, 0x6e, 0x74, 0x73, 0x74, 0x65, 0x61, 0x6c, 0x28, 0x63, 0x29, |
+ 0x41, 0x70, 0x70, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x63, }; |
+ |
+ // First three pages are encrypted, just copy |
+ memcpy(dest, src, PAGE_SIZE * 3); |
+ src += PAGE_SIZE * 3; |
+ dest += PAGE_SIZE * 3; |
+ count = ([self filesize] / PAGE_SIZE) - 3; |
+ |
+ magic = OSReadLittleInt32(src, 0); |
+ if (magic == CDSegmentProtectedMagicTypeNone) { |
+ memcpy(dest, src, [self filesize] - PAGE_SIZE * 3); |
+ } else if (magic == CDSegmentProtectedMagicType2) { |
+ // 10.6 decryption |
+ unsigned char ivec[8]; |
+ BF_KEY key; |
+ |
+ BF_set_key(&key, 64, keyData); |
+ |
+ for (index = 0; index < count; index++) { |
+ memset(ivec, 0, 8); |
+ BF_cbc_encrypt(src, dest, PAGE_SIZE, &key, ivec, BF_DECRYPT); |
+ |
+ src += PAGE_SIZE; |
+ dest += PAGE_SIZE; |
+ } |
+ } else if (magic == CDSegmentProtectedMagicType1) { |
+ AES_KEY key1, key2; |
+ |
+ // 10.5 decryption |
+ |
+ AES_set_decrypt_key(keyData, 256, &key1); |
+ AES_set_decrypt_key(keyData + 32, 256, &key2); |
+ |
+ for (index = 0; index < count; index++) { |
+ unsigned char iv1[AES_BLOCK_SIZE]; |
+ unsigned char iv2[AES_BLOCK_SIZE]; |
+ |
+ //NSLog(@"src = %08x, encrypted", src); |
+ memset(iv1, 0, AES_BLOCK_SIZE); |
+ memset(iv2, 0, AES_BLOCK_SIZE); |
+ AES_cbc_encrypt(src, dest, PAGE_SIZE / 2, &key1, iv1, AES_DECRYPT); |
+ AES_cbc_encrypt(src + PAGE_SIZE / 2, dest + PAGE_SIZE / 2, PAGE_SIZE / 2, &key2, iv2, AES_DECRYPT); |
+ |
+ src += PAGE_SIZE; |
+ dest += PAGE_SIZE; |
+ } |
+ } else { |
+ NSLog(@"Unknown encryption type: 0x%08x", magic); |
+ exit(99); |
+ } |
+ } |
+ } |
+ //NSLog(@"decryptedData: %p", decryptedData); |
+ |
+ return decryptedData; |
+} |
+ |
+@end |
Property changes on: class-dump/src/CDLCSegment.m |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |