Reverse Engineering iOS apps

18,534 views
18,053 views

Published on

UAMobile 2013 talk

Published in: Technology
2 Comments
46 Likes
Statistics
Notes
No Downloads
Views
Total views
18,534
On SlideShare
0
From Embeds
0
Number of Embeds
102
Actions
Shares
0
Downloads
297
Comments
2
Likes
46
Embeds 0
No embeds

No notes for slide

Reverse Engineering iOS apps

  1. 1. Reverse Engineering iOS apps
  2. 2. Max Bazaliy Mobile lead at RnR XP practices follower CocoaHeads UA founder
  3. 3. Why? Security audit Competitor analysis Solution advantages FUN !
  4. 4. Analysis
  5. 5. External Traffic sniffing Module call tracing I/O activity
  6. 6. Charles SSL proxying RepeatEdit request Breakpoints Bandwidth throttle
  7. 7. Internal Disassembling Decompiling Debugging Resource reversing
  8. 8. Binary file Image files Interface files Property list files CoreData model files
  9. 9. Image files Compressed => pngcrush => appcrush.rb => artwork extractor
  10. 10. Interface files NIBs Storyboards => nib dec => nib_patch
  11. 11. CoreData Models mom => momdec
  12. 12. Binary
  13. 13. Tools otool otx class-dump MachOView Hopper IDA Cycript
  14. 14. Segment 1 Segment command 2 Segment 2 Mach-O binary Segment command 1 Section 1 data Section 2 data Section 3 data Section 4 data Section 5 data … Section n data
  15. 15. Mach-O header 0xFEEDFACE 0xFEEDFACF 0xCAFEBABE
  16. 16. __TEXT -> code and read only data __objc sections-> data used by runtime
  17. 17. __message_refs __cls_refs __symbols __module_info __class __meta_class __instance_vars __inst_meth __cls_meth __cat_cls_meth __protocol_ext __cat_inst_meth
  18. 18. __message_refs __cls_refs __symbols __module_info __class __meta_class __instance_vars __inst_meth __cls_meth __cat_cls_meth __protocol_ext __cat_inst_meth
  19. 19. @interface RRSubscription : NSObject! {! NSString *_subscriptionID;! !unsigned int _period;! float _price;! NSDate *_creationDate;! }! ! + (id)arrayOfSubscriptionsWithJSONArray:(id)arg1;! + (id)subscriptionWithDictionary:(id)arg1;! ! @property(readonly, nonatomic) NSDate *creationDate;! @property(readonly, nonatomic) float price; ! @property(readonly, nonatomic) unsigned int period; ! !!
  20. 20. FairPlay AES MD5
  21. 21. otool -arch all –Vl MyApp | grep -A5 LC_ENCRYP!
  22. 22. > address (cryptoff + cryptsize) size (base address + cryptoff + cryptsize)! > gdb dump memory decrypted.bin 0x3000 0xD23000 ! > Address space layout randomization! > 0x1000 -> 0x4f000! > decrypted.bin -> binary!
  23. 23. Rasticrac Clutch Crackulous
  24. 24. Binary analysis
  25. 25. Hopper Disassembler Debugger Decompiler IDA Disassembler Debugger + objc_helper
  26. 26. Hopper Disassembler Debugger Decompiler IDA Disassembler Debugger + objc_helper + decompiler
  27. 27. Hopper
  28. 28. id objc_msgSend(id self, SEL op, ...)
  29. 29. application_didFinishLaunchingWithOptions
  30. 30. Control flow graph
  31. 31. asm -> pseudocode
  32. 32. ! Method names Strings Constants rd party 3
  33. 33. Cycript Works at runtime Modify ivars Instantiate objects Invoking methods Swizzling methods
  34. 34. But
  35. 35. What next ? No Objective-C Integrity checks SSL pinning Obfuscation
  36. 36. SSL pinning Public key Certificate
  37. 37. - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge {! …! NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));! NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"MyLocalCertificate" ofType:@"cer"];! NSData *localCertData = [NSData dataWithContentsOfFile:cerPath];! if ([remoteCertificateData isEqualToData:localCertData]) {! [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];! } else {! [[challenge sender] cancelAuthenticationChallenge:challenge];!
  38. 38. #define _AFNETWORKING_PIN_SSL_CERTIFICATES_ 1 ! AFHTTPClient.h! @property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode sslPinningMode; { AFSSLPinningModePublicKey, AFSSLPinningModeCertificate } AFURLConnectionOperation.h When `defaultSSLPinningMode` is defined on `AFHTTPClient` and the Security framework is linked, connections will be validated on all matching certificates with a `.cer` extension in the bundle root.!
  39. 39. Method obfuscation Use functions Strip symbols Use #define inline ((always_inline))
  40. 40. #define isEncrypted() bxtlrz()! static inline BOOL bxtlrz() {! …! }!
  41. 41. Strings obfuscation XORs Encoding keys Encoding table New key for app Use hash
  42. 42. #define PTRACE_STRING_ENCODED @"<mlbD3Z1" #define PTRACE_STRING_ENCODED_HASH @"F47C218D1285CBC7F66B0FF88B15E10DC6690CBE" #define PTRACE_STRING_DECODED_HASH @"F4B756A8181E5339D73C9E2F9214E8949D2EE4F2”
  43. 43. #define verifyDecodedString(encoded, hashE, hashD, success) fweybz(encoded, hashE, hashD, success) static inline NSString * fweybz(NSString *encoded, NSString *hashE, NSString *hashD, BOOL *success) { NSString *decoded = decodedString(encoded); if (success != NULL) { *success = (decoded && [hashFromString(encoded) isEqualToString:hashEncoded] && [hashFromString(decoded) isEqualToString:hashDecoded]) ? YES : NO; return decoded; }
  44. 44. Anti debugger tricks Deny attach Constructor -> nil Change values
  45. 45. #define denyDebugger() tmzpw()! static __inline__ void tmzpw() {! if (getuid() != 0) {! !NSString *ptraceString = .. ! !void *handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);! ptrace_ptr_t ptrace_ptr = (ptrace_ptr_t)dlsym(handle, ptraceString);! ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);! dlclose(handle);! }! else! *(volatile int *)NULL = 0xDEADBEEF;! }!
  46. 46. ASSEMBLER
  47. 47. mov r0, #31 ! mov r1, #0 ! mov r2, #0 ! mov r3, #0 ! mov ip, #26 ! svc #0x80 !
  48. 48. int main(int argc, char *argv[])! {! @autoreleasepool {! denyDebugger();! return UIApplicationMain(argc, argv, nil, nil));! }! }!
  49. 49. + (PurchaseManager *)sharedManager {! if (isDebugged())! !return nil;! static PurchaseManager *sharedPurchaseManager = nil; ! static dispatch_once_t onceToken;! !dispatch_once(&onceToken, ^{ ! !! !sharedPurchaseManager = [[self alloc] init];! });! !return sharedPurchaseManager ; ! }!
  50. 50. Integrity checks Is encrypted SC_Info dir iTunesMetadata .dylib files
  51. 51. const struct mach_header *header = (struct mach_header *)dlinfo.dli_fbase; struct load_command *cmd = (struct load_command *) (header + 1); for (uint32_t i = 0; cmd != NULL && i < header->ncmds; i++) { if (cmd->cmd == LC_ENCRYPTION_INFO) { struct encryption_info_command *crypt_cmd = (struct encryption_info_command *)cmd; if (crypt_cmd->cryptid < 1) return NO; else return YES; } else cmd = (struct load_command *)((uint8_t *) cmd + cmd->cmdsize); } return NO;
  52. 52. BOOL isDirectory = NO; NSString *directoryPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@”SC_Info/”]; BOOL directoryExists = [[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:&isDirectory]; BOOL contentSeemsValid = ([[[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:NULL] count] == 2);
  53. 53. !NSDictionary *iTunesMetadata = [NSDictionary !dictionaryWithContentsOfFile:[rootDirectoryPath !stringByAppendingPathComponent:@” iTunesMetadata.plist”]];! !NSString *appleID = iTunesMetadata[appleID];! NSDictionary *accountInfo = iTunesMetadata[downloadInfoKey][accountInfo];! !BOOL isValidAppleID = (appleID.length > 0 && ![appleID rangeOfString:appleIDMailAddress !options:NSCaseInsensitiveSearch].location == !NSNotFound);! BOOL isValidDownloadInfo = (accountInfo.count > 0);!
  54. 54. BOOL dyLibFound = NO; NSArray *directoryFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath: [[NSBundle mainBundle] bundlePath] error:NULL]; for (NSString *filename in directoryFiles) { if ([[filename pathExtension] caseInsensitiveCompare:@”dylib”] == NSOrderedSame) { dyLibFound = YES; break; } }!
  55. 55. What next? Terminate app Run in demo mode Change behavior
  56. 56. Jailbreak detection Path check File access Root check Process name System files
  57. 57. ! NSError *error; ! NSString *jailTest = @”Jailbreak time!";! [jailTest writeToFile:@"/private/test_jail.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error];! if(error==nil) {! …! }! !
  58. 58. if (getuid() == 0) {! …! }! ! ! if (system(0)) {! ...! }!
  59. 59. NSArray *jailbrokenPaths = @[@"/Applications/Cydia.app",! ! ! !@"/usr/sbin/sshd",! ! !@"/usr/bin/sshd",! ! ! !@"/private/var/lib/apt",! ! ! !@"/private/var/lib/cydia”! ! ! !@"/usr/libexec/sftp-server",! ! ! !@"/Applications/blackra1n.app",! ! ! !@"/Applications/Icy.app",! ! ! ! ! ! !@"/Applications/RockApp.app",! ! !! ! ! !@"/private/var/stash"];! ! NSString *rooted;! for (NSString *string in jailbrokenPath)! if ([[NSFileManager defaultManager] fileExistsAtPath:string]) {! …! }!
  60. 60. ! ! for (NSDictionary * dict in processes) {! !NSString *process = [dict objectForKey:@"ProcessName"];! !! !if ([process isEqualToString:CYDIA]) {! !! ! ! !...! !! ! ! !}! }! !
  61. 61. struct stat sb;! stat("/etc/fstab", &sb);! long long size = sb.st_size;! if (size == 80) {! !! ! ! !return NOTJAIL;! } else! !! ! ! !return JAIL;! }!
  62. 62. Cracking time = Protection time
  63. 63. @mbazaliy

×