Review, README, Refactor, New build. New publish.
This commit is contained in:
parent
d17bd484ff
commit
f3e89ef14c
@ -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`
|
||||
.
|
||||
|
57
review.md
57
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.*
|
||||
|
68
tikker.c
68
tikker.c
@ -1,3 +1,20 @@
|
||||
/*
|
||||
Written by retoor@molodetz.nl
|
||||
|
||||
This program captures keyboard input events, resolves device names, and logs these events into a specified database.
|
||||
|
||||
Includes:
|
||||
- sormc.h: Custom library file for database management.
|
||||
|
||||
MIT License:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sormc.h"
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user