codephp
软件环境:Xcode
硬件环境:iPhone5越狱手机、Mac
开发工具: Cycript、LLDB、logos Tweak、hopper、MonkeyDev、AFLEXLoader、dumpdecrypted、debugserver、ssh、class_dump、hookhtml
本文采用tweak 的方式进行MSHookFunctionios
初始化应用程序,而不是运行中附着git
iPhone:~ root# debugserver -x posix *:12345 /var/mobile/Containers/Bundle/Application/A612F542-81EF-456A-A6A0-B23046EF57BA/AlipayWallet.app/AlipayWallet
初始化程序,目的是从程序入口就开始进行附着,这样咱们就能够在一些安全防御代码执行以前,进行破解。 最经常使用的就是跳过ptrace:
过命令thread return直接返回,以跳过函数的逻辑。程序员
(lldb) br set -n ptrace Breakpoint 2: where = libsystem_kernel.dylib`__ptrace, address = 0x00000001966af2d4 (lldb) br command add 2 Enter your debugger command(s). Type 'DONE' to end. > thread return > c > DONE
iPhone:~ root# ps -e |grep AlipayWallet 714 ?? 0:26.44 /var/mobile/Containers/Bundle/Application/A612F542-81EF-456A-A6A0-B23046EF57BA/AlipayWallet.app/AlipayWallet 736 ttys000 0:00.01 grep AlipayWallet
iPhone:~ root# cycript -p AlipayWallet cy# [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0] #"file:///var/mobile/Containers/Data/Application/89313E1C-76C2-41E3-8ECD-F4BDC1A78524/Documents/"
devzkndeMacBook-Pro:decrypted devzkn$ scp /Users/devzkn/Downloads/kevin-software/ios-Reverse_Engineering/dumpdecrypted-master/dumpdecrypted.dylib iphone150:/var/mobile/Containers/Data/Application/89313E1C-76C2-41E3-8ECD-F4BDC1A78524/Documents/
devzkndeMacBook-Pro:decrypted devzkn$ scp iphone150:/var/mobile/Containers/Data/Application/89313E1C-76C2-41E3-8ECD-F4BDC1A78524/Documents/AlipayWallet.decrypted /Users/devzkn/decrypted/AlipayWallet
devzkndeMacBook-Pro:bin devzkn$ class-dump --arch armv7 /Users/devzkn/decrypted/AlipayWallet10.1.8/AlipayWallet.decrypted -H -o /Users/devzkn/decrypted/AlipayWallet10.1.8/head
TBSDKMTOPServer
修改com.apple.springboard为iphoneclientgithub
iPhone:~ root# cycript -p AlipayWallet cy# [[NSBundle mainBundle] bundleIdentifier] @"com.alipay.iphoneclient"
%hook DFClientDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { %log(); // 打印某个类的全部方法的,查看全部方法的执行顺序 [KNHook hookClass:@"H5WebViewController"];//aluLoginViewController [KNHook hookClass:@"TBSDKServer"];//getUaPageName aluMTopService _tokenLoginInvoker [KNHook hookClass:@"TBSDKMTOPServer"];//getUaPageName aluMTopService _tokenLoginInvoker return %orig; } %end
Nov 28 18:36:20 iPhone AlipayWallet[1246] <Warning>: KNHooklog :-(void)loadJs:(have 1 value) return:(null) value1:__NSCFString-->(function(){if(window.NEBULAHASADDEDTOUCHEVENT){return;};function onDOMReady(callback){var readyRE=/complete|loaded|interactive/;if(readyRE.test(document.readyState)){setTimeout(function(){callback();},1);}else{document.defaultView.addEventListener('DOMContentLoaded',function(){callback();},false);}} onDOMReady(function(){document.addEventListener("touchstart",function(event){AlipayJSBridge.call("reportClickTime");},false);});window.NEBULAHASADDEDTOUCHEVENT=true;})(); object:<H5WebViewController: 0x5a40800>
reportClickTimeweb
Nov 28 18:46:07 iPhone AlipayWallet[1246] <Warning>: KNHooklog :-(void)resetWebviewDomainLabelText:(have 1 value) return:(null) value1:NSURL-->https://render.alipay.com/p/f/fd-j6lzqrgm/addressbook.html?__webview_options__=canPullDown%3DNO%26showOptionMenu%3DNO%26transparent%3DNO%26networkIndicator%3DYES object:<H5WebViewController: 0x4a34600> ##########################################
https://render.alipay.com/p/f/fd-j6lzqrgm/addressbook.html?__webview_options__=canPullDown=NO&showOptionMenu=NO&transparent=NO&networkIndicator=YES
NSURLRequest *_originalHttpsRequest;
char -[AliH5WebViewController webView:shouldStartLoadWithRequest:navigationType:](void * self, void * _cmd, void * arg2, void * arg3, int arg4) {
else { sub_e0afcc(*ivar_offset(_originalHttpsRequest) + r8, stack[2051]); loc_e0afa4(@class(NSURLConnection), @selector(alloc), 0x39e724c); r8->_urlConnection = loc_e0afa4(); loc_e0afa0(r8->_urlConnection, r8->_urlConnection); loc_e0afa4(r8->_urlConnection, @selector(start)); r5 = 0x0; } goto loc_d14f42;
void -[H5WebViewController callExternNativeApi:](void * self, void * _cmd, void * arg2) { r6 = sub_2a0e18c(); sub_2a0e184(); r5 = sub_2a0e188(); sub_2a0e184(); sub_2a0e180(); loc_2a0e1a4(r5, @selector(callExternNativeApi:webviewcontroller:), r6); return; }
iPhone:~ root# debugserver *:12345 -a AlipayWallet debugserver-@(#)PROGRAM:debugserver PROJECT:debugserver-320.2.89 for armv7. Attaching to process AlipayWallet... Segmentation fault: 11
当程序运行后,使用 debugserver *:1234 -a BinaryName 附加进程出现 segmentfault 11 时,通常说明程序内部调用了ptrace 。spring
http://everettjf.com/2015/12/...segmentfault
iPhone:~ root# debugserver *:12345 -x backboard /var/mobile/Containers/Bundle/Application/A612F542-81EF-456A-A6A0-B23046EF57BA/AlipayWallet.app/AlipayWallet debugserver-@(#)PROGRAM:debugserver PROJECT:debugserver-320.2.89 for armv7. Segmentation fault: 11
iPhone:~ root# debugserver -x *:12345 /var/mobile/Containers/Bundle/Application/A612F542-81EF-456A-A6A0-B23046EF57BA/AlipayWallet.app/AlipayWallet error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '*:12345' Valid values TYPE are: auto Auto-detect the best launch method to use. posix Launch the executable using posix_spawn. fork Launch the executable using fork and exec. backboard Launch the executable through BackBoard Services.
总共有四种类型api
debugserver -x backboard *:1234 /var/mobile/......
把这个backboard改为posix试试
iPhone:~ root# debugserver -x posix *:12345 /var/mobile/Containers/Bundle/Application/A612F542-81EF-456A-A6A0-B23046EF57BA/AlipayWallet.app/AlipayWallet debugserver-@(#)PROGRAM:debugserver PROJECT:debugserver-320.2.89 for armv7. Listening to port 12345 for a connection from *...
(lldb) process connect connect://127.0.0.1:12345 (lldb) error: Process 1657 is currently being debugged, kill the process before connecting. Process 1657 stopped * thread #1, stop reason = signal SIGSTOP frame #0: 0x1fe9b000 dyld`_dyld_start dyld`_dyld_start: -> 0x1fe9b000 <+0>: mov r8, sp 0x1fe9b004 <+4>: sub sp, sp, #16 0x1fe9b008 <+8>: bic sp, sp, #7 0x1fe9b00c <+12>: ldr r3, [pc, #0x70] ; <+132> Target 0: (dyld) stopped.
(lldb) b ptrace Breakpoint 1: no locations (pending). WARNING: Unable to resolve breakpoint to any actual locations.
(lldb) c Process 1657 resuming
关闭Target,从新启动Target
1 location added to breakpoint 1 Process 1657 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x37a13e64 libsystem_kernel.dylib`__ptrace libsystem_kernel.dylib`__ptrace: -> 0x37a13e64 <+0>: ldr r12, [pc, #0x4] ; <+12> 0x37a13e68 <+4>: ldr r12, [pc, r12] 0x37a13e6c <+8>: b 0x37a13e74 ; <+16> 0x37a13e70 <+12>: rsbeq r9, r11, #192, #2 Target 0: (AlipayWallet) stopped. (lldb) p/x $lr (unsigned int) $0 = 0x0000bfbb
因而可知ptrace函数在libsystem_kernel.dylib这个动态库中,使用时才进行加载,不是静态放在本地的,因此咱们不能简单地去tweak ptrace函数。
(lldb) image list -o -f |grep AlipayWallet [ 0] 0x00000000 /private/var/mobile/Containers/Bundle/Application/A612F542-81EF-456A-A6A0-B23046EF57BA/AlipayWallet.app/AlipayWallet(0x0000000000004000)
因此ptrace的调用者位于0x0000bfbb - 0x00000000 = 0x0000bfbb处,如图所示:
在hopper使用go to add ,快捷键G
0x0000bfba
这段代码的含义很明显了,动态调用ptrace,来达到反动态调试的目的。这段代码位于 sub_bf92:内部,咱们来看看 sub_bf92:的显式调用者:
只有一个EnteryPoint+212,看看内部实现
高德地图经过在main函数中动态调用ptrace函数来达到反动态调试目的,能够参考学习。
支付宝如今作到的是经过inline函数调用ptrace
其中MSHookMessageEx负责用来hook Objective-C函数,
MSHookFunction负责用来hook C/C++函数。
简单说来就是首先修改要Hook函数的前N个字节的内存,使其跳转到替换后的函数头,这样就能执行本身的代码;同时会保存原函数的前N个字节的内容以便执行完本身的逻辑后能正确执行原函数的逻辑。具体的汇编实现能够参考这篇分析文章。
void MSHookFunction(void *symbol, void *hook, void **old);
void *(*oldConnect)(int, const sockaddr *, socklen_t); void *newConnect( int socket, const sockaddr *address, socklen_t length ) { if (address->sa_family == AF_INET) { sockaddr_in *address_in = address; if (address_in->sin_port == htons(6667)) { sockaddr_in copy = *address_in; address_in->sin_port = htons(7001); return oldConnect(socket, ©, length); } } return oldConnect(socket, address, length); } MSHookFunction(&connect, &newConnect, &oldConnect);
首先定义了一个名为oldConnect的指针用于保存要Hook函数被替换的指令;
而后实现了新的newConnect方法,即Hook后实际想要执行的代码逻辑;
最后使用MSHookFunction来对目标函数进行Hook。
第一个参数为原方法connect的地址,第二个参数为实现的新方法地址,第三个参数为用于保存connect被替换的汇编指令的地址。
其中“&connect”是MSHookFunction内部调用了CydiaSubstrate的另外一个MSFindSymbol函数来实现根据函数名查找其函数地址,更多的MSHookFunction实现原理
// See http://iphonedevwiki.net/index.php/Logos //http://everettjf.com/2015/12/20/amap-ios-client-kill-anti-debugging-protect/ //https://segmentfault.com/a/1190000006104602 //http://dev.qq.com/topic/5791da152168f2690e72daa4 //https://bbs.pediy.com/thread-185014.htm //http://www.rainyx.com/archives/category/ios/reverse #import <substrate.h> #import <mach-o/dyld.h> #import <dlfcn.h> void (*old_sub_bf92)(void); void new_sub_bf92(void) { // old_sub_bf92(); NSLog(@"KNiOSRE: anti-anti-debugging"); } //sub_bf92 %ctor { @autoreleasepool { unsigned long _sub_bf92 = (_dyld_get_image_vmaddr_slide(0) + 0xbf92) | 0x1; if (_sub_bf92) NSLog(@"KNiOSRE: Found sub_bf92!"); MSHookFunction((void *)_sub_bf92, (void *)&new_sub_bf92, (void **)&old_sub_bf92); } }
编译打包安装,咱们看看有了这个tweak的加持,动态调试的效果:
iPhone:~ root# debugserver *:12345 -a AlipayWallet debugserver-@(#)PROGRAM:debugserver PROJECT:debugserver-320.2.89 for armv7. Attaching to process AlipayWallet... Listening to port 12345 for a connection from *...
成功
(lldb) process connect connect://127.0.0.1:12345 Process 1721 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP frame #0: 0x37a004f0 libsystem_kernel.dylib`mach_msg_trap + 20 libsystem_kernel.dylib`mach_msg_trap: -> 0x37a004f0 <+20>: pop {r4, r5, r6, r8} 0x37a004f4 <+24>: bx lr libsystem_kernel.dylib`mach_msg_overwrite_trap: 0x37a004f8 <+0>: mov r12, sp 0x37a004fc <+4>: push {r4, r5, r6, r8} Target 0: (AlipayWallet) stopped.
Nov 28 21:53:46 iPhone kernel[0] <Notice>: xpcproxy[1815] Container: /private/var/mobile/Containers/Data/Application/89313E1C-76C2-41E3-8ECD-F4BDC1A78524 (sandbox) Nov 28 21:53:46 iPhone AlipayWallet[1815] <Notice>: MS:Notice: Injecting: com.alipay.iphoneclient [AlipayWallet] (1141.14) Nov 28 21:53:46 iPhone AlipayWallet[1815] <Notice>: MS:Notice: Loading: /Library/MobileSubstrate/DynamicLibraries/AFlexLoader.dylib Nov 28 21:53:46 iPhone AlipayWallet[1815] <Warning>: AFlexLoader: injected successfully Nov 28 21:53:46 iPhone AlipayWallet[1815] <Notice>: MS:Notice: Loading: /Library/MobileSubstrate/DynamicLibraries/AlipayWalletTweakF.dylib Nov 28 21:53:46 iPhone AlipayWallet[1815] <Warning>: KNiOSRE: Found sub_bf92! Nov 28 21:53:46 iPhone locationd[103] <Notice>: Gesture EnabledForTopCLient: 0, EnabledInDaemonSettings: 0 Nov 28 21:53:46 iPhone AlipayWallet[1815] <Notice>: MS:Notice: Loading: /Library/MobileSubstrate/DynamicLibraries/TSTweakEx.dylib Nov 28 21:53:46 iPhone AlipayWallet[1815] <Warning>: MS:Warning: nil class argument for selector applicationDidFinishLaunching: Nov 28 21:53:46 iPhone AlipayWallet[1815] <Warning>: KNiOSRE: anti-anti-debugging
cy# [#0xfc4e730 nextResponder] #"<H5WebViewController: 0x537e600>"
cy# [#0x537e600 h5WebView] #"<H5WebView: 0xfc4e240; baseClass = UIWebView; frame = (0 64; 320 504); autoresize = H; layer = <CALayer: 0xd4a8e70>>" cy# [#0xfc4e240 delegate] #"<PSDJsBridge: 0x13019ea0>" cy# [#0x13019ea0 ] [#"<PSDJsBridge: 0x13019ea0>"]
@property(retain, nonatomic) NSMutableDictionary *responseCallbacks; // @synthesize responseCallbacks=_responseCallbacks;
cy# [#0x13019ea0 webViewDelegate] #"<PSDView: 0xfc4ed90>"
ptrace函数在libsystem_kernel.dylib这个动态库中,使用时才进行加载,不是静态放在本地的,因此咱们不能简单地去tweak ptrace函数。因此咱们分析一下其代码逻辑,通常这种反调试,代码是这么写的 :
void disable_gdb() { void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW); ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace"); ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0); dlclose(handle); }
能够经过hook dlsym,当其调用时,若是是获取ptrace函数,则咱们返回一个假的ptrace函数回去 , tweak如此编写 :
#import <substrate.h> #import <mach-o/dyld.h> #import <dlfcn.h> int fake_ptrace(int request, pid_t pid, caddr_t addr, int data){ return 0; } void *(*old_dlsym)(void *handle, const char *symbol); void *my_dlsym(void *handle, const char *symbol){ if(strcmp(symbol,"ptrace") == 0){ return (void*)fake_ptrace; } return old_dlsym(handle,symbol); } %ctor{ MSHookFunction((void*)dlsym,(void*)my_dlsym,(void**)&old_dlsym); }
操做系统提供了一种标准的服务来让程序员实现对底层硬件和服务的控制(好比文件系统),叫作系统调用(system calls)。当一个程序须要做系统调用的时候,它将相关参数放进系统调用相关的寄存器,而后调用软中断0x80,这个中断就像一个让程序得以接触到内核模式的窗口,程序将参数和系统调用号交给内核,内核来完成系统调用的执行。