65.9K
CodeProject 正在变化。 阅读更多。
Home

Target Eye 揭秘: 第 4 部分 - 键盘捕获

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (42投票s)

2013年8月11日

CPOL

14分钟阅读

viewsIcon

91587

Target Eye 的一部分是如何实现键盘捕获的

引言

本文是关于 Target Eye 监控系统 系列的第四篇文章,该系统开发于 2000 年至 2010 年。 第一篇文章 介绍了 Target Eye 的自动更新机制,以及它是如何无需用户干预即可检查更新、下载、安装并运行新版本的。 第二篇文章 介绍了 Target Eye 的屏幕捕获机制,以及如何创建兼顾图像质量和文件大小的紧凑型 JPG 文件。第三篇文章介绍了“购物清单”机制。第五篇文章介绍了“封面故事”机制,而 第六篇 则解释了文件是如何以及何时被隐藏的,并揭示了如何显示这些隐藏文件。那么,Target Eye 系统的下一个重要组成部分是 **键盘捕获**。实现此功能有多种方法,并且有许多问题需要注意,因此除了某些人可能从中找到的历史价值外,我希望还能带来一些技术价值…… 微笑 | <img src=

在撰写本文时,我还尝试为您提供键盘捕获的其他来源,包括 Code Project 上的文章和外部来源。

什么是 Target Eye

上图为 Target Eye 美国专利申请。

我于 2000 年开发的 Target Eye 监控系统 是最早用于捕获远程计算机活动的监控工具之一。与黑客工具不同,Target Eye 是一款监控工具,旨在供执法机构使用,特别是供不了解黑客技术的人员使用。该产品专注于信息,如何收集、结构化、汇总和准备信息,以便作为正在进行的调查的一部分。Target Eye 的设计目标是能够运行数月甚至数年而不崩溃,这是此类产品的一项非常重要的要求,因为被调查的用户在软件运行期间不应有任何操作。这一要求催生了无需用户干预即可进行安装升级和报告等功能的需求,因此稳定性是关键因素。此类产品的质量保证需要数千小时的测试,老实说,错误总会发生,要避免大多数错误需要时间,因此只有经过多年使用的成熟产品才能信赖。

Target Eye 监控系统包含几个构建块

  • Target Eye Secret Agent - 该产品的隐蔽部分,运行在被监控的计算机上。
  • Target Eye Operator - 操作 Secret Agent 的授权方(例如:执法机构)。
  • A Mission - 执行操作的请求。有许多可能的操作(例如,如我在另一篇文章中所述的屏幕捕获,或如在本文中所述的文件搜索和查找)。
  • Target Eye Compiler - Target Eye Operator 用于自定义 Secret Agent 以执行特定任务的工具。

键盘捕获由 **Target Eye Secret Agent** 执行,并由 **Target Eye Compiler** 进行配置。

什么是键盘捕获

根据 牛津词典 的定义,**键盘记录**(也称为键盘捕获)是“一种计算机程序,它记录计算机用户输入的每一个按键,尤其是为了欺诈性地访问密码和其他机密信息”。

无需多言,记录按键有许多合法的原因(尤其是在您记录和监控自己的 PC 时……),从家长控制到执法部门、军队和情报机构用于打击网络犯罪和恐怖活动。Target Eye 的发明主要针对这些市场。此外,“键盘记录器”这类记录按键的产品与 Target Eye 这样的监控产品之间存在区别,后者会记录按键以及其他信息。

当我写一篇新文章时,我首先会查看关于我正在写的这个主题已经写了什么。因此,这里有一篇名为 **基本按键挖掘** 的文章,作者是 Alexander Kent,其中提供了 C# 代码示例。另一篇关于 **鼠标和键盘钩子** 的文章,作者是 Adam Roderick J,该文章介绍了使用全局钩子(需要 DLL)的传统方法(源代码是 C++,示例应用程序与键盘记录器不常见,因为它像录放系统一样工作。您录制您的事件 - 鼠标和键盘活动,然后播放给您)。据我所知,这种想法的第一个演示是由我的一位朋友引入的,他是一位现在在电影行业很有名的程序员, Oren Peli,他在 16 岁时就编写了这样一个应用程序,当时他有一台 Amiga 电脑……我读过的另一篇有趣的文章是关于 内核中的键盘钩子,作者是 Günter Bergmann。您可能还会发现以下文章:**侦听键盘活动的后台应用程序**,其中包含 VB 源代码。

我找到的另外两个来源是:Kid LoggerSpyTool

