reverse engineering ios apps

Post on 11-Sep-2014

6.135 Views

Category:

Technology

11 Downloads

Preview:

Click to see full reader

DESCRIPTION

UAMobile 2013 talk

TRANSCRIPT

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 @"<mlbD3Z1" #define PTRACE_STRING_ENCODED_HASH

@"F47C218D1285CBC7F66B0FF88B15E10DC6690CBE" #define PTRACE_STRING_DECODED_HASH

@"F4B756A8181E5339D73C9E2F9214E8949D2EE4F2”

#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",!

! ! !@"/Applications/Icy.app",!

! ! !@"/usr/sbin/sshd",!

! ! !@"/usr/bin/sshd",!

! ! !@"/private/var/lib/apt",!

! ! !@"/private/var/lib/cydia”!

! ! ! ! ! ! ! !@"/usr/libexec/sftp-server",!

! ! !@"/Applications/blackra1n.app",!

! ! !@"/private/var/stash"];!

!

NSString *rooted;!

for (NSString *string in jailbrokenPath)!

if ([[NSFileManager defaultManager] fileExistsAtPath:string]) {!

…!

}!

!

!! for (NSDictionary * dict in processes) {!!NSString *process = [dict objectForKey:@"ProcessName"];!!! !if ([process isEqualToString:CYDIA]) {!!! ! ! !...!!! ! ! !}!

}!!

struct stat sb;! stat("/etc/fstab", &sb);! long long size = sb.st_size;! if (size == 80) {!!! ! ! !return NOTJAIL;!

} else!!! ! ! !return JAIL;!

}!

Cracking time =

Protection time

@mbazaliy

top related