OLD | NEW |
(Empty) | |
| 1 // -*- mode: ObjC -*- |
| 2 |
| 3 // This file is part of class-dump, a utility for examining the Objective-C seg
ment of Mach-O files. |
| 4 // Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard. |
| 5 |
| 6 #import "CDLCSegment.h" |
| 7 |
| 8 #import "CDMachOFile.h" |
| 9 #import "CDSection.h" |
| 10 #include <openssl/aes.h> |
| 11 #include <openssl/blowfish.h> |
| 12 |
| 13 NSString *CDSegmentEncryptionTypeName(CDSegmentEncryptionType type) |
| 14 { |
| 15 switch (type) { |
| 16 case CDSegmentEncryptionTypeNone: return @"None"; |
| 17 case CDSegmentEncryptionType1: return @"Protected Segment Type 1 (prior to
10.6)"; |
| 18 case CDSegmentEncryptionType2: return @"Protected Segment Type 2 (10.6)"; |
| 19 } |
| 20 |
| 21 return @"Unknown"; |
| 22 } |
| 23 |
| 24 @implementation CDLCSegment |
| 25 |
| 26 - (id)initWithDataCursor:(CDDataCursor *)cursor machOFile:(CDMachOFile *)aMachOF
ile; |
| 27 { |
| 28 if ([super initWithDataCursor:cursor machOFile:aMachOFile] == nil) |
| 29 return nil; |
| 30 |
| 31 name = nil; |
| 32 sections = [[NSMutableArray alloc] init]; |
| 33 decryptedData = nil; |
| 34 |
| 35 return self; |
| 36 } |
| 37 |
| 38 - (void)dealloc; |
| 39 { |
| 40 [name release]; |
| 41 [sections release]; |
| 42 [decryptedData release]; |
| 43 |
| 44 [super dealloc]; |
| 45 } |
| 46 |
| 47 - (NSString *)name; |
| 48 { |
| 49 return name; |
| 50 } |
| 51 |
| 52 - (void)setName:(NSString *)newName; |
| 53 { |
| 54 if (newName == name) |
| 55 return; |
| 56 |
| 57 [name release]; |
| 58 name = [newName retain]; |
| 59 } |
| 60 |
| 61 - (NSArray *)sections; |
| 62 { |
| 63 return sections; |
| 64 } |
| 65 |
| 66 - (NSUInteger)vmaddr; |
| 67 { |
| 68 // Implement in subclasses. |
| 69 return 0; |
| 70 } |
| 71 |
| 72 - (NSUInteger)fileoff; |
| 73 { |
| 74 // Implement in subclasses. |
| 75 return 0; |
| 76 } |
| 77 |
| 78 - (NSUInteger)filesize; |
| 79 { |
| 80 // Implement in subclasses. |
| 81 return 0; |
| 82 } |
| 83 |
| 84 - (vm_prot_t)initprot; |
| 85 { |
| 86 // Implement in subclsses. |
| 87 return 0; |
| 88 } |
| 89 |
| 90 - (uint32_t)flags; |
| 91 { |
| 92 // Implement in subclsses. |
| 93 return 0; |
| 94 } |
| 95 |
| 96 - (BOOL)isProtected; |
| 97 { |
| 98 return ([self flags] & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1; |
| 99 } |
| 100 |
| 101 - (CDSegmentEncryptionType)encryptionType; |
| 102 { |
| 103 //NSLog(@"%s, isProtected? %u, filesize: %lu, fileoff: %lu", _cmd, [self isP
rotected], [self filesize], [self fileoff]); |
| 104 if ([self isProtected]) { |
| 105 if ([self filesize] <= 3 * PAGE_SIZE) { |
| 106 // First three pages aren't encrypted, so we can't tell. Let's pret
ent it's something we can decrypt. |
| 107 return CDSegmentEncryptionType1; |
| 108 } else { |
| 109 const void *src; |
| 110 uint32_t magic; |
| 111 |
| 112 src = [nonretained_machOFile machODataBytes] + [self fileoff] + 3 *
PAGE_SIZE; |
| 113 |
| 114 magic = OSReadLittleInt32(src, 0); |
| 115 //NSLog(@"%s, magic= 0x%08x", _cmd, magic); |
| 116 switch (magic) { |
| 117 case CDSegmentProtectedMagicTypeNone: return CDSegmentEncryptionTy
peNone; |
| 118 case CDSegmentProtectedMagicType1: return CDSegmentEncryptionType1
; |
| 119 case CDSegmentProtectedMagicType2: return CDSegmentEncryptionType2
; |
| 120 } |
| 121 |
| 122 return CDSegmentEncryptionTypeUnknown; |
| 123 } |
| 124 } |
| 125 |
| 126 return CDSegmentEncryptionTypeNone; |
| 127 } |
| 128 |
| 129 - (BOOL)canDecrypt; |
| 130 { |
| 131 CDSegmentEncryptionType encryptionType = [self encryptionType]; |
| 132 |
| 133 return (encryptionType == CDSegmentEncryptionTypeNone) |
| 134 || (encryptionType == CDSegmentEncryptionType1) |
| 135 || (encryptionType == CDSegmentEncryptionType2); |
| 136 } |
| 137 |
| 138 - (NSString *)flagDescription; |
| 139 { |
| 140 NSMutableArray *setFlags; |
| 141 unsigned long flags; |
| 142 |
| 143 setFlags = [NSMutableArray array]; |
| 144 flags = [self flags]; |
| 145 if (flags & SG_HIGHVM) |
| 146 [setFlags addObject:@"HIGHVM"]; |
| 147 if (flags & SG_FVMLIB) |
| 148 [setFlags addObject:@"FVMLIB"]; |
| 149 if (flags & SG_NORELOC) |
| 150 [setFlags addObject:@"NORELOC"]; |
| 151 if (flags & SG_PROTECTED_VERSION_1) |
| 152 [setFlags addObject:@"PROTECTED_VERSION_1"]; |
| 153 |
| 154 if ([setFlags count] == 0) |
| 155 return @"(none)"; |
| 156 |
| 157 return [setFlags componentsJoinedByString:@" "]; |
| 158 } |
| 159 |
| 160 - (NSString *)description; |
| 161 { |
| 162 NSString *extra = [self extraDescription]; |
| 163 |
| 164 if (extra == nil) { |
| 165 return [NSString stringWithFormat:@"<%@:%p> name: %@", |
| 166 NSStringFromClass([self class]), self, |
| 167 name]; |
| 168 } |
| 169 |
| 170 return [NSString stringWithFormat:@"<%@:%p> name: %@, %@", |
| 171 NSStringFromClass([self class]), self, |
| 172 name, extra]; |
| 173 } |
| 174 |
| 175 - (NSString *)extraDescription; |
| 176 { |
| 177 // Implement in subclasses |
| 178 return nil; |
| 179 } |
| 180 |
| 181 - (BOOL)containsAddress:(NSUInteger)address; |
| 182 { |
| 183 // Implement in subclasses |
| 184 return NO; |
| 185 } |
| 186 |
| 187 - (CDSection *)sectionContainingAddress:(NSUInteger)address; |
| 188 { |
| 189 for (CDSection *section in sections) { |
| 190 if ([section containsAddress:address]) |
| 191 return section; |
| 192 } |
| 193 |
| 194 return nil; |
| 195 } |
| 196 |
| 197 - (CDSection *)sectionWithName:(NSString *)aName; |
| 198 { |
| 199 for (CDSection *section in sections) { |
| 200 if ([[section sectionName] isEqual:aName]) |
| 201 return section; |
| 202 } |
| 203 |
| 204 return nil; |
| 205 } |
| 206 |
| 207 - (NSUInteger)fileOffsetForAddress:(NSUInteger)address; |
| 208 { |
| 209 return [[self sectionContainingAddress:address] fileOffsetForAddress:address
]; |
| 210 } |
| 211 |
| 212 - (NSUInteger)segmentOffsetForAddress:(NSUInteger)address; |
| 213 { |
| 214 return [self fileOffsetForAddress:address] - [self fileoff]; |
| 215 } |
| 216 |
| 217 - (void)appendToString:(NSMutableString *)resultString verbose:(BOOL)isVerbose; |
| 218 { |
| 219 [super appendToString:resultString verbose:isVerbose]; |
| 220 #if 0 |
| 221 [resultString appendFormat:@" segname %@\n", [self name]]; |
| 222 [resultString appendFormat:@" vmaddr 0x%08x\n", segmentCommand.vmaddr]; |
| 223 [resultString appendFormat:@" vmsize 0x%08x\n", segmentCommand.vmsize]; |
| 224 [resultString appendFormat:@" fileoff %d\n", segmentCommand.fileoff]; |
| 225 [resultString appendFormat:@" filesize %d\n", segmentCommand.filesize]; |
| 226 [resultString appendFormat:@" maxprot 0x%08x\n", segmentCommand.maxprot]; |
| 227 [resultString appendFormat:@" initprot 0x%08x\n", segmentCommand.initprot]; |
| 228 [resultString appendFormat:@" nsects %d\n", segmentCommand.nsects]; |
| 229 |
| 230 if (isVerbose) |
| 231 [resultString appendFormat:@" flags %@\n", [self flagDescription]]; |
| 232 else |
| 233 [resultString appendFormat:@" flags 0x%x\n", segmentCommand.flags]; |
| 234 #endif |
| 235 // Implement in subclasses |
| 236 } |
| 237 |
| 238 - (void)writeSectionData; |
| 239 { |
| 240 unsigned int index = 0; |
| 241 |
| 242 for (CDSection *section in sections) { |
| 243 [[section data] writeToFile:[NSString stringWithFormat:@"/tmp/%02d-%@",
index, [section sectionName]] atomically:NO]; |
| 244 index++; |
| 245 } |
| 246 } |
| 247 |
| 248 - (NSData *)decryptedData; |
| 249 { |
| 250 if ([self isProtected] == NO) |
| 251 return nil; |
| 252 |
| 253 if (decryptedData == nil) { |
| 254 const void *src; |
| 255 void *dest; |
| 256 |
| 257 //NSLog(@"filesize: %08x, pagesize: %04x", [self filesize], PAGE_SIZE); |
| 258 NSParameterAssert(([self filesize] % PAGE_SIZE) == 0); |
| 259 decryptedData = [[NSMutableData alloc] initWithLength:[self filesize]]; |
| 260 |
| 261 src = [nonretained_machOFile machODataBytes] + [self fileoff]; |
| 262 dest = [decryptedData mutableBytes]; |
| 263 |
| 264 if ([self filesize] <= PAGE_SIZE * 3) { |
| 265 memcpy(dest, src, [self filesize]); |
| 266 } else { |
| 267 uint32_t magic; |
| 268 unsigned int index, count; |
| 269 uint8_t keyData[64] = { 0x6f, 0x75, 0x72, 0x68, 0x61, 0x72, 0x64, 0x
77, 0x6f, 0x72, 0x6b, 0x62, 0x79, 0x74, 0x68, 0x65, |
| 270 0x73, 0x65, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x
67, 0x75, 0x61, 0x72, 0x64, 0x65, 0x64, 0x70, 0x6c, |
| 271 0x65, 0x61, 0x73, 0x65, 0x64, 0x6f, 0x6e, 0x
74, 0x73, 0x74, 0x65, 0x61, 0x6c, 0x28, 0x63, 0x29, |
| 272 0x41, 0x70, 0x70, 0x6c, 0x65, 0x43, 0x6f, 0x
6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x63, }; |
| 273 |
| 274 // First three pages are encrypted, just copy |
| 275 memcpy(dest, src, PAGE_SIZE * 3); |
| 276 src += PAGE_SIZE * 3; |
| 277 dest += PAGE_SIZE * 3; |
| 278 count = ([self filesize] / PAGE_SIZE) - 3; |
| 279 |
| 280 magic = OSReadLittleInt32(src, 0); |
| 281 if (magic == CDSegmentProtectedMagicTypeNone) { |
| 282 memcpy(dest, src, [self filesize] - PAGE_SIZE * 3); |
| 283 } else if (magic == CDSegmentProtectedMagicType2) { |
| 284 // 10.6 decryption |
| 285 unsigned char ivec[8]; |
| 286 BF_KEY key; |
| 287 |
| 288 BF_set_key(&key, 64, keyData); |
| 289 |
| 290 for (index = 0; index < count; index++) { |
| 291 memset(ivec, 0, 8); |
| 292 BF_cbc_encrypt(src, dest, PAGE_SIZE, &key, ivec, BF_DECRYPT)
; |
| 293 |
| 294 src += PAGE_SIZE; |
| 295 dest += PAGE_SIZE; |
| 296 } |
| 297 } else if (magic == CDSegmentProtectedMagicType1) { |
| 298 AES_KEY key1, key2; |
| 299 |
| 300 // 10.5 decryption |
| 301 |
| 302 AES_set_decrypt_key(keyData, 256, &key1); |
| 303 AES_set_decrypt_key(keyData + 32, 256, &key2); |
| 304 |
| 305 for (index = 0; index < count; index++) { |
| 306 unsigned char iv1[AES_BLOCK_SIZE]; |
| 307 unsigned char iv2[AES_BLOCK_SIZE]; |
| 308 |
| 309 //NSLog(@"src = %08x, encrypted", src); |
| 310 memset(iv1, 0, AES_BLOCK_SIZE); |
| 311 memset(iv2, 0, AES_BLOCK_SIZE); |
| 312 AES_cbc_encrypt(src, dest, PAGE_SIZE / 2, &key1, iv1, AES_DE
CRYPT); |
| 313 AES_cbc_encrypt(src + PAGE_SIZE / 2, dest + PAGE_SIZE / 2, P
AGE_SIZE / 2, &key2, iv2, AES_DECRYPT); |
| 314 |
| 315 src += PAGE_SIZE; |
| 316 dest += PAGE_SIZE; |
| 317 } |
| 318 } else { |
| 319 NSLog(@"Unknown encryption type: 0x%08x", magic); |
| 320 exit(99); |
| 321 } |
| 322 } |
| 323 } |
| 324 //NSLog(@"decryptedData: %p", decryptedData); |
| 325 |
| 326 return decryptedData; |
| 327 } |
| 328 |
| 329 @end |
OLD | NEW |