Kid LoggerRohos 的一款商业产品(家长控制系统),Rohos 是一家摩尔多瓦的初创公司,它收集 Windows、Mac 或手机用户活动数据,并在网上提供详细的工时跟踪和生产力报告。我提到这个产品是因为它包含了完整的源代码。要获取源代码,您需要下载试用版并安装。您会在安装文件夹内找到源代码文件夹。源代码不是最新版本,但它完美地展示了如何在 DLL 中使用全局钩子。Rohos,我与他们合作多年,在信息安全领域的许多方面都取得了令人惊叹的成就,显然他们的源代码,即使已经过时,在编码标准方面也是最先进的。

SpyTool 是一款间谍软件,不仅可以捕获键盘,还可以捕获被监控计算机连接的网络摄像头。它是由我的同事 Gregory Stein 开发的,他在 Intel 有全职工作,因此更新他的项目的时间非常少。Greg 好心地允许我检查是否有可能将他源代码的某些部分(特别是网络摄像头捕获代码)用于 Target Eye 的当前和未来版本。

上图 - 如何开启和关闭键盘捕获(2),以及如何定义热词(2)。

Target Eye 如何演变

我于 2000 年开始开发 Target Eye,从可视化(UI)部分开始,这将在未来的文章中介绍。这部分用于在“视频墙”布局中显示来自多个源的数据(主要是屏幕捕获图像)。第一个 POC 是在 Visual Basic 6.0 下开发的,这是第一个版本的示例。GetText 返回给定窗口的标题文本。

Function GetText(hWnd) As String
    Dim GetString As String
    Dim TrimSpace$
    Dim GetTrim
    GetTrim = Sendmessagebynum(hWnd, 14, 0&, 0&)
    TrimSpace$ = Space$(GetTrim)
    GetString = SendMessageByString(hWnd, 13, GetTrim + 1, TrimSpace$)
    GetText = TrimSpace$ 
End Function 

几周后,推出了 C++ 版本(Visual C++ 6.0)……

上图显示 Target Eye 2000 同时监控 6 个“代理”。

然后我开始研究“Secret Agent”部分,这是实际的引擎,被植入到被监控的计算机中并收集信息。这个代理的一部分是捕获键盘。通过检查早期版本,JournalLogProc 随着时间的推移发生了变化。在 2000-2004 年,它使用 ToAscii() 处理文本,并立即将输入的每个字符保存到数据文件中,这导致被监控 PC 变慢。

BYTE kbuf[256]; 
WORD ch; 
int chcount; 					 
GetKeyboardState(kbuf); 					 
chcount=ToAscii(vKey,nScan,kbuf,&ch,0);
if(chcount>0) 
{
	int IsHotWord=CheckHotWords(ch); 
	WriteFile(g_hCapFile,&ch,chcount,&dwBytes,NULL);	 

2005 年有所不同,当时使用了 ToAsciiEx()。数据首先捕获到一个缓冲区以提高速度。还使用了 GetKeyboardLayout()。

DWORD dwCount;			 
char svBuffer[256]; 
int vKey,nScan; 
DWORD idT = GetWindowThreadProcessId(destWnd, NULL);
KL = GetKeyboardLayout(idT);   
GetKeyboardState(kbuf); 
chcount=ToAsciiEx(vKey,nScan,kbuf,&ch,0,KL);
if(chcount>0) 
{ 
	AddText(ch,FALSE); 
... 

除了这些演变之外,Target Eye 始终在不使用外部 DLL 的情况下提供键盘捕获。

处理特殊键

一个 proper 的键盘捕获引擎应该能够处理特殊键,并将这些键或组合键转换为用户友好的数据文件条目。一个很好的例子是反映删除的文本。当文本被删除时,实际捕获的按键是 BACKSPACE 或 DEL。Target Eye 将它们显示为 [XXX] 和 [---],所以如果数据文件显示

I have corrected my mistac[XXX]ke”,这意味着在输入“c”时,它被删除并替换为“k”。

其他特殊键是:

  • VK_SPACE(或 SPACE 键)- 在较近的版本中,Target Eye 将捕获的数据保存到缓冲区,并在捕获 SPACE 或 ENTER 键时将缓冲区刷新到数据文件中。
  • RETURN / ENTER - 这些特殊键的处理方式相同,并转换为新行('\n')。
  • 箭头键 - 这些有助于理解编辑发生在何处(以及鼠标光标的位置指示)。
  • 功能键 - 这些键被转换为它们的名称。F1 会显示为“F1”等等……

这里是部分源代码,其中解释了一些特殊键。

  case VK_TAB:  
	api_lpsz = _T("[TAB]");
	break;
  case VK_LEFT:   
	api_lpsz = _T("[LEFT]");
	break;
  case VK_RIGHT:  
	api_lpsz = _T("[RIGHT]");
	break;
  case VK_UP:     
	api_lpsz = _T("[UP]");
	break;
  case VK_DOWN:   
	api_lpsz = _T("[DOWN]");
	break;
  case VK_PRIOR:  
	api_lpsz = _T("[PAGE UP]");
	break;
  case VK_NEXT:   
	api_lpsz = _T("[PAGE DOWN]");
	break;
  case VK_END:    
	api_lpsz = _T("[END]");
	break;  
  case VK_HOME:
	api_lpsz = _T("[HOME]");
	break;

处理热词

通常作为键盘捕获一部分的另一个功能是处理热词。热词是用来触发警报并引起其他操作的短语。例如,Target Eye 的操作员可能会要求,当输入短语“murder”或“kill”时,会截取屏幕截图并向操作员发送电子邮件警报。

首先,初始化热词数组。在商业产品中,热词列表是从应用程序的加密段中获取的,该段由 Compiler 附加。在这个代码示例中,我们只添加 2 个条目。

void InitHotWords()
{ 
	// This POC has hardcoded hot words, unlike the real Target Eye 
    // which uses the definitions created by the Compiler
	HotWords.RemoveAll();
	HotWords.Add("kill");
	HotWords.Add("murder");
}    

接下来是分析捕获的文本并将其与此列表进行检查的部分。

CheckHotWords() 返回在当前缓冲区中找到的热词的索引,如果没有找到则返回 -1

inline int CheckHotWords()
{	
	int i,result=-1;	// index of hotword found
		
	for(i=0;i<=HotWords.GetUpperBound();i++)
	{
		int Len=HotWords[i].GetLength();
		
		if(CaptureString.GetLength()>=Len)
		{
			if(CaptureString.Right(Len)==HotWords[i])
			{
				result=i;
				break;
			}
		}
	}
	return(result);
} 

Target Eye 使用的方法确保无论热词在何处以及如何输入,都会被捕获。为此,您可以转到 Google,输入“ki”,然后切换到记事本并输入“ll”,就会捕获到单词“kill”。当然,这可以更改和定制。

用于键盘捕获的方法

键盘捕获有几个要求。输入会消耗 CPU,尤其是在快速输入时。用于捕获输入文本的后台线程会消耗更多 CPU,这可能导致被监控的 PC 变慢,以及输入响应变慢,这可能会让被监控用户感到恼火。另一个可能的问题是按键丢失。对于用于执法和法证目的的工具来说,丢失一个按键也是不可接受的。此外,在整个监控会话中创建和更新的数据文件必须在任何给定时刻都是最新和准确的,即使例如,在输入过程中,PC 被突然关闭(例如,断电)。键盘捕获必须反映当前活动的应用程序和窗口,并将每个按键与正确的窗口和应用程序相关联。屏幕截图(我在这篇文章中介绍过)也应该与在此屏幕捕获期间输入的任何文本相关联。

有几种方法可以用来记录键盘:

SetWindowsHookEx

常用的方法是使用一个独立的 DLL 创建的全局钩子。请参阅此链接

HHOOK WINAPI SetWindowsHookEx(
  _In_  int idHook,
  _In_  HOOKPROC lpfn,
  _In_  HINSTANCE hMod,
  _In_  DWORD dwThreadId
); 

我在使用此方法时遇到了一些问题,尤其是在最新的 Windows 版本(例如 Windows 7)中,按键会丢失,尤其是在 CPU 活动高的情况下。

RegisterRawInputDevices

一种不太为人知的方法 - 直接使用键盘的**原始输入**。

BOOL WINAPI RegisterRawInputDevices(
  _In_  PCRAWINPUTDEVICE pRawInputDevices,
  _In_  UINT uiNumDevices,
  _In_  UINT cbSize 
;  

WH_JOURNALRECORD

我选择使用 Journal 钩子来实现 Target Eye,并且自从 Target Eye 的第一个版本(2000 年)和后来的产品版本以来,只有很少的改动。**Journal 钩子**是用于记录和播放键盘和鼠标事件的系统范围内的钩子,但是对于监控系统来说,我们只需要记录机制,这会生成一个存储所有文本的数据文件。

这种方法在当年(至少到 2007 年)效果很好,但今天可能无法在没有一些调整的情况下工作,因为自 Windows Vista 以来,WH_JOURNALRECORD 类型的钩子需要管理员权限、代码签名以及其他限制和要求。请参阅此链接

处理日期和时间戳

当您构建一个将在不同国家/地区运行并在其他国家/地区进行远程控制的监控产品时,您必须考虑到时区,而不仅仅是本地时间。

Target Eye 使用 CTime 类(可在 MFCATLWTL 中找到)。

使用 GetGmtTm() 获取通用日期和时间,该日期和时间将与时区无关。

此外,实际时区可以在数据文件中显示(Target Eye 仅对屏幕捕获文件这样做)。

处理国际字符

文本的捕获与活动应用程序无关,因此,您可以直接按键盘,即使没有活动应用程序,文本仍然会被完整记录。Target Eye 与其他类似产品一样,会跟踪输入文本时活动的窗口,这有助于操作员确定捕获文本的上下文。

许多键盘记录系统运行快速高效,但在输入另一种语言时,捕获的文本文件中仍然会显示相同的拉丁字母文本。这是因为从钩子机制的角度来看,无论选择哪种语言,捕获的按键都是相同的。许多 PC 用户拥有多种语言(通常是两种)系统,他们使用 ALT+SHIFT 进行切换。一个好的监控系统应该能够检测到选定的活动语言(键盘布局)并将按键的键码转换为正确的字符。例如,在使用希伯来语-英语系统时,按下键盘上的“A”键,如果选择了英语,则应捕获“a”或“A”(取决于是否按下了 SHIFT),当选择了希伯来语时,则应捕获字符“ש”。做到这一点的方法是,在获取当前选定的语言(通过调用 GetKeyboardState() 完成)后,立即调用 ToUnicodeEx()

GetKeyboardState() 将 256 个虚拟键的状态复制到指定的缓冲区。

BOOL WINAPI GetKeyboardState(_Out_  PBYTE lpKeyState);  

ToUnicodeEx() 将指定的虚拟键代码和键盘状态转换为相应的 Unicode 字符。

int WINAPI ToUnicodeEx(
  _In_      UINT wVirtKey,
  _In_      UINT wScanCode,
  _In_      const BYTE *lpKeyState,
  _Out_     LPWSTR pwszBuff,
  _In_      int cchBuff,
  _In_      UINT wFlags,
  _In_opt_  HKL dwhkl
);    

处理多种语言的完整代码如下:

DWORD dwMsg = p->scanCode << 16;
// Translate to actual character depending on keyboard state and layout
BYTE keyState[256];
GetKeyboardState(keyState);
key[0]=key[1]=key[2]=0; // reset key. Note that act_length=1 "[A]"
ToUnicodeEx(p->vkCode, p->scanCode, keyState, key, 1, p->flags,layout);  

处理数据文件

与屏幕捕获为每个屏幕截图生成一个单独的文件不同,键盘捕获的文本保存在一个连续的文件中并被不断更新。这个文件可能会变得很大,通常在通过电子邮件发送给操作员或上传到 FTP 服务器后会被重置。

数据文件的创建或更新(如果已存在)方式如下:

void CreateKBCFile()
{
	HANDLE g_hCapFile;
	CTime theTime=CTime::GetCurrentTime();
	CString TempFileName;
	DWORD dwBytes;
	g_hCapFile=CreateFile(POC_LOGFILENAME,GENERIC_WRITE,FILE_SHARE_WRITE,
               NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,NULL);
	if(g_hCapFile==INVALID_HANDLE_VALUE) 
	{
		TRACE("Can't open log file %s\n",POC_LOGFILENAME);
		return;
	}
	SetFilePointer(g_hCapFile,0,NULL,FILE_END);
	if(!(WriteFile(g_hCapFile,CaptureString.Mid(12),
         CaptureString.GetLength()-12,&dwBytes,NULL)))
	{
		TRACE("KB Capturing: Can't write to log file %s\n",POC_LOGFILENAME);
	}
	CloseHandle(g_hCapFile);
	return;
}    

典型的数据文件

下面的示例显示了一个典型的数据文件(各种部分已突出显示)。

数据文件包含几个部分:

  1. 活动窗口
  2. 输入的文本
  3. 时间/日期戳
  4. 删除文本
  5. 用于指示操作案件 ID、主题 ID 等的文件名。

然后,在分析这样的文件时,有时可以很容易地确定用户名、密码、登录详细信息等。事实上,如果您自己监控自己的 PC(我准备这篇文章时就是这样做的),如果您需要,可以找回丢失的密码……

摘要

本文旨在提供 Target Eye 系统的另一个视角,对于键盘捕获部分,我没有提供该产品早期版本的源代码,原因如我所述。

历史

  • 2014 年 6 月 12 日:初始版本

Michael Haephrati CodeProject MVP 2013

©2000-2010 Target Eye LTD (UK)

本文中包含的所有材料均受国际版权法保护,未经 Target Eye LTD (UK) 事先书面许可,不得使用、复制、分发、传播、展示、出版或广播。您不得更改或删除副本中的任何商标、版权或其他声明。
© . All rights reserved.