0xthirteen/SharpRDP

Review keycodes to support various language

upils opened this issue · 5 comments

upils commented

On a french version of Windows with keyboard in French, key sent are sent like on a QWERTY keyboard.

Can you give the source of the harcoded key values ? What I was able to find with a quick search do not match with your values (like here)

I was thinking to add another argument to specify the language of the targeted system in order to use the appropriate keymap.

I don't currently have any plans to support other languages. It would be easy to change the codes in the keycodes method for what you need. There are a handful of pages that will show the keycodes like https://www.csee.umbc.edu/portal/help/theory/ascii.txt.

Not exactly a solution, but you can query the remote machine using WMI and look for the Win32_Keyboard class.
The KeyCodes function would be then something like:

switch (keyboardLayout)
            {
                //https://github.com/apache/guacamole-server/tree/master/src/protocols/rdp/keymaps
                case "00000809": // UK layout
                    keycode["\\"] = new Code(new[] { false, true }, new[] { 0x56 });
                    break;
                default:
                    keycode["\\"] = new Code(new[] { false, true }, new[] { 0x2b });
                    break;
            }

That is just an example with the GB keyboard setting that was causing me troubles with \
But I'm just too lazy to check all the other keys.

The code I'm using to do the WMI query within SharpRDP:

if (wmi)
                    {
                        Console.WriteLine("[.] Acquiring keyboard layout..");
                        ConnectionOptions options = new ConnectionOptions();

                        options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
                        options.EnablePrivileges = true;
                        options.Authentication = AuthenticationLevel.PacketPrivacy;

                        if (!String.IsNullOrEmpty(username))
                        {
                            Console.WriteLine("[+] Using explicit credentials");
                            options.Username = username;
                            options.Password = password;


                        }


                        ManagementScope scope = new ManagementScope("\\\\" + server + "\\root\\cimv2", options);
                        scope.Connect();
                        ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Keyboard");
                        ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
                        ManagementObjectCollection q = searcher.Get();
                        
                        foreach (ManagementObject m in q)
                        {
                            layout = m["Layout"].ToString();
                            Console.WriteLine("[+] Acquired remote keyboard layout via WMI: " + layout);
                        }
                    }
                    else
                    {
                        layout = "0000";
                    }

EDIT: Clearly, this adds the requirement to communicate using something that is not just RDP. This might not be ok for every situation.

