破解Mac版WiFi万能钥匙密码
春节回家,家里没有网络,手机流量又不够用,所以只能去蹭邻居的网。
我的电脑里以前装过WiFi万能钥匙,打开一看,发现有可以连接的热点:
先用手机开启一个热点给电脑使用,再打开Charles 拦截电脑数据包。 在WiFi列表里选中TP-LINK_FB2BBE
这一列,然后点击 自动连接 按钮,可以截取到以下数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 { "qryapwd" : { "retCd" : "0" , "psws" : { "f8:d1:11:fb:2b:be" : { "bssid" : "f8:d1:11:fb:2b:be" , "pwd" : "EDFE4543092F6A8BAD1900F2ACD40233E723205FDE9211C4B5D1D54900F9C9BC" , "hid" : "1AD1DB9E0F7EBBA9B0FB6E8C567CE3A8" , "xJs" : "" , "ssid" : "TP-LINK_FB2BBE" , "xUser" : "" , "type" : "internet" , "xPwd" : "" , "securityLevel" : "2" } } }, "retCd" : "0" }
由结果可以看出,pwd
字段很有可能就是加密后的密码。如果能破解出原始密码的话,那么手机就可以直接连接WiFi了。
以下就是破解密码的过程:
一、获取选中的CellView 先按照《使用EasySIMBL为Mac应用加载插件》 教程里的方法安装EasySIMBL模板,然后用Xcode新建一个EasySIMBL插件工程,工程名为WifiMasterKeyPlugin
,再将初始化代码改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + (instancetype )sharedInstance { static WifiMasterKeyPlugin *plugin = nil ; @synchronized (self ) { if (!plugin) { plugin = [[self alloc] init]; [[NSNotificationCenter defaultCenter] addObserver:plugin selector:@selector (notificationListener:) name:NSViewDidUpdateTrackingAreasNotification object:nil ]; } } return plugin; } - (void )notificationListener:(NSNotification *)notification { NSView *view = notification.object; if ([view respondsToSelector:@selector (frame)]) { NSLog (@"view : %@, frame : %@" , view, [NSValue valueWithRect:view.frame]); } }
上面的代码能够获取到创建视图的通知,根据通知可以打印出视图的类名。 编译工程后,打开控制台应用,重新运行WiFi万能钥匙,然后点击TP-LINK_FB2BBE
这一列,在控制台里可以看到输出的log:
1 2 3 WiFiMasterKey[30976]: view : <NSTableView: 0x7f8fa3dc3810>, frame : NSRect: {{0, 0}, {537, 862}} WiFiMasterKey[30976]: view : <NSTableRowView: 0x7f8fa60a8620> - row: 1, frame : NSRect: {{0, 52}, {537, 82}} WiFiMasterKey[30976]: view : <WiFiTableSelectedCellView: 0x7f8fa6134df0>, frame : NSRect: {{1, 1}, {534, 80}}
可以看到创建了一个<WiFiTableSelectedCellView: 0x7f8fa6134df0>
,看类名应该是当前选中的CellView,CellView对象的内存地址为0x7f8fa6134df0
。
二、用Xcode动态调试应用 接下来用Xcode来动态调试WiFi万能钥匙,点击Xcode的菜单 Debug –> Attach to Process ,选择WiFiMasterKey
进程。
等待进程附加完毕,点击下面的按钮暂停应用:
然后在调试框里输入以下命令打印出CellView的子视图: (注意:pviews
命令需要先安装chisel 才能使用。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 (lldb) po 0x7f8fa6134df0 <WiFiTableSelectedCellView: 0x7f8fa6134df0> (lldb) pviews 0x7f8fa6134df0 [ A P ] h=--- v=-&- WiFiTableSelectedCellView 0x7f8fa6134df0 f=(1,1,534,80) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms [ A ] h=--& v=&-- NSImageView 0x7f8fa6159a80 "<NSImage 0x7f8fa3d302c0 Name=icon_lock_signal_big_3 Size={45, 37} Reps=( "NSBitmapImageRep 0x7f8fa615f6d0 Size={45, 37} ColorSpace=iMac colorspace BPS=8 BPP=32 Pixels=45x37 Alpha=YES Planar=NO Format=2 CurrentBacking=<CGImageRef: 0x7f8fa615f850> CGImageSource=0x7f8fa62424f0" )> " f=(5,22,44,37) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms [ AF ] h=--& v=&-- NSButton 0x7f8fa61353d0 "输入密码" f=(433,6,85,25) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms [ AF ] h=--& v=&-- NSTextField 0x7f8fa3d1a810 f=(415,47,99,20) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms [ A ] h=--& v=&-- NSImageView 0x7f8fa3d149e0 "<NSImage 0x7f8fa607c030 Name=icon_key Size={10, 18} Reps=( "NSBitmapImageRep 0x7f8fa3d1a4f0 Size={10, 18} ColorSpace=sRGB IEC61966-2.1 colorspace BPS=8 BPP=32 Pixels=10x18 Alpha=YES Planar=NO Format=2 CurrentBacking=<CGImageRef: 0x7f8fa615ae10> CGImageSource=0x7f8fa3de4270" )> " f=(495,40,23,34) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms [ AF ] h=-&- v=&-- NSTextField 0x7f8fa61977e0 "TP-LINK_FB2BBE" f=(60,30,184,21) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms [ AF ] h=--& v=&-- NSButton 0x7f8fa3daf760 "自动连接" f=(237,6,85,25) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms [ AF ] h=--& v=&-- NSButton 0x7f8fa6184d80 "分享热点" f=(336,6,85,25) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms A=autoresizesSubviews, C=canDrawConcurrently, D=needsDisplay, F=flipped, G=gstate, H=hidden (h=by ancestor), L=needsLayout (l=child needsLayout), U=needsUpdateConstraints (u=child needsUpdateConstraints), O=opaque, P=preservesContentDuringLiveResize, S=scaled/rotated, W=wantsLayer (w=ancestor wantsLayer), V=needsVibrancy (v=allowsVibrancy), #=has surface
由结果可知, 自动连接 按钮对象的内存地址是0x7f8fa3daf760
,用以下命令可以得到点击按钮时调用的方法名:
1 2 3 4 5 6 7 8 (lldb) po [0x7f8fa3daf760 target] <WiFiTableSelectedCellView: 0x7f8fa6134df0> (lldb) po [0x7f8fa3daf760 action] 0x0000000101d2c889 (lldb) po NSStringFromSelector(0x0000000101d2c889) autoConnectButtonAction:
也就是说,点击按钮时会调用[WiFiTableSelectedCellView autoConnectButtonAction:]
方法。
三、用Hopper静态分析应用 接下来用动态调试来分析比较麻烦,可以采用静态分析的方法。 将WiFi万能钥匙的可执行文件拖到Hopper Disassembler 里进行分析,等待分析完毕后搜索WiFiTableSelectedCellView autoConnectButtonAction:
方法,再按 alt + enter 组合键查看反汇编伪代码,可得到以下结果:
1 2 3 4 5 6 7 8 9 10 void -[WiFiTableSelectedCellView autoConnectButtonAction:](void * self , void * _cmd, void * arg2) { rsi = @selector (queryWiFiMasterKey); [var_90 queryWiFiMasterKey]; }
查看queryWiFiMasterKey
方法的伪代码:
1 2 3 4 5 6 7 8 9 10 11 void -[WiFiTableSelectedCellView queryWiFiMasterKey](void * self , void * _cmd) {loc_10004c361: rsi = @selector (queryWiFiMasterKeyFromServer); goto loc_10004c385; }
再查看queryWiFiMasterKeyFromServer
方法的伪代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void -[WiFiTableSelectedCellView queryWiFiMasterKeyFromServer](void * self , void * _cmd) { rdx = self ->_wifi; r12 = *objc_msgSend; r14 = [[NSArray arrayWithObject:rdx] retain ]; r13 = [[WiFiMasterKeyService shareInstance] retain ]; var_50 = *_NSConcreteStackBlock; var_48 = 0xc2000000 ; var_44 = 0x0 ; var_40 = ___57-[WiFiTableSelectedCellView queryWiFiMasterKeyFromServer]_block_invoke; var_38 = ___block_descriptor_tmp219; var_30 = [self retain ]; [r13 queryMasterKey:r14 tag:0x0 userInfo:0x0 scanWiFiType:0x1 success:var_50 failure:void ^(void * _block, struct AFHTTPRequestOperation * arg1, struct NSError * arg2) { rax = [MLHudAlert alertWithType:0x2 message:cfstring__g_RhV___c1Y___0]; return ; }]; rbx = *objc_release; [var_30 release]; [r13 release]; rax = [r14 release]; return ; }
也就是说,点击 自动连接 按钮,会调用[WiFiMasterKeyService queryMasterKey:tag:userInfo:scanWiFiType:success:failure:]
方法向服务器查询加密后的密码,数据请求成功的回调方法是[WiFiTableSelectedCellView queryWiFiMasterKeyFromServer]_block_invoke
,这个block的伪代码是:
1 2 3 4 5 void ___57-[WiFiTableSelectedCellView queryWiFiMasterKeyFromServer]_block_invoke(int arg0) { rdi = *(arg0 + 0x20 ); rax = [rdi parserScanWiFiResult:rdx]; return ; }
最后通过[WiFiTableSelectedCellView parserScanWiFiResult:]
方法来解析返回的数据,所以解密WiFi密码的代码很有可能就在这个方法里。
由一开始可知,加密后的密码字段名是pwd
,因此在parserScanWiFiResult:
方法的伪代码里可以很快发现以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void -[WiFiTableSelectedCellView parserScanWiFiResult:](void * self , void * _cmd, void * arg2) { rbx = [[rdi objectForKey:@"pwd" ] retain ]; r13 = *objc_msgSend; r15 = [[WiFiKeyAESUtilties ShareKeyAES128Decry:rbx] retain ]; r12 = *objc_release; [rbx release]; [var_38 connectNetworkWithPassword:r15]; }
原来是通过[WiFiKeyAESUtilties ShareKeyAES128Decry:]
方法解密出密码。
四、编写插件 因此我们可以通过hook这个方法,把解密后的密码用弹出框显示出来,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @implementation NSObject (WiFiKeyAESUtiltiesHook )+ (void )hook_WiFiKeyAESUtilties { [self jr_swizzleClassMethod:@selector (ShareKeyAES128Decry:) withClassMethod:@selector (hook_ShareKeyAES128Decry:) error:nil ]; } + (id )hook_ShareKeyAES128Decry:(id )arg1 { NSString *shareKey = [self hook_ShareKeyAES128Decry:arg1]; shareKey = [shareKey stringByRemovingPercentEncoding]; NSAlert *alert = [[NSAlert alloc] init]; alert.alertStyle = NSInformationalAlertStyle ; alert.messageText = @"密码:" ; alert.informativeText = shareKey; [alert runModal]; return shareKey; } @end
具体工程代码可以在WifiMasterKeyPlugin 下载。
编译工程后,重新运行WiFi万能钥匙,点击 自动连接 按钮,可以看到弹出一个提示框: