/* * pauto.c -- Payload Automation (HID Keystroke Injector) module * * SPDX-License-Identifier: GPL-2.0-or-later * * Payload Automation (HID keystroke injector). Scans /data/vault/payloads/ for .macro * files, parses the OreBolt macro command language (DELAY, * STRING, REM, modifier+key combos), and sends 8-byte USB * HID reports via /dev/hidg0. Full USB HID keycode table * for a-z, A-Z, 0-9, punctuation, F1-F12, and special keys. */ #include #include #include #include #include #include #include #include "h2_ui.h" #include "log_manager.h" #define PAYLOAD_DIR "/data/vault/payloads" #define HID_DEV "/dev/hidg0" #define MAX_PAYLOADS 8 #define LINE_BUF 256 #define DELAY_US 12000 static char payload_names[MAX_PAYLOADS][64]; static int payload_count; static void scan_payloads(void) { DIR *dir = opendir(PAYLOAD_DIR); struct dirent *ent; payload_count = 0; if (!dir) return; while ((ent = readdir(dir)) != NULL && payload_count < MAX_PAYLOADS) { if (ent->d_name[0] == '.') continue; const char *dot = strrchr(ent->d_name, '.'); if (!dot || strcmp(dot, ".macro") != 0) continue; strncpy(payload_names[payload_count], ent->d_name, 63); payload_names[payload_count][63] = '\0'; payload_count++; } closedir(dir); } static void send_hid_report(int hid_fd, uint8_t modifier, uint8_t keycode) { uint8_t report[8] = {0}; report[0] = modifier; report[2] = keycode; write(hid_fd, report, 8); memset(report, 0, 8); write(hid_fd, report, 8); usleep(DELAY_US); } static uint8_t ascii_to_keycode(char c, uint8_t *modifier) { *modifier = 0; if (c >= 'a' && c <= 'z') return (uint8_t)(0x04 + (c - 'a')); if (c >= 'A' && c <= 'Z') { *modifier = 0x02; return (uint8_t)(0x04 + (c - 'A')); } if (c >= '1' && c <= '9') return (uint8_t)(0x1e + (c - '1')); if (c == '0') return 0x27; if (c == ' ') return 0x2c; if (c == '\n') return 0x28; if (c == '-') return 0x2d; if (c == '=') return 0x2e; if (c == '[') return 0x2f; if (c == ']') return 0x30; if (c == '\\') return 0x31; if (c == ';') return 0x33; if (c == '\'') return 0x34; if (c == '`') return 0x35; if (c == ',') return 0x36; if (c == '.') return 0x37; if (c == '/') return 0x38; if (c == '\t') return 0x2b; return 0; } static uint8_t lookup_modifier(const char *token) { if (strcmp(token, "CTRL") == 0 || strcmp(token, "CONTROL") == 0) return 0x01; if (strcmp(token, "SHIFT") == 0) return 0x02; if (strcmp(token, "ALT") == 0) return 0x04; if (strcmp(token, "GUI") == 0) return 0x08; return 0; } static uint8_t lookup_keycode(const char *token) { if (strcmp(token, "ENTER") == 0 || strcmp(token, "RETURN") == 0) return 0x28; if (strcmp(token, "SPACE") == 0) return 0x2c; if (strcmp(token, "TAB") == 0) return 0x2b; if (strcmp(token, "ESC") == 0 || strcmp(token, "ESCAPE") == 0) return 0x29; if (strcmp(token, "BACKSPACE") == 0) return 0x2a; if (strcmp(token, "DELETE") == 0 || strcmp(token, "DEL") == 0) return 0x4c; if (strcmp(token, "F1") == 0) return 0x3a; if (strcmp(token, "F2") == 0) return 0x3b; if (strcmp(token, "F3") == 0) return 0x3c; if (strcmp(token, "F4") == 0) return 0x3d; if (strcmp(token, "F5") == 0) return 0x3e; if (strcmp(token, "F6") == 0) return 0x3f; if (strcmp(token, "F7") == 0) return 0x40; if (strcmp(token, "F8") == 0) return 0x41; if (strcmp(token, "F9") == 0) return 0x42; if (strcmp(token, "F10") == 0) return 0x43; if (strcmp(token, "F11") == 0) return 0x44; if (strcmp(token, "F12") == 0) return 0x45; if (token[0] != '\0' && token[1] == '\0') { uint8_t mod; uint8_t kc = ascii_to_keycode(token[0], &mod); if (kc) return kc; } return 0; } static void execute_payload(const char *filename) { int hid_fd = open(HID_DEV, O_WRONLY); if (hid_fd < 0) { LOG_ERR("cannot open %s", HID_DEV); return; } char path[128]; snprintf(path, sizeof(path), "%s/%s", PAYLOAD_DIR, filename); FILE *fp = fopen(path, "r"); if (!fp) { close(hid_fd); return; } LOG_INF("executing payload: %s", filename); char line[LINE_BUF]; while (fgets(line, LINE_BUF, fp)) { line[strcspn(line, "\r\n")] = '\0'; if (strncmp(line, "DELAY ", 6) == 0) { long ms = atol(line + 6); if (ms < 0) ms = 0; if (ms > 60000) ms = 60000; usleep((useconds_t)(ms * 1000)); continue; } if (strncmp(line, "STRING ", 7) == 0) { const char *p = line + 7; while (*p) { uint8_t mod = 0, key = ascii_to_keycode(*p, &mod); if (key) send_hid_report(hid_fd, mod, key); p++; } continue; } if (strncmp(line, "REM ", 4) == 0 || strcmp(line, "REM") == 0) continue; char tokens[8][32]; int ntok = 0; char *p = line; while (*p && ntok < 8) { while (*p == ' ') p++; if (!*p) break; int ti = 0; while (*p && *p != ' ' && ti < 31) tokens[ntok][ti++] = *p++; tokens[ntok][ti] = '\0'; ntok++; } if (ntok == 0) continue; if (ntok == 1) { uint8_t kc = lookup_keycode(tokens[0]); if (kc) { send_hid_report(hid_fd, 0, kc); continue; } } uint8_t mods = 0; for (int t = 0; t < ntok - 1; t++) mods |= lookup_modifier(tokens[t]); uint8_t keycode = lookup_keycode(tokens[ntok - 1]); if (mods || keycode) { send_hid_report(hid_fd, mods, keycode); continue; } } fclose(fp); close(hid_fd); LOG_INF("payload complete: %s", filename); } int main(void) { init_h2_graphics_runtime("HID KEYSTROKE INJECTOR"); LOG_INF("pauto module started"); lv_obj_t *scr = lv_scr_act(); lv_obj_t *title = lv_label_create(scr); lv_label_set_text(title, "HID PAYLOAD INJECTOR"); lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 15); lv_obj_set_style_text_color(title, COLOR_PRIMARY, LV_PART_MAIN); scan_payloads(); LOG_INF("found %d .macro payloads", payload_count); lv_obj_t *list = lv_list_create(scr); lv_obj_set_size(list, 280, 140); lv_obj_align(list, LV_ALIGN_CENTER, 0, 15); if (payload_count == 0) { lv_list_add_text(list, "No .macro files found in payload dir"); } int sel = 0; for (int i = 0; i < payload_count; i++) { lv_list_add_btn(list, LV_SYMBOL_FILE, payload_names[i]); } int input_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK); struct input_event ev; while (1) { lv_timer_handler(); if (input_fd >= 0 && read(input_fd, &ev, sizeof(struct input_event)) > 0) { if (ev.type == EV_REL && ev.code == 0) { if (ev.value > 0 && sel < payload_count - 1) sel++; else if (ev.value < 0 && sel > 0) sel--; } if (ev.type == EV_KEY && ev.code == H2_KEY_PLAY && ev.value == 1 && payload_count > 0) { execute_payload(payload_names[sel]); } if (ev.type == EV_KEY && ev.code == H2_KEY_BACK && ev.value == 1) break; } usleep(20000); } if (input_fd >= 0) close(input_fd); LOG_INF("pauto module exited"); return 0; }