From d48ca89d20d98d93379b0d0555d390588a822797 Mon Sep 17 00:00:00 2001 From: Kevin F Date: Thu, 2 Mar 2023 21:20:34 -0600 Subject: [PATCH] Replace sendkeys with keylogger --- Client.md | 8 ++++--- Dependencies.md | 9 ++++---- EnvironmentVariables.md | 4 ++-- server/Sendkeys.md | 46 ++++++++++++++--------------------------- server/Server.md | 2 +- server/Streaming.md | 21 +++++++++++++++---- tools/Input.md | 2 +- 7 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Client.md b/Client.md index 9396c40..551359c 100644 --- a/Client.md +++ b/Client.md @@ -14,9 +14,9 @@ When the GoSmartKeyboard client is started, it does the following: --- handle client command if len(os.Args) > 1 { - @{get client fifo input file from environment} + @{get client fifo input file from environment} @{setup client} - if clientFifoInputFileExists { + if clientFifoInputFileEnvExists { @{start client with fifo} os.Exit(0) } @@ -97,6 +97,8 @@ if !strings.HasPrefix(connectionURL, "ws://") && !strings.HasPrefix(connectionUR var inputString string +syscall.Mkfifo(clientFifoInputFile, syscall.S_IFIFO|0666) + for { input, err := ioutil.ReadFile(clientFifoInputFile) if err != nil { @@ -118,7 +120,6 @@ for { ``` - ## Sending keys from stdin @@ -187,6 +188,7 @@ package main import ( "strings" "io/ioutil" + "syscall" "io" "bufio" "log" diff --git a/Dependencies.md b/Dependencies.md index 5bb9b6e..c100fbf 100644 --- a/Dependencies.md +++ b/Dependencies.md @@ -24,14 +24,13 @@ We use sha3 to hash authentication tokens. It is not in the crypto standard libr --- -# sendkeys +# keylogger +We use keylogger to get keyboard input on the client and simulate keystrokes on the server. -In order to avoid coding key press simulation for every major platform, we use [sendkeys](https://github.com/yunginnanet/sendkeys). This is a cross-platform library that uses the OS's native key press simulation using [keybd_event](https://github.com/micmonay/keybd_event) +--- keylogger import string ---- sendkeys import string - - "github.com/EgosOwn/sendkeys" + "github.com/MarinX/keylogger" --- diff --git a/EnvironmentVariables.md b/EnvironmentVariables.md index 3f80b2e..deee10a 100644 --- a/EnvironmentVariables.md +++ b/EnvironmentVariables.md @@ -7,7 +7,7 @@ Some users may always want xdotool, see the [Streaming.md](Streaming.md) file fo ``` go --- always use xdotool environment variable -var alwaysUseXdotool := false +var alwaysUseXdotool = false alwaysUseXdotoolEnv, alwaysUseXdotoolExists := os.LookupEnv("KEYBOARD_ALWAYS_USE_XDOTOOL") if alwaysUseXdotoolExists { if alwaysUseXdotoolEnv == "true" || alwaysUseXdotoolEnv == "1" { @@ -46,7 +46,7 @@ authTokenInput, authTokenInputExists := os.LookupEnv("KEYBOARD_AUTH") --- get client fifo input file from environment -clientFifoInputFile, clientFifoInputFileExists := os.LookupEnv("KEYBOARD_FIFO") +clientFifoInputFile, clientFifoInputFileEnvExists := os.LookupEnv("KEYBOARD_FIFO") --- diff --git a/server/Sendkeys.md b/server/Sendkeys.md index b3f5c27..4b7c96b 100644 --- a/server/Sendkeys.md +++ b/server/Sendkeys.md @@ -1,39 +1,25 @@ -# Send keys streaming approach +# uinput streaming approach -When applicable to use send keys, we need to detect Enter, Tab, and BackSpace and use the applicatble functions. -We test if it meets the characterRegex, and if so we iterate for each character and send the corresponding key. -Otherwise we send the entire string at once. ``` go ---- do streaming sendkeys approach -if characterRegex.MatchString(message_string) { - for _, character := range message_string { - charString := string(character) - if charString == "\n" { - keyboard.Enter() - continue - } - if charString == "\t" { - keyboard.Tab() - continue - } - if charString == "\b" { - keyboard.BackSpace() - continue - } - err = keyboard.Type(charString) - if err != nil { - log.Println("type:", err) - } - continue +--- do streaming keylogger approach + +key := "" +if strings.HasPrefix(message_string, "{KEYDWN}") { + key = strings.TrimPrefix(string(message_string), "{KEYDWN}") + k.Write(1, key) +} else if strings.HasPrefix(message_string, "{KEYUP}") { + key = strings.TrimPrefix(string(message_string), "{KEYUP}") + k.Write(0, key) +} else{ + for _, key := range message_string { + // write once will simulate keyboard press/release, for long press or release, lookup at Write + k.WriteOnce(string(key)) } - continue -} -err = keyboard.Type(message_string) -if err != nil { - log.Println("type:", err) } + + --- ``` \ No newline at end of file diff --git a/server/Server.md b/server/Server.md index 0ec4fe2..b0cbd20 100644 --- a/server/Server.md +++ b/server/Server.md @@ -68,7 +68,7 @@ import( "log" "keyboard.voidnet.tech/auth" @{gorilla/websocket import string} - @{sendkeys import string} + @{keylogger import string} ) var listener net.Listener diff --git a/server/Streaming.md b/server/Streaming.md index 620bdea..573bb77 100644 --- a/server/Streaming.md +++ b/server/Streaming.md @@ -2,9 +2,9 @@ We use the Gorilla websocket library to handle the websocket connection. -Most of the time, we can use sendkeys (which uses libinput) to effeciently press keys. However, if we need to send a character that sendkeys doesn't know about, we can use the xdotool command. xdotool is also useful if one does not want to use root. +Most of the time, we can use the keylogger library (which uses uinput) to effeciently press keys. However, if we need to send a character that keylogger doesn't know about, we can use the xdotool command. xdotool is also useful if one does not want to use root. -xdotool spawns a new process for each keypress, so it's not as effecient as sendkeys. +xdotool spawns a new process for each keypress, so it's not as effecient as keylogger. To specify xdotool usage, the client should send a message with the format `{kb_cmd:xdotool}:message` where message is a utf-8 string. @@ -14,7 +14,20 @@ To specify xdotool usage, the client should send a message with the format `{kb_ func clientConnected(w http.ResponseWriter, r *http.Request) { // regex if string has characters we need to convert to key presses characterRegex, _ := regexp.Compile(`[^\x08]\x08|\t|\n`) - keyboard, err := sendkeys.NewKBWrapWithOptions(sendkeys.Noisy) + + // find keyboard device, does not require a root permission + keyboard := keylogger.FindKeyboardDevice() + + // check if we found a path to keyboard + if len(keyboard) <= 0 { + return + } + + k, err := keylogger.New(keyboard) + if err != nil { + return + } + defer k.Close() @{always use xdotool environment variable} @@ -84,7 +97,7 @@ doXDoTool := func(command string, keys string)(err error) { @{handle xdotoool commands} -@{do streaming sendkeys approach} +@{do streaming keylogger approach} --- ``` \ No newline at end of file diff --git a/tools/Input.md b/tools/Input.md index f0f30b6..fc4d7fc 100644 --- a/tools/Input.md +++ b/tools/Input.md @@ -19,7 +19,7 @@ import ( func main(){ var input string - @{get client fifo input file from environment} + @{get client input file from environment} if ! clientFifoInputFileExists { os.Exit(1) }