抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

春节回家,家里没有网络,手机流量又不够用,所以只能去蹭邻居的网。

我的电脑里以前装过WiFi万能钥匙,打开一看,发现有可以连接的热点:
This is a picture without description

先用手机开启一个热点给电脑使用,再打开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进程。
This is a picture without description

等待进程附加完毕,点击下面的按钮暂停应用:
This is a picture without description

然后在调试框里输入以下命令打印出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万能钥匙,点击 自动连接 按钮,可以看到弹出一个提示框:
This is a picture without description

评论