Upload
innovecs
View
1.293
Download
1
Tags:
Embed Size (px)
DESCRIPTION
On Saturday, 19 of July, regular quarterly meeting of Tech Hangout Community took place in Creative Space 12, the cultural and educational center based in Kiev! The event was held under the motto “One day of inspiring talks on Mobile Software Development!”. This time enthusiastic and proactive people gathered to share their tips & tricks in mobile software development. *TECH HANGOUT COMMUNITY was found in 2012 by the developers for the developers for knowledge and experience sharing. Such meetings are the part of Innovecs Educational Project that actively develops sphere of internal trainings and knowledge exchange program among professionals. This Initiative was born within the walls of Innovecs and has proved to be extremely popular and high-demand. In a short period of time it gained its own Facebook group with more than 90 members, blog with more than 40 posts and constant quarterly external meeting of Tech hangout community with more than 80 participants. The concept of the event proposes a 30-minute report on the topic previously defined, and the discussion in a roundtable session format. Join to discuss - https://www.facebook.com/groups/techhangout/
Citation preview
Reverse Engineering iOS apps
Max Bazaliy tech hangout
@CocoaHeadsUA iSecurityKit
@mbazaliy github.com/mbazaliy
Security audit Competitor analysis Solution advantages
Why?
It’s fun!
Analysis
Traffic sniffing Module call tracing I/O activity
System
Code Disasm\ Decompiling Debugging Resource reversing
Binary file Image files Interface files Property list files CoreData model files
App files
Compressed pngcrush
appcrush.rb artwork extractor
Image f iles
NIBs Storyboards nib dec
nib_patch
Interface files
*.mom momdec CoreData
Binary
otool class-dump MachOView Hopper cycript Reveal
Tools
Mach-O binary
32 bit (ARMv6,ARMv7)
0xFEEDFACE
64 bit (ARM64)
0xFEEDFACF
Universal binaries (FAT)
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
class-dump
@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;
Binary is encrypted
otool -arch all –Vl MyApp | grep -A5 LC_ENCRYP!
evasi0n.com
> address (cryptoff + cryptsize) size (base address + cryptoff + cryptsize)!
> gdb dump memory decrypted.bin 0x3000 0xD23000 !
> Address space layout randomization!
> 0x1000 -> 0x5000!
> decrypted.bin -> binary!> patch header!
Rasticrac
Clutch
dumpdecrypted
Binary analysis Debugger attach ASLR bypass Binary dump Patch cryptid
Clutch Rasticrac
Binary analysis
Disassembler Debugger Decompiler
Hopper
IDA Disassembler Debugger + objc_helper + Hex-Rays
id objc_msgSend(id self, SEL op, ...)
80% of calls
application: didFinishLaunchingWithOptions:
Hopper Disassembler
Control flow graph
Hopper Disassembler
Decompilation
Hopper Disassembler
! Method names Strings Constants
Dump headers Modify ivars Instantiate objects
Invoking methods Swizzling methods
cycript
cy# UIApp@"<UIApplication: 0x14632f70>"cy# function tryPrintIvars(a){ var x={}; for(i in *a){ try{ x[i] = (*a)[i]; } catch(e){} } return x;}
cy# UIApp.keyWindow.subviews[0].nextResponder.topViewController@"<UINavigationController: 0x14596530>"
cy# UIApp.keyWindow.subviews[0].nextResponder.topViewController.viewControllers[0]@"<JailbreakDetectionVC: 0x15a5ad10>"
cy# JailbreakDetectionVC.messages['isJailbroken'] = function () { return NO };{}
cy# [[[UIView alloc] init] autorelease]@"<UIView: 0x14d71bb0; frame = (0 0; 0 0); layer = <CALayer: 0x14d702b0>>"
Runtime inspection Modify layer Dynamically loaded
Reveal
Foursquare.app
idb iNalyzer Snoop-it Introspy iRET
Special tools
Best practices
Compile with PIE No credentials in plists Disable NSLog Use NSFileProtection
Best practices
Sensitive - keychain View snapshots Cache.db URL Schemes Secure coding guide
No Objective-C Integrity checks SSL pinning Obfuscation
What next ?
Public key Certificate
SSL pinning
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler{ !
""… !
""NSData *localCertificateData = [NSData dataWithContentsOfFile: [[NSBundle mainBundle] pathForResource: @"MyCert” ofType: @"crt"]]; !
"CFDataRef remoteCertificateData = SecCertificateCopyData(remoteVersionOfServerCertificate); !
""BOOL certificatesAreTheSame = !
" [localCertificateData isEqualToData: remoteCertificateData]; !
""NSURLCredential* cred = [NSURLCredential credentialForTrust: serverTrust]; !
""if (certificatesAreTheSame) { !
""completionHandler(NSURLSessionAuthChallengeUseCredential,cred);" "} !
""else {""completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace,nil); !
""} !
- (AFSecurityPolicy*) googleSecurityPolicy { !
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"google" ofType:@"cer"]; !
NSData *certData = [NSData dataWithContentsOfFile:cerPath]; !
AFSecurityPolicy *securityPolicy = [[AFSecurityPolicy alloc] init]; !
[securityPolicy setAllowInvalidCertificates:NO]; !
[securityPolicy setPinnedCertificates:@[certData]]; !
[securityPolicy setSSLPinningMode:AFSSLPinningModeCertificate]; !
return securityPolicy; } !
!
- (void)googleRequest { !
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; !
[manager setSecurityPolicy:[self googleSecurityPolicy]]; !
[manager GET:@"www.google.com" parameters:nil success:^(AFHTTPRequestOperation *operation, NSDictionary* responseObject) { !
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { !
}]; !
}!
Use functions Strip symbols Use #define inline
((always_inline))
Method obfuscation
#define isJailbroken() gbrlp() !static inline int () gbrlp{ !… !} !
XORs Decoding tables Don’t use one key
Strings obfuscation
!
!
!
!
!
#define PTRACE_STRING @"<mlbD3Z1”!
NSString *scInfoString = decodeString(PTRACE_STRING);!!! NSData *encryptedData = ! [RNEncryptor encryptData:data " " " " withSettings:kRNCryptorAES256Settings " " " " " password:@"passw0rd” " " " " " " error:&error]; !
! NSData *decryptedData = ! [RNDecryptor decryptData:data " " " " withSettings:kRNCryptorAES256Settings " " " " " password:@"passw0rd” " " " " " " error:&error]; !
!!
!
!
Deny attach Constructor tricks Change values
Anti debugger
tricks
static int checkGDB() __attribute__((always_inline)) !
{ !
size_t size = sizeof(struct kinfo_proc); !
struct kinfo_proc info; !
memset(&info, 0, sizeof(struct kinfo_proc)); !
!
int ret, name[4]; !
name[0] = CTL_KERN; !
name[1] = KERN_PROC; !
name[2] = KERN_PROC_PID; !
name[3] = getpid(); !
!
if ((ret = (sysctl(name, 4, &info, &size, NULL, 0)))) !
return ret; !
return (info.kp_proc.p_flag & P_TRACED) ? 1 : 0; !
} !
#import <dlfcn.h> !
#import <sys/types.h> !
!
#define PT_DENY_ATTACH 31!
!
typedef int (*ptrace_ptr_t) !
(int _request, pid_t _pid, caddr_t _addr, int _data); !
!
void *handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW); !
ptrace_ptr_t ptrace_ptr = (ptrace_ptr_t)dlsym(handle, [ptraceString UTF8String]); !
ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0); !
dlclose(handle); !
!
SYSCALL
syscall(26, 31, 0, 0, 0);!
ptrace
PT_DENY_ATTACH
+ (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 Is patched SC_Info iTunesMetadata
overdrive tricks
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; !
} !
const char * originalSignature = "5f9b18edc3666be3de79134a40deea5b"; !
const struct mach_header * header; !
Dl_info dlinfo; !
!
uint32_t * textSectionAddr = (uint32_t *)section->addr; !
uint32_t textSectionSize = section->size; !
uint32_t * vmaddr = &segment->vmaddr; !
!
char * textSectionPtr = (char *)((int)header + (int)textSectionAddr - " " " " " " " " " " " " " " " "(int)vmaddr); !
!
unsigned char digest[CC_MD5_DIGEST_LENGTH]; !
char signature[2 * CC_MD5_DIGEST_LENGTH]; !
CC_MD5(textSectionPtr, textSectionSize, digest); !
!
for (int i = 0; i < sizeof(digest); i++) !
"" "sprintf(signature + (2 * i), "%02x", digest[i]); !
return strcmp(originalSignature, signature) == 0; !
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);
NSString *scInfoString = @"SC_Info/"; !
NSString *appleIDString = @"appleId"; !
NSString *appleIDMailAddress = @"[email protected]"; !
NSString *metadataString = @"iTunesMetadata.plist"; !
NSString *downloadInfoKeyString = @"com.apple.iTunesStore.downloadInfo"; !
NSString *accountInfoString = @"accountInfo"; !
!
NSDictionary *iTunesMetadata = [NSDictionary dictionaryWithContentsOfFile:[rootDirectoryPath stringByAppendingPathComponent:metadataString]]; !
NSString *appleID = [iTunesMetadata objectForKey:appleIDString]; !
NSDictionary *accountInfo = [[iTunesMetadata objectForKey:downloadInfoKeyString] objectForKey:accountInfoString]; !
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; ! } ! }!
Class hooksClass = objc_getClass("hooks"); !
Class descriptorsClass = objc_getClass("descriptors"); !
SEL allocWithZoneSelector = sel_registerName("allocWithZone:"); !
!
if (hooksClass != NULL) { !
"Method method = !
" class_getClassMethod(hooksClass, allocWithZoneSelector);!
" method_setImplementation(method, (IMP)nilImplementation); !
} !
!
if (descriptorsClass != NULL) { !
Method method = !
class_getClassMethod(descriptorsClass, allocWithZoneSelector); !
method_setImplementation(method, (IMP)nilImplementation); !
} !
Terminate app Run in demo mode Change behavior
What next?
Path check URL check File access Root check Process check
Jailbreak detection
NSError *error; ! NSString *jailTest = @"Jailbreak time!"; ! ! BOOL success = [jailTest writeToFile: !"@"/private/test_jail.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error]; !
! if (success) { ! …! }!
int result = fork(); !"if (!result) ! exit(0); ! if (result >= 0) ! return isJail; ! return noJail; !
! ! if (system(0)) ! ...! }!
NSURL *FakeURL = [NSURL URLWithString: !@"cydia://package/com.fake.package"]; !! if ([[UIApplication sharedApplication] canOpenURL:FakeURL]) !
return isJail; ! else! return noJail;
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”, !
@"/private/var/stash"]; !
!
for (NSString *string in jailbrokenPaths) ! if ([[NSFileManager defaultManager] " " " " "fileExistsAtPath:string]) { !
…! }!
!!
NSArray *processes = [self runningProcesses]; !
! for (NSDictionary * dict in processes) { !
NSString *process = dict[@"ProcessName"]; !
if ([process isEqualToString:@"MobileCydia"]) " " "{ !
...!
} !!
iMAS
Encrypted Core Data Security checks
Passcode check
Memory security
LLVM Obfuscator
Instructions substitution Control Flow flattening Bogus Control Flow Functions merging
LLVM Obfuscator
Instructions substitution Control Flow flattening Bogus Control Flow Functions merging
Cracking time =
Protection time
@mbazaliy