在本文中,将探讨一个使用WPF和Visual Studio 2019开发的WiFi密码恢复与管理应用程序。这个应用程序采用了MVVM架构,使用了Caliburn.Micro和Autofac进行依赖注入。该应用程序的主要目的是管理WiFi配置文件,从WiFi配置文件中恢复密码,并匹配不同的密码以便连接到自己的安全WiFi(如果想要将新设备连接到WiFi但不记得自己的WiFi密码,并希望进行有根据的猜测)。WiFi配置文件管理功能允许查看和管理Windows 10 PC上的所有WiFi配置文件,例如删除配置文件,这在连接到不同WiFi网络后,WiFi配置文件列表可能会增加,有时可能希望删除不必要的WiFi配置文件。WiFi密码恢复和管理应用程序旨在恢复自己的WiFi密码,并不打算用于破解任何人的WiFi。暴力破解安全WiFi网络的方法与此应用程序使用的方法完全不同,具体可以在这里阅读。这个应用程序的最新代码可以在GitHub仓库中找到,ClickOnce部署可以在这里启动。
WiFi密码恢复和管理工具使用ManagedNativeWifi库从Windows 10 PC中检索WiFi配置文件及其对应的密码。此外,该库还用于操作PC上存在的WiFi配置文件,例如增加或减少它们的优先级。对于WiFi连接功能,应用程序使用simplewifi库的代码生成WiFi连接配置文件。应用程序用户可以通过三种不同的方式提供潜在的密码:手动通过在主视图中右键单击网络行,使用字典和正则表达式。应用程序的一些屏幕截图如下所示。可以点击图片放大查看。
主用户界面由四个控件组成,排列在一个DockPanel中:
以下是主用户界面(ShellView.xaml)的代码片段:
<Window x:Class="EasyPasswordRecoveryWiFi.Views.ShellView">
<DockPanel>
<ContentControl DockPanel.Dock="Bottom" cal:View.Model="{Binding StatusBarBottom}">
</ContentControl>
<ContentControl DockPanel.Dock="Top" cal:View.Model="{Binding HeaderMenu}">
</ContentControl>
<ContentControl DockPanel.Dock="Left" cal:View.Model="{Binding LeftMenu}">
</ContentControl>
<ContentControl x:Name="ActiveItem">
</ContentControl>
</DockPanel>
</Window>
如上所述,状态栏控件位于主用户界面的底部,当没有消息且应用程序不忙碌时,状态栏控件使用数据触发器隐藏。状态栏通过从不同视图模型发送消息来更新,使用Caliburn.Micro事件聚合器。对于那些不熟悉的人,事件聚合器是一个服务,它提供了从一个实体到另一个实体以松散方式发布对象的能力,具体可以在这里阅读。
为了减少应用程序的依赖,使用了Autofac进行依赖注入。使用依赖注入的一个主要优点是它通过允许注入IWiFiService接口的模拟实现到MainController中,从而提高了应用程序的可测试性。在应用程序启动期间,可以轻松地在模拟和实际实现的IWiFiService接口之间切换,如下所示:
#if MOCK_DATA
builder.RegisterType<MockWiFiAdapter>().As<IWiFiService>();
#else
builder.RegisterType<NativeWiFiAdapter>().As<IWiFiService>();
#endif
//
Constructor Dependency Injection
public class MainController
{
private readonly IWiFiService _wiFiService;
public MainController(IWiFiService wifiService)
{
_wiFiService = wifiService;
}
}
应用程序和ManagedNativeWifi库之间的耦合是通过适配器模式完成的。这种方法允许轻松地用其他替代品替换使用的ManagedNativeWifi库。
public class NativeWiFiAdapter : NativeWifiPlayer, IWiFiService { }
对于异步任务的处理,使用了fire and forget方法,可以在这篇文章中找到。这种方法基本上将任务包装到一个try catch块中。如果发生错误,它会将异常发送到错误处理程序,在情况下,错误处理程序会使用新的错误消息更新状态栏。当任务处于活动状态时,busy标志为true,导致主用户界面被禁用,从而禁止启动新任务。
public static class TaskUtilities
{
#pragma warning disable RECS0165 // Asynchronous methods should return a Task instead of void
public static async void FireAndForgetSafeAsync(this Task task, IErrorHandler handler = null)
#pragma warning restore RECS0165 // Asynchronous methods should return a Task instead of void
{
try
{
await task;
}
catch (Exception ex)
{
handler?.HandleError(ex);
}
}
}
如前所述,WiFi连接功能使用ProfileFactory类生成WiFi连接配置文件。ProfileFactory类包含CreateProfileXml方法,该方法可以用Accesspoint对象(包含目标WiFi网络的认证类型、加密类型和Bss类型)和密码作为输入参数调用,之后返回连接配置文件。生成的连接配置文件随后被添加到PC的连接配置文件列表中,之后尝试连接到目标WiFi网络。在调用CreateProfileXml方法之前,使用PasswordHelper类验证密码。不支持企业网络,因为它们需要额外的配置步骤,包括用户名和域,具体可以在这里阅读。
弹出窗口使用Caliburn.Micro的WindowManager类显示。Caliburn.Micro负责初始化窗口,设置其数据上下文并显示适当的视图。
bool dialogResult = _windowManager.ShowDialog(_passwordViewModel) ?? false;
if (dialogResult)
{
password = _passwordViewModel.Password;
}
应用程序的WiFi管理视图允许导入和操作Windows 10 PC上存在的所有WiFi连接配置文件。通过在配置文件行上右键单击,可以操作WiFi连接配置文件(删除、增加或减少其优先级、导出配置文件或显示其属性)。当单击属性选项时,属性窗口会弹出,显示包括用于连接到其相应WiFi网络的密码在内的配置文件属性。为了检索未加密的密码,修改了ManagedNativeWifi库的GetProfile方法。
uint flags = WLAN_PROFILE_GET_PLAINTEXT_KEY;
var result = WlanGetProfile(clientHandle, interfaceId, profileName, IntPtr.Zero, out string profileXml, ref flags, out uint grantedAccess);
可以使用命令提示符来显示WiFi配置文件的明文密码。
C:\Users>netsh wlan show profiles
C:\Users>netsh wlan show profile name="network-profile-name" key=clear
#Replace network-profile-name with your copied network name.
如文章开头所述,WiFi连接过程中使用的密码可以使用字典和正则表达式提供。有关如何使用正则表达式生成密码字符串的详细信息,可以在这篇文章中找到。最后但并非最不重要的是,使用NUnit对应用程序进行测试。为所有支持的WiFi网络生成了连接配置文件,并将其与Windows 10 PC生成的参考配置文件进行了验证。此外,还编写了测试用例来验证PasswordHelper类(该类检查字符串是否符合目标WiFi网络的密码规则)。