From f3e89ef14c827773e558b34099f4445719f07283 Mon Sep 17 00:00:00 2001 From: retoor Date: Thu, 26 Dec 2024 00:48:47 +0100 Subject: [PATCH] Review, README, Refactor, New build. New publish. --- README.md | 7 ++++++ review.md | 57 +++++++++++++++++++++++++++------------------ tikker | Bin 230752 -> 230752 bytes tikker.c | 68 +++++++++++++++++++++++++----------------------------- 4 files changed, 72 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 75ee8ff..9ba69f9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,13 @@ This is an application for monitoring your key presses. It will store all your keypresses in a database called 'tikker.db' in current work directory. +It didn't came well out of the [review](tikker.c.md). + - It contains one bug for sure. + - Other issues were false positives. + - Did not agree on some points. + - I can do whatever I want, but in the end i'll just be a 6-quality-person. + - Tsoding says, you have two kinds of people. One that writes perfect code and the ones that get shit done. I'm the latter. School time's over. It's time for work. + Pre-build binaries: - Download using `curl -OJ https://retoor.molodetz.nl/api/packages/retoor/generic/tikker/1.0.0/tikker` . diff --git a/review.md b/review.md index 77dc003..8f0aa52 100644 --- a/review.md +++ b/review.md @@ -1,35 +1,46 @@ markdown -# Keylogger Program Analysis +# Keyboard Input Event Logger Summary ## Overview -This document reviews a C-based program designed to monitor multiple keyboard devices for input events and log them into a database. The code includes mappings of keycodes to character representations and utilizes system calls to interact with input devices efficiently. +This C program captures keyboard input events, resolves device names, and logs these events into a specified SQLite database `tikker.db`. It utilizes a custom library `sormc.h` for database management. -## Code Highlights +## Features -### Bugs -- **Key Mapping:** The `keycode_to_char` array lacks comprehensive keycode definitions, leading to potential null pointer dereferences. -- **Security Risk:** SQL injection vulnerability due to direct variable embedding in queries. -- **Unhandled Returns:** Undefined behavior for unknown keycodes, potentially causing `NULL` insertions in the database. +- **Key Event Mapping**: Maps keycodes to their respective characters for better representation. +- **Event Logging**: Logs key events with timestamps efficiently into the database. +- **User Configuration**: Allows device selection via a command-line option for targeted event capturing. +- **MIT License**: Allows free use, modification, and distribution of the software. -### Optimizations -- Implement error handling for `snprintf` in loops and use `strncasecmp` for safer keyboard checks. -- Minimize `EVIOCGNAME` calls by caching device names. -- Bound checks to prevent `keycode_to_char` array access overflow and batch `read` operations for performance. -- Ensure proper resource cleanup, including database connection closure. -- Adopt dynamic memory allocation if `device_path` exceeds 32 characters. +## Bugs and Issues -### Strengths -- Efficient monitoring of multiple devices using `fd_set` and `select()`. -- Proper use of `snprintf` to prevent buffer overflow. -- Logical division between device acquisition and event processing. +1. **Undefined Functions**: Missing definitions for `rargs_get_option_string`, `sormc`, and `sormq`, leading to potential undefined behavior. +2. **Device Resolution**: Uses `O_RDONLY` to open devices, which may need root access, potentially causing permission issues. +3. **Array Boundaries**: Access to `keycode_to_char` without bounds checking could lead to undefined behavior. +4. **Error Handling**: Lack of checks after using `snprintf`, `open`, and `ioctl`, leading to potential failures and bugs. -## Summary +## Recommendations -Despite its functional capability, the program presents issues primarily in security, efficiency, and resource management. Addressing vulnerabilities and performance limitations could substantially enhance its reliability. +- **Argument Parsing**: Use robust libraries for better flexibility and error management. +- **Signal Handling**: Implement graceful termination with proper file descriptor management. +- **Error Checking**: Add checks post `snprintf`, `open`, and `ioctl` to handle errors effectively. +- **Optimize Performance**: Reduce redundancy in `printf` statements for better efficiency. -### Recommendations +## Positive Attributes -Consider using open-source alternatives for better functionality: -- **Logkeys:** Offers broader functionality and community support. -- **Keylogger:** Lightweight with active development on GitHub. +- Effectively maps keycodes to characters. +- Provides informative console output for ongoing events. +- Efficient database logging of key events. + +## Potential Improvements + +To enhance its robustness and user-friendliness, the program needs the implementation of missing functions and improved error-handling mechanisms. + +## Alternative Open Source Tools + +- **logkeys**: A Linux keylogger similar in function. +- **Keylogger (Python)**: Uses `pynput` for cross-platform keylogging. +- **Linux-dirty-injector**: Provides additional functionalities including keylogging. + +--- +*Note: The program is reviewed with a grade of 6.0, suggesting more development is needed in error handling and functionality completion.* diff --git a/tikker b/tikker index 0ba69d213c71e66af4403fd15617f7d359ff23ed..bed9ef10d00130fd0246317737b026633c7108bc 100755 GIT binary patch delta 8191 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 #include @@ -16,7 +33,6 @@ const char *keycode_to_char[] = { [2] = "1", [3] = "2", [4] = "3", [5] = "4", [6] = "5", [7] = "6", [8] = "7", [9] = "8", [10] = "9", [11] = "0", [12] = "-", [13] = "=", [14] = "[BACKSPACE]", [15] = "[TAB]", - [16] = "Q", [17] = "W", [18] = "E", [19] = "R", [20] = "T", [21] = "Y", [22] = "U", [23] = "I", [24] = "O", [25] = "P", [26] = "[", [27] = "]", [28] = "[ENTER]\n", [29] = "[LEFT_CTRL]", @@ -27,35 +43,27 @@ const char *keycode_to_char[] = { [49] = "N", [50] = "M", [51] = ",", [52] = ".", [53] = "/", [54] = "[RIGHT_SHIFT]", [55] = "[KEYPAD_*]", [56] = "[LEFT_ALT]", [57] = " ", [58] = "[CAPSLOCK]", - [59] = "[F1]", [60] = "[F2]", [61] = "[F3]", [62] = "[F4]", [63] = "[F5]", [64] = "[F6]", [65] = "[F7]", [66] = "[F8]", [67] = "[F9]", [68] = "[F10]", [87] = "[F11]", [88] = "[F12]", - [69] = "[NUMLOCK]", [70] = "[SCROLLLOCK]", [71] = "[KEYPAD_7]", - [72] = "[KEYPAD_8]", [73] = "[KEYPAD_9", [74] = "[KEYPAD_-]", - [75] = "[KEYPAD_4]", [76] = "[KEYPAD_5", [77] = "[KEYPAD_6]", - [78] = "[KEYPAD_+]", [79] = "[KEYPAD_1", [80] = "[KEYPAD_2]", - [81] = "[KEYPAD_3]", [82] = "[KEYPAD_0", [83] = "[KEYPAD_.]", - + [72] = "[KEYPAD_8]", [73] = "[KEYPAD_9]", [74] = "[KEYPAD_-]", + [75] = "[KEYPAD_4]", [76] = "[KEYPAD_5]", [77] = "[KEYPAD_6]", + [78] = "[KEYPAD_+]", [79] = "[KEYPAD_1]", [80] = "[KEYPAD_2]", + [81] = "[KEYPAD_3]", [82] = "[KEYPAD_0]", [83] = "[KEYPAD_.]", [86] = "<", [100] = "[RIGHT_ALT]", [97] = "[RIGHT_CTRL]", [119] = "[PAUSE]", [120] = "[SYSRQ]", [121] = "[BREAK]", - [102] = "[HOME]", [103] = "[UP]", [104] = "[PAGEUP]", [105] = "[LEFT]", [106] = "[RIGHT]", [107] = "[END]", [108] = "[DOWN]", [109] = "[PAGEDOWN]", [110] = "[INSERT]", [111] = "[DELETE]", - [113] = "[MUTE]", [114] = "[VOLUME_DOWN]", [115] = "[VOLUME_UP]", [163] = "[MEDIA_NEXT]", [165] = "[MEDIA_PREV]", [164] = "[MEDIA_PLAY_PAUSE]" }; - - -char * resolve_device_name(int fd) { +char *resolve_device_name(int fd) { static char device_name[256]; device_name[0] = 0; - if (ioctl(fd, EVIOCGNAME(sizeof(device_name)), device_name) < 0) { return 0; } @@ -63,37 +71,29 @@ char * resolve_device_name(int fd) { } int main(int argc, char *argv[]) { - - char * device_to_read = rargs_get_option_string(argc, argv, "--device", DEVICE_TO_READ_DEFAULT); - + char *device_to_read = rargs_get_option_string(argc, argv, "--device", DEVICE_TO_READ_DEFAULT); int db = sormc(DATABASE_NAME); - ulonglong times_repeated = 0; ulonglong times_pressed = 0; ulonglong times_released = 0; - sormq(db, "CREATE TABLE IF NOT EXISTS kevent (id INTEGER PRIMARY KEY AUTOINCREMENT, code,event,name,timestamp,char)"); - int keyboard_fds[MAX_DEVICES]; int num_keyboards = 0; for (int i = 0; i < MAX_DEVICES; i++) { char device_path[32]; snprintf(device_path, sizeof(device_path), "%s%d", DEVICE_PATH, i); - int fd = open(device_path, O_RDONLY); if (fd < 0) { continue; } - char * device_name = resolve_device_name(fd); - if(!device_name) - { + char *device_name = resolve_device_name(fd); + if (!device_name) { close(fd); continue; } bool is_device_to_read = strstr(device_name, device_to_read) != NULL; - printf("[%s] %s. Mount: %s.\n", is_device_to_read ? "-" : "+", device_name, device_path); - + printf("[%s] %s. Mount: %s.\n", is_device_to_read ? "-" : "+", device_name, device_path); if (is_device_to_read) { keyboard_fds[num_keyboards++] = fd; } else { @@ -102,21 +102,19 @@ int main(int argc, char *argv[]) { } if (num_keyboards == 0) { - fprintf(stderr, "No keyboard found. Do you execute under root?\n" - "If your device is listed above with a minus[-] in front of it,\n" - "execute this application using --device='[DEVICE_NAME]'\n"); + fprintf(stderr, "No keyboard found. Are you running as root?\n" + "If your device is listed above with a minus [-] in front, \n" + "run this application using --device='[DEVICE_NAME]'\n"); return 1; } printf("Monitoring %d keyboards.\n", num_keyboards); - struct input_event ev; fd_set read_fds; while (1) { FD_ZERO(&read_fds); int max_fd = -1; - for (int i = 0; i < num_keyboards; i++) { FD_SET(keyboard_fds[i], &read_fds); if (keyboard_fds[i] > max_fd) { @@ -132,17 +130,14 @@ int main(int argc, char *argv[]) { for (int i = 0; i < num_keyboards; i++) { if (FD_ISSET(keyboard_fds[i], &read_fds)) { ssize_t bytes = read(keyboard_fds[i], &ev, sizeof(struct input_event)); - if (bytes == sizeof(struct input_event)) { if (ev.type == EV_KEY) { - char * char_name = NULL; + char *char_name = NULL; if (ev.code < sizeof(keycode_to_char) / sizeof(keycode_to_char[0])) { char_name = (char *)keycode_to_char[ev.code]; } - char keyboard_name[256]; ioctl(keyboard_fds[i], EVIOCGNAME(sizeof(keyboard_name)), keyboard_name); - printf("Keyboard: %s, ", keyboard_name); char *event_name = NULL; if (ev.value == 1) { @@ -155,9 +150,8 @@ int main(int argc, char *argv[]) { event_name = "REPEATED"; times_repeated++; } - sormq(db, "INSERT INTO kevent (code, event, name,timestamp,char) VALUES (%d, %s, %s, DATETIME('now'),%s)", ev.code, - event_name, keyboard_name,char_name); + event_name, keyboard_name, char_name); printf("Event: %s, ", ev.value == 1 ? "PRESSED" : ev.value == 0 ? "RELEASED" : "REPEATED"); printf("Key Code: %d, ", ev.code); printf("Name: %s, ", char_name);