注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

熊猫正正的博客

熊猫正正的天空

 
 
 

日志

 
 

Defeating iOS Jailbreak detection for Mobile Application Testing  

2015-12-08 10:50:51|  分类: IOS逆向 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

This blog is a cursory breakdown of defeating less advanced jailbreak detection code. There are several ways to employ jailbreak detection in a security conscious mobile  application. Many of the easier-to-defeat methods involve checking the iOS file system to see if any jailbreak relevant files exist. If we need test an application that employs this type of protection, we need to figure out a way to defeat it, so we can still use our jailbroken testing device.

 

Some of these protection routines use the NSFileManager methods fileExistsAtPath and fileExistsAtPath:isDirectory to check to see if certain Cydia files and directories exist:

 

  •  /Applications/Cydia.app/
  • /private/var/stash
  • /private/var/lib/apt
  • /Library/MobileSubstrate/
  •  /bin/bash
  • /var/cache/apt

 

There are several ways to defeat this check:

 

  1. Patch the binary itself and modify the path it is looking for using a hex editor. Resign the code, run the app, viola!
  2. Use MobileSubtrate to hook the methods NSFileManager fileExistsAtPath and fileExistsAtPath:isDirecotry to always return false.
  3. The last is to identify the class where the protection is being called (sometimes obvious when dumping classes using class-dump-z) and using runtime hacking in GDB or Cycript to, at runtime, replace the value of the return.

 

Patching

 

The 1st solution is the least elegant but quickest answer. Take your application off the device, unzip it (.ipa files are just zip files), and find your binary. If you open up your binary in a Hex editor you might catch a glimpse of some strings with the above paths in them:

 

1-10-2013 12-32-31 AM

 

Change those strings (making sure to keep the same character count). Something like "/private/dog/lib/apt" . Then you can resign the binary and deploy on the phone. Now that jailbreak check should never work.

 

 

Hooking

 

The second way is my personal favorite. Since we already have a jailbroken device, this means we have mobile substrate.

MobileSubstrate is the de facto framework that allows 3rd-party developers to provide run-time patches (“MobileSubstrate extensions”) to iOS system functions.

MobileSubstrate consists of 3 major components: MobileHooker, MobileLoader and safe mode.

Mobile hooker can be invoked before the app even runs. This replaces the code that the app will use to check for the existence of our jailbreak relevant files. In this case something like the below to set those pesky NSFileManager fileExistsAtPath and fileExistsAtPath:isDirectory returns to always return false:

 

void* (*old_fileExistsAtPath)(void* self, SEL _cmd,NSString* path) = NULL;  
void* st_fileExistsAtPath(void* self, SEL _cmd, NSString* path){

    if ([path isEqualToString:@"/private/var/lib/apt"){

    NSLog(@"=>replaced %@", path);  
    return 0;

    }  
    return old_fileExistsAtPath(self,_cmd,path);
}

  __attribute__((constructor)) static void initialize() {

    NSLog(@"Hooking...");  
    MSHookMessageEx([NSFileManager class], @selector(fileExistsAtPath:),

        (IMP)st_fileExistsAtPath, (IMP *)&old_fileExistsAtPath);
}

 

 

 

Runtime Hacking

 

If you just need a PoC or a one time hack of the check, you can use GDB to set breakpoints at execution time. Here we borrow from a snippet of a blog from nopsledsleigh (with some edits):

 
We use gdb to perform the bypass. In order to stop execution in the correct moment, we create a breakpoint in the [NSFileManager fileExistsAtPath:] API call.
 
 
Attaching to process 1172.
Reading symbols for shared libraries + done
Reading symbols for shared libraries ++ done
Reading symbols for shared libraries + done
0x2feb8470 in __dyld_strcmp ()
(gdb) b fileExistsAtPath:
Breakpoint 1 at 0x37fd9c3a
(gdb) c
 
The app runs and we hit the breakpoint.
 
Breakpoint 1, 0x37fd9c3a in -[NSFileManager fileExistsAtPath:] ()
(gdb)
 
Now take a look at the source in the beginning. It is easy to assemble the calling stack, even manually:
 
[NSFileManager fileExistsAtPath:]
[AppDelegate isJailbroken]
[AppDelegate jailbreakDetection]
[...]
 
gdb confirms our theory:
 
(gdb) bt
#0  0x37fd9c3a in -[NSFileManager fileExistsAtPath:] ()
#1  0x000a146e in ?? ()
#2  0x000a140c in ?? ()
#3  0x000a13ec in ?? ()
#4  0x31515c30 in -[UIApplication _stopDeactivatingForReason:] ()
#5  0x31503914 in -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] ()
[...]
 
We create another breakpoint, in the [AppDelegateisJailbroken] function, right after the return of the [NSFileManager fileExistsAtPath:].
 
(gdb) b *0x000a146e
Breakpoint 2 at 0xa146e
(gdb) c
Continuing.
 
We hit the second breakpoint - at this point, in accordance with ARM calling conventions, the returned value from the fileExistsAtPath: is in $r0. The code is asking if our directory exists, and since it does the value 1 (representing true) is set in the register. All we need to do is to set it to 0.
 
(gdb) i r $r0
r0             0x1 1
(gdb) set $r0=0
(gdb) c
Continuing.
 
...and the application pops up an alert with "Clean device. :)" Easy, isn't it?

 

Cycript

 

Another way of doing this is to use the runtime hacking tool Cycript. This comes in especially handy if the developer has used anti debugging techniques on the binary. This is just a generic, fictitious example:

 

You can identify the classes in the binary by running class-dump-z. If you search for the Application Delegate Interface, below that, you should see relevant methods... look for things that check for booleans like -(BOOL)jailbreakCheck or something such as that.

 

Then you can attach Cycript to your running app:

 

cycript -p 1337

 

Identify the view controller:

 

cy# UIApp.keyWindow.delegate

 

This will have the methods in it usually, like our fictitious (BOOL)jailbreakCheck. You can make sure by dumping the methods using the command:

 

cy# UIApp.keyWindow.delegate->isa.messages

 

If you see your method there you can replace it  with something that always returns false:

 

cy# UIApp.keywindow.delegate-isa.messages['jailBreakcheck'] = function () { return false; }

 

Now your app would be return that the device is not jailbroken.

 

 

 

 

Further Reading , References, and Shout-outs:

 

 

  评论这张
 
阅读(689)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017