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,這個中斷就像一個讓程序得以接觸到內核模式的窗口,程序將參數和系統調用號交給內核,內核來完成系統調用的執行。