Reverse Engineering iOS apps

Embed Size (px)

DESCRIPTION

UAMobile 2013 talk

Text of Reverse Engineering iOS apps

  • Reverse Engineering

    iOS apps

  • Mobile lead at RnR XP practices follower CocoaHeads UA founder

    Max Bazaliy

  • Security audit Competitor analysis Solution advantages FUN !

    Why?

  • Analysis

  • Traffic sniffing Module call tracing I/O activity

    External

  • SSL proxying Repeat\Edit request Breakpoints Bandwidth throttle

    Charles

  • Disassembling Decompiling Debugging Resource reversing

    Internal

  • Binary file Image files Interface files Property list files CoreData model files

  • Compressed => pngcrush => appcrush.rb => artwork extractor

    Image files

  • NIBs Storyboards => nib dec => nib_patch

    Interface files

  • mom => momdec CoreData Models

  • Binary

  • otool \ otx class-dump MachOView Hopper \ IDA Cycript

    Tools

  • Mach-O binary

    Section 1 data

    Section 2 data

    Section 3 data

    Section 4 data

    Section 5 data

    Section n data S

    egm

    ent 1

    S

    egm

    ent 2

    Segment command 1 Segment command 2

  • 0xFEEDFACE 0xFEEDFACF 0xCAFEBABE

    Mach-O header

  • __TEXT -> code and read only data

    __objc sections-> data used by runtime

  • __message_refs __cls_refs __symbols __module_info __class __meta_class

    __instance_vars __inst_meth __cls_meth __cat_cls_meth __protocol_ext __cat_inst_meth

  • __message_refs __cls_refs __symbols __module_info __class __meta_class

    __instance_vars __inst_meth __cls_meth __cat_cls_meth __protocol_ext __cat_inst_meth

  • @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; !

  • FairPlay

    AES MD5

  • otool -arch all Vl MyApp | grep -A5 LC_ENCRYP!

  • > address (cryptoff + cryptsize) size (base address + cryptoff + cryptsize)!

    > gdb dump memory decrypted.bin 0x3000 0xD23000 !

    > Address space layout randomization!

    > 0x1000 -> 0x4f000!

    > decrypted.bin -> binary!

  • Rasticrac

    Clutch

    Crackulous

  • Binary analysis

  • Disassembler Debugger Decompiler

    Hopper

    IDA Disassembler Debugger + objc_helper

  • Disassembler Debugger Decompiler

    Hopper

    IDA Disassembler Debugger + objc_helper + decompiler

  • Hopper

  • id objc_msgSend(id self, SEL op, ...)

  • application_didFinishLaunchingWithOptions

  • Control flow graph

  • asm -> pseudocode

  • ! Method names Strings Constants 3rd party

  • Works at runtime Modify ivars Instantiate objects

    Invoking methods Swizzling methods

    Cycript

  • But

  • No Objective-C Integrity checks SSL pinning Obfuscation

    What next ?

  • Public key Certificate

    SSL pinning

  • - (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];!}!

  • #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.!

  • Use functions Strip symbols Use #define inline

    ((always_inline))

    Method obfuscation

  • #define isEncrypted() bxtlrz()!static inline BOOL bxtlrz() {!!}!

  • XORs Encoding keys Encoding table New key for app

    Use hash

    Strings obfuscation

  • #define PTRACE_STRING_ENCODED @"
  • #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;

    }

  • Deny attach Constructor -> nil Change values

    Anti debugger

    tricks

  • #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;!}!

  • ASSEMBLER

  • mov r0, #31!mov r1, #0!mov r2, #0!mov r3, #0!mov ip, #26!svc #0x80!

  • int main(int argc, char *argv[])!{! @autoreleasepool {!

    denyDebugger();! return UIApplicationMain(argc, argv, nil, nil));! }!}!

  • + (PurchaseManager *)sharedManager {!if (isDebugged())!

    !return nil;!static PurchaseManager *sharedPurchaseManager = nil; !static dispatch_once_t onceToken;! !dispatch_once(&onceToken, ^{ !

    ! ! !sharedPurchaseManager = [[self alloc] init];! });!

    !return sharedPurchaseManager ; !}!

  • Is encrypted SC_Info dir iTunesMetadata

    .dylib files

    Integrity checks

  • 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;

  • 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);

  • !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);!

  • 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; } }!

  • Terminate app Run in demo mode Change behavior

    What next?

  • Path check File access Root check Process name System files

    Jailbreak detection

  • !NSError *error; !NSString *jailTest = @Jailbreak time!";![jailTest writeToFile:@"/private/test_jail.txt"

    atomically:YES encoding:NSUTF8StringEncoding error:&error];!

    if(error==nil) {!!}!!

  • if (getuid() == 0) {!! }!!! if (system(0)) {!...! }!

  • NSArray *jailbrokenPaths = @[@"/Applications/Cydia.app",! ! ! !@"/Applications/RockApp.app",! ! ! !@"/Applicatio