using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.IO; namespace sharprd { class RDPFileFormat { static byte[] ToByteArray(String HexString) { try { int NumberChars = HexString.Length; byte[] bytes = new byte[NumberChars / 2]; for (int i = 0; i < NumberChars; i += 2) { bytes[i / 2] = Convert.ToByte(HexString.Substring(i, 2), 16); } return bytes; } catch (Exception ex) { throw new Exception("Problem converting Hex to Bytes", ex); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct DATA_BLOB { public int cbData; public IntPtr pbData; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct CRYPTPROTECT_PROMPTSTRUCT { public int cbSize; public CryptProtectPromptFlags dwPromptFlags; public IntPtr hwndApp; public String szPrompt; } [Flags] private enum CryptProtectPromptFlags { // prompt on unprotect CRYPTPROTECT_PROMPT_ON_UNPROTECT = 0x1, // prompt on protect CRYPTPROTECT_PROMPT_ON_PROTECT = 0x2 } [Flags] private enum CryptProtectFlags { // for remote-access situations where ui is not an option // if UI was specified on protect or unprotect operation, the call // will fail and GetLastError() will indicate ERROR_PASSWORD_RESTRICTION CRYPTPROTECT_UI_FORBIDDEN = 0x1, // per machine protected data -- any user on machine where CryptProtectData // took place may CryptUnprotectData CRYPTPROTECT_LOCAL_MACHINE = 0x4, // force credential synchronize during CryptProtectData() // Synchronize is only operation that occurs during this operation CRYPTPROTECT_CRED_SYNC = 0x8, // Generate an Audit on protect and unprotect operations CRYPTPROTECT_AUDIT = 0x10, // Protect data with a non-recoverable key CRYPTPROTECT_NO_RECOVERY = 0x20, // Verify the protection of a protected blob CRYPTPROTECT_VERIFY_PROTECTION = 0x40 } [DllImport("Crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CryptProtectData( ref DATA_BLOB pDataIn, String szDataDescr, ref DATA_BLOB pOptionalEntropy, IntPtr pvReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct, CryptProtectFlags dwFlags, ref DATA_BLOB pDataOut ); [DllImport("Crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CryptUnprotectData( ref DATA_BLOB pDataIn, String szDataDescr, ref DATA_BLOB pOptionalEntropy, IntPtr pvReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct, CryptProtectFlags dwFlags, ref DATA_BLOB pDataOut ); public static RDConnection Load(string path) { TextReader reader = File.OpenText(path); string line = string.Empty; RDConnection connection = new RDConnection(); connection.Name = Path.GetFileNameWithoutExtension(path); while ((line = reader.ReadLine()) != null) { string[] tokens = line.Split(new char[] { ':' }); switch (tokens[0]) { // 1 - WIDTHxHEIGHT // 2 - Fullscreen case "screen mode id": connection.DisplayMode = (RDConnection.DisplayModes)(2 - int.Parse(tokens[2])); break; case "desktopwidth": case "desktopheight": case "winposstr": case "compression": case "keyboardhook": case "redirectcomports": case "redirectsmartcards": case "autoreconnection enabled": case "disable cursor setting": case "redirectposdevices": case "drivestoredirect": case "authentication level": case "prompt for credentials": case "negotiate security layer": case "remoteapplicationmode": case "gatewayhostname": case "gatewayusagemethod": case "gatewaycredentialssource": case "gatewayprofileusagemethod": case "promptcredentialonce": // TODO break; case "session bpp": connection.ColorDepth = (RDConnection.ColorDepths)int.Parse(tokens[2]); break; case "full address": connection.Computer = tokens[2]; break; case "audiomode": switch (tokens[2]) { case "0": connection.RemoteAudio = RDConnection.RemoteAudioConfiguration.PlayOnThisComputer; break; case "1": connection.RemoteAudio = RDConnection.RemoteAudioConfiguration.PlayOnRemoteComputer; break; case "2": connection.RemoteAudio = RDConnection.RemoteAudioConfiguration.DoNotPlay; break; } break; case "redirectdrives": connection.Drives = tokens[2] == "1"; break; case "redirectprinters": connection.Printers = tokens[2] == "1"; break; case "displayconnectionbar": connection.DisplayConnectionBar = tokens[2] == "1"; break; case "username": connection.Username = tokens[2]; break; case "domain": connection.Domain = tokens[2]; break; case "disable wallpaper": connection.DesktopBackground = tokens[2] != "1"; break; case "disable full window drag": connection.WindowContents = tokens[2] != "1"; break; case "disable menu anims": connection.MenuAnimation = tokens[2] != "1"; break; case "disable themes": connection.VisualStyles = tokens[2] != "1"; break; case "bitmapcachepersistenable": connection.PersistentBitmapCaching = tokens[2] == "1"; break; case "allow desktop composition": connection.DesktopComposition = tokens[2] == "1"; break; case "allow font smoothing": connection.FontSmoothing = tokens[2] == "1"; break; case "redirectclipboard": connection.Clipboard = tokens[2] == "1"; break; case "password 51": //Error("Password decryption not supported. Password will be ignored"); //DATA_BLOB pDataIn; ////pDataIn.pbData = Marshal.StringToCoTaskMemAuto(tokens[2]); ////pDataIn.cbData = tokens[2].Length * sizeof(char); //pDataIn.pbData = Marshal.AllocHGlobal(tokens[2].Length); //pDataIn.cbData = tokens[2].Length; //Marshal.Copy(ToByteArray(tokens[2]), 0, pDataIn.pbData, pDataIn.cbData); //CRYPTPROTECT_PROMPTSTRUCT pPromptStruct; //pPromptStruct.cbSize = Marshal.SizeOf(typeof(CRYPTPROTECT_PROMPTSTRUCT)); //pPromptStruct.dwPromptFlags = 0; //pPromptStruct.hwndApp = IntPtr.Zero; //pPromptStruct.szPrompt = null; //DATA_BLOB pDataOut = new DATA_BLOB(), pOptionalEntropy = new DATA_BLOB(); //bool result = CryptUnprotectData(ref pDataIn, "psw", ref pOptionalEntropy, IntPtr.Zero, ref pPromptStruct, CryptProtectFlags.CRYPTPROTECT_UI_FORBIDDEN, ref pDataOut); //if (!result) //{ // string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message; // Error("Unable to decrypt: " + errorMessage); //} //connection.Password = tokens[2]; break; case "alternate shell": connection.AlternateShell = tokens[2]; break; case "shell working directory": connection.ShellWorkingDirectory = tokens[2]; break; default: //Error("Unmanaged tag: " + tokens[0]); break; } } reader.Close(); return connection; } } }