Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Reverse Engineering iOS apps. Lessons learned.
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Max Bazaliy
May 15, 2014
Programming
2.9k
21
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Reverse Engineering iOS apps. Lessons learned.
UIKonf, Berlin @ 2014
Max Bazaliy
May 15, 2014
More Decks by Max Bazaliy
See All by Max Bazaliy
Jailbreaking Apple Watch
mbazaliy
3
4.6k
Jailbreaking Apple Watch
mbazaliy
3
27k
Fried Apples: Jailbreak DIY
mbazaliy
1
3.1k
Pegasus Internals
mbazaliy
4
3.9k
Mobile Espionage in the Wild: Pegasus and Nation-State Level Attacks
mbazaliy
1
670
FRAPL - Next Generation Reverse Engineering Framework
mbazaliy
3
520
A Journey Through Exploit Mitigation Techniques on iOS
mbazaliy
2
2.3k
Securing iOS applications
mbazaliy
8
1.8k
Other Decks in Programming
See All in Programming
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
8
5.5k
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
440
Java 27新機能 / Java 27 new features
kishida
2
200
CodeRabbitの効果検証と過ごしてみた3ヶ月
armondando
0
140
ソニーのクラウド共通基盤の変遷とAI時代の開発スタイルに合わせた進化 / The Journey of Sony’s Common Cloud Platform and Its Evolution for AI-Native Development
kenjiyoneyama
0
230
見えないものを探る要求要件定義に必要な基本的思考 / invisible-requirement-thinking
minodriven
13
6.6k
Embedded Swiftで作る自作USBデバイス によるiOSデバイスの自動テスト / iOSDC Japan 2026 glassfiber
glassfiber
0
290
phperだってパンチカードでコーディングしたい
o0h
PRO
0
200
Starting & Sustaining Code-Based E2E Testing for Non-Coding QA Teams( #jasstniigata )
teyamagu
PRO
1
910
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
740
AWSに止められる覚悟してますか?
morizo_1984
2
510
【加筆修正版】Laravel のアプリケーションをどこにデプロイするか #phpcon_ehime
akase244
0
150
Featured
See All Featured
Designing for humans not robots
tammielis
254
26k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.5k
How to Ace a Technical Interview
jacobian
280
24k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
2
930
The Pragmatic Product Professional
lauravandoore
37
7.5k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
620
Music & Morning Musume
bryan
48
7.4k
We Are The Robots
honzajavorek
0
380
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Testing 201, or: Great Expectations
jmmastey
46
8.3k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Mind Mapping
helmedeiros
1
390
Transcript
Reverse Engineering iOS apps UIKonf 2014 Max Bazaliy
@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
None
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-z
@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!
None
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
None
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
None
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 ?
None
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
None
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);}!
None
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?
None
Path check URL check File access Root check Process check
Jailbreak detection
! NSError *error;! NSString *jailTest = @"Jailbreak time!";! [jailTest writeToFile:@"/private/
test_jail.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error];! if(error==nil) {! …! }!
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
None
@mbazaliy