Search code examples
c#xmlencryptionwifiwlanapi

Getting Wi-Fi profile information


I'm using Windows 8.1 which doesn't have a tool (with a GUI) to manage wifi network profiles. So I'm writing one which will help me. I did some googling and found Managed Wifi API, and with the help of a tutorial I managed to put this code together:

foreach (WlanClient.WlanInterface wlanIface in client.Interfaces)
{
    foreach (Wlan.WlanProfileInfo profileInfo in wlanIface.GetProfiles())
    {
        string profileName = profileInfo.profileName;
        ListViewItem item = new ListViewItem(profileName);

        string profileXML = wlanIface.GetProfileXml(profileInfo.profileName);
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(profileXML);
        var NSManager = new XmlNamespaceManager(doc.NameTable);
        NSManager.AddNamespace("d", "http://www.microsoft.com/networking/WLAN/profile/v1");
        XmlNode node = doc.DocumentElement.SelectSingleNode("//d:WLANProfile/d:MSM/d:security/d:authEncryption/d:authentication", NSManager);

        item.SubItems.Add(node.InnerText);
        Profiles.Items.Add(item);
    }
}

Getting the list of saved network profiles and printing them on a ListView. I have two problems. One is how to get the full profile information using Managed Wifi API? Because the only thing I can get is the profile name. There is no documentation in the site.

The second problem is, since I can't get the full network information using the API, I used the API to print the profile info in XML format and then parse the XML and read it. An example XML:

<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
    <name>MEDO PUB</name>
    <SSIDConfig>
        <SSID>
            <hex>4D45444F20505542</hex>
            <name>MEDO PUB</name>
        </SSID>
    </SSIDConfig>
    <connectionType>ESS</connectionType>
    <connectionMode>manual</connectionMode>
    <MSM>
        <security>
            <authEncryption>
                <authentication>WPA2PSK</authentication>
                <encryption>AES</encryption>
                <useOneX>false</useOneX>
            </authEncryption>
            <sharedKey>
                <keyType>passPhrase</keyType>
                <protected>true</protected>
                <keyMaterial>someReallyLongStringLike500+chars</keyMaterial>
            </sharedKey>
        </security>
    </MSM>
</WLANProfile>

I need to get the wifi password but I think it is encrypted. How can I get the actual password or decode the encrypted password?


Update: I found two links: Exposing the WiFi Password Secrets and [C++] Dump wireless passwords but I'm not sure if they work, or rather how to implement them in C#.


Solution

  • As I mentioned in a comment, you can do this with

    netsh wlan show profiles
    

    then

    netsh wlan show profile "<a profile from the last step>" key=clear
    

    If you still want to do this in code, read on:

    The managed WiFi API you are using doesn't have this function, but you can add it easily.

    Modify the WlanProfileFlags enum in Interop.cs to this:

    [Flags]
    public enum WlanProfileFlags
    {
        /// <remarks>
        /// The only option available on Windows XP SP2.
        /// </remarks>
        AllUser = 0,
        GroupPolicy = 1,
        User = 2,
        GetPlaintextKey = 4
    }
    

    Add this function to the WlanApi.cs file, probably near the GetProfileXml function (for organization's sake).

    /// <summary>
    /// Gets the profile's XML specification. Key is unencrypted.
    /// </summary>
    /// <param name="profileName">The name of the profile.</param>
    /// <returns>The XML document.</returns>
    public string GetProfileXmlUnencrypted(string profileName)
    {
        IntPtr profileXmlPtr;
        Wlan.WlanProfileFlags flags = Wlan.WlanProfileFlags.GetPlaintextKey;
        Wlan.WlanAccess access;
        Wlan.ThrowIfError(
            Wlan.WlanGetProfile(client.clientHandle, info.interfaceGuid, profileName, IntPtr.Zero, out profileXmlPtr, out flags, out access));
        try
        {
            return Marshal.PtrToStringUni(profileXmlPtr);
        }
        finally
        {
            Wlan.WlanFreeMemory(profileXmlPtr);
        }
    }
    

    You can call this function to get the unencrypted key.

    I haven't tested this but it should work. Let me know if you have any questions.