Hi, here are the keycodes of the qwerty keyboard in Spanish, in case anyone was looking for it. Some keys I haven't been able to make work, in case I get them I'll put them here. I hope they solve the problem soon.

            keycode["Esc"] = new Code(new[] { false, true }, new[] { 0x01 });
            keycode["Enter+down"] = new Code(new[] { false }, new[] { 0x1c });
            keycode["Enter+up"] = new Code(new[] { true }, new[] { 0x1c });
            keycode["Win"] = new Code(new[] { false, true }, new[] { 0x15b });
            keycode["Down"] = new Code(new[] { false, true }, new[] { 0x150 });
            keycode["Right"] = new Code(new[] { false, true }, new[] { 0x14d });
            keycode["Left"] = new Code(new[] { false, true }, new[] { 0x14b });
            keycode["Alt"] = new Code(new[] { false, true }, new[] { 0x38 });
            keycode["Shift"] = new Code(new[] { false, true }, new[] { 0x2a });
            keycode["Space"] = new Code(new[] { false, true }, new[] { 0x39 });
            keycode["Tab"] = new Code(new[] { false, true }, new[] { 0x0f });

            keycode["Calc"] = new Code(new[] { false, true }, new[] { 0x121, 0x121 });
            keycode["Paste"] = new Code(new[] { false, true }, new[] { 0x10a, 0x10a });

            keycode["1"] = new Code(new[] { false, true }, new[] { 0x02 });
            keycode["2"] = new Code(new[] { false, true }, new[] { 0x03 });
            keycode["3"] = new Code(new[] { false, true }, new[] { 0x04 });
            keycode["4"] = new Code(new[] { false, true }, new[] { 0x05 });
            keycode["5"] = new Code(new[] { false, true }, new[] { 0x06 });
            keycode["6"] = new Code(new[] { false, true }, new[] { 0x07 });
            keycode["7"] = new Code(new[] { false, true }, new[] { 0x08 });
            keycode["8"] = new Code(new[] { false, true }, new[] { 0x09 });
            keycode["9"] = new Code(new[] { false, true }, new[] { 0x0a });
            keycode["0"] = new Code(new[] { false, true }, new[] { 0x0b });

            keycode["A"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x1e });
            keycode["B"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x30 });
            keycode["C"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x2e });
            keycode["D"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x20 });
            keycode["E"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x12 });
            keycode["F"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x21 });
            keycode["G"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x22 });
            keycode["H"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x23 });
            keycode["I"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x17 });
            keycode["J"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x24 });
            keycode["K"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x25 });
            keycode["L"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x26 });
            keycode["M"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x32 });
            keycode["N"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x31 });
            keycode["O"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x18 });
            keycode["P"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x19 });
            keycode["Q"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x10 });
            keycode["R"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x13 });
            keycode["S"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x1f });
            keycode["T"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x14 });
            keycode["U"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x16 });
            keycode["V"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x2f });
            keycode["W"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x11 });
            keycode["X"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x2d });
            keycode["Y"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x15 });
            keycode["Z"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x2c });

            keycode["a"] = new Code(new[] { false, true }, new[] { 0x1e });
            keycode["b"] = new Code(new[] { false, true }, new[] { 0x30 });
            keycode["c"] = new Code(new[] { false, true }, new[] { 0x2e });
            keycode["d"] = new Code(new[] { false, true }, new[] { 0x20 });
            keycode["e"] = new Code(new[] { false, true }, new[] { 0x12 });
            keycode["f"] = new Code(new[] { false, true }, new[] { 0x21 });
            keycode["g"] = new Code(new[] { false, true }, new[] { 0x22 });
            keycode["h"] = new Code(new[] { false, true }, new[] { 0x23 });
            keycode["i"] = new Code(new[] { false, true }, new[] { 0x17 });
            keycode["j"] = new Code(new[] { false, true }, new[] { 0x24 });
            keycode["k"] = new Code(new[] { false, true }, new[] { 0x25 });
            keycode["l"] = new Code(new[] { false, true }, new[] { 0x26 });
            keycode["m"] = new Code(new[] { false, true }, new[] { 0x32 });
            keycode["n"] = new Code(new[] { false, true }, new[] { 0x31 });
            keycode["o"] = new Code(new[] { false, true }, new[] { 0x18 });
            keycode["p"] = new Code(new[] { false, true }, new[] { 0x19 });
            keycode["q"] = new Code(new[] { false, true }, new[] { 0x10 });
            keycode["r"] = new Code(new[] { false, true }, new[] { 0x13 });
            keycode["s"] = new Code(new[] { false, true }, new[] { 0x1f });
            keycode["t"] = new Code(new[] { false, true }, new[] { 0x14 });
            keycode["u"] = new Code(new[] { false, true }, new[] { 0x16 });
            keycode["v"] = new Code(new[] { false, true }, new[] { 0x2f });
            keycode["w"] = new Code(new[] { false, true }, new[] { 0x11 });
            keycode["x"] = new Code(new[] { false, true }, new[] { 0x2d });
            keycode["y"] = new Code(new[] { false, true }, new[] { 0x15 });
            keycode["z"] = new Code(new[] { false, true }, new[] { 0x2c });
            keycode[" "] = new Code(new[] { false, true }, new[] { 0x39 });

            keycode[","] = new Code(new[] { false, true }, new[] { 0x33 });
            keycode["."] = new Code(new[] { false, true }, new[] { 0x34 });
            keycode["+"] = new Code(new[] { false, true }, new[] { 0x4E });
            keycode["-"] = new Code(new[] { false, true }, new[] { 0x35 });
            keycode["'"] = new Code(new[] { false, true }, new[] { 0x28 });
            keycode["="] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x0b });
            keycode[":"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x34 });
            keycode["/"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x08 });
            keycode["\""] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x03 });
            keycode["&"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x07 });
            keycode["%"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x06 });
            keycode["("] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x09 });
            keycode[")"] = new Code(new[] { false, false, true, true }, new[] { 0x2a, 0x0a });

            keycode["Win+R+down"] = new Code(new[] { false, false }, new[] { 0x15b, 0x13 });
            keycode["Win+R+up"] = new Code(new[] { true, true }, new[] { 0x15b, 0x13 });
            keycode["Win+D"] = new Code(new[] { false, false, true, true }, new[] { 0x15b, 0x20 });
            keycode["Alt+Shift"] = new Code(new[] { false, false, true, true }, new[] { 0x38, 0x2a });
            keycode["Alt+Space"] = new Code(new[] { false, false, true, true }, new[] { 0x38, 0x39 });
            keycode["Ctrl+Shift"] = new Code(new[] { false, false, true, true }, new[] { 0x1d, 0x2a });
            keycode["Alt+F4"] = new Code(new[] { false, false, true, true }, new[] { 0x38, 0x3e });
            keycode["Ctrl+V"] = new Code(new[] { false, false, true, true }, new[] { 0x1d, 0x2f });
            keycode["Alt+F"] = new Code(new[] { false, false, true, true }, new[] { 0x38, 0x21 });

            keycode["Ctrl+Shift+down"] = new Code(new[] { false, false }, new[] { 0x1d, 0x2a });
            keycode["Ctrl+Shift+up"] = new Code(new[] { true, true }, new[] { 0x1d, 0x2a });

I have compiled it with visual studio and executed it this way (the remote machine with the ES keyboard):

.\SharpRDP.exe  computername=10.0.2.4 command="powershell.exe -enc RwBlAHQALQBTAE0AQgBzAGgAYQByAGUAIAA+ACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHAAZQBwAGUALgBsAG8AZwA=" username=.\Administrador password=Passw0rd!

if I use the flag exec=cmd or exec=powershell the command is never executed. I haven't been able to find out why this bug happens. And I have also removed ToLower from the command entered, because if you force the base64 to be converted to lowercase, for example, the command no longer works. All this at Client.cs

一位同事在这里找到了键盘映射列表https://github.com/apache/guacamole-server/tree/master/src/protocols/rdp/keymaps

Great! I found the map of Caplocks, helping me a lot