文件关联方法较早由“冰河”程序实现。“冰河”为了达到自我保护目的,进行了TXT和EXE文件关联。在普通程序打开后缀名为.txt 和.exe文件时,首先打开“冰河”程序,执行完既定功能后,再把相关参数(如要打开的文本文件名)传递给.txt默认的打开程序(如 notepad.exe)。具体实现就是修改注册表项:“HKEY_CLASSES_ROOT\txtfile\shell\open\command” 的REG_EXPAND_SZ类型值。系统该值默认为:“%SystemRoot%\system32\NOTEPAD.EXE %1”,其中“%1”即代表需要打开的文本文件名。“冰河”程序的这种关联方式影响了很多后来的木马后门程序,当然,也成了杀毒软件重点关注的对象。有没有另外的方法来进行程序的关联操作呢?
Solomon和Russinovich的著作:《Windows 2000内部揭秘》深入的探讨了系统方方面面的设计和实现问题。在讨论“CreateProcess流程”一节中,Russinovich指出,程序通过 CreateProcess创建进程时,首先第一步是打开要执行的映像(具体参考本书相关章节)。具体就是CreateProcess找到合适的 Win32映像,比如Win32程序是Win32还是Win16、MS-DOS、POSIX或者OS/2等等,进而会选择合适的加载器来进行Win32映像的加载。找到有效的Win32可执行映像后,CreateProcess会在注册表\HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options 下查看是否有一个带有可执行映像的文件名和扩展名的子键(如是否有notepad.exe表项),如果有,则CreateProcess会在该表项中寻找名为Debugger的值。如果该值非空,则运行该值中描述的字符串(比如你的后门程序backdoor.exe),并且从阶段1重新开始。这里的阶段1 就是上面我们看到的:CreateProcess会重新打开要执行的映像,这很重要,后面我们会看到。
书中Russinovich还提到,“如果你偶尔想搞个恶作剧,就可以使用这个行为来迷惑人们,当它们要运行指定的文件时却运行了另外的文件”。如果你不是想搞恶作剧,而是想程序关联,那这个位置也是后门木马理想的温床。我们先看一下这个注册表项,如图1所示,可以看到这个注册表项存在很多项目,这么多项难免可以让我们浑水摸鱼,替换我们需要的程序。大家可能都用过Russinovich的进程查看程序Process Explorer(),程序中有一个菜单项为“Replace Task Manager”,也就是替换Windows系统自带进程查看程序Task Manager(taskmgr.exe)。这是怎么做到的呢?其中一个偷梁换柱的技巧就是修改这个注册表项,也就是Russinovich所说的“恶作剧”程序,如图2所示。
图1
图2
注意看图2中的Debugger表项,它的值已被替换成Process Explorer的可执行程序PROCEXP.EXE了。现在大家心里都很清楚了,我们的文件关联只需在Image File Execution Options注册表项下面加入需要替换的文件名,这里我们就加入notepad.exe,然后为其增加一个REG_SZ类型的Debugger值,在其中添加木马程序的路径,如“c:\trojan.exe”,就万事大吉了。下面我们就编写一个测试程序看一下实现效果,代码如下。
view plainprint?
#include
#include
#include
//#define Debug
int _tmain( int argc, LPTSTR argv[] )
{
LPTSTRszCmdLine[200] = {0};
// Prepare for CreateProcess Parameters
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// place your trojan code here... :)
MessageBox(NULL,_T("You are hacked!"),_T("Warning"),0);
// trojan code end
_tcscat(szCmdLine, argv[1]);
_tcscat(szCmdLine, _T(" "));
_tcscat(szCmdLine, argv[2]);
#ifdef Debug
_tprintf(_T("%s\n"), szCmdLine);
getch();
#endif
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
szCmdLine, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
//CREATE_NO_WINDOWS,// No Windows !!!
//CREATE_NEW_PROCESS_GROUP,
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si,// Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
_tprintf( _T("CreateProcess failed (%d)\n", GetLastError()) );
return 2;
}
#ifdef Debug
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
#endif
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return 0;
}
//end
程序很简单,首先运行我们的后门程序,这里运行了一个对话框,代码为“MessageBox(NULL,_T("You are hacked!"),_T("Warning"),0);”;接下来,运行完成以后,我们还要把程序默认的步骤完成。比如程序通过这样的方式 “notepad.exe foo.txt”来打开一个名为foo.txt的文本文件。所以我们要得到这个参数,并且正常执行它,这样我们的程序才能神不知鬼不觉的执行,达到潜行的目的。
我们得到关联参数的程序如下:
_tcscat(szCmdLine, argv[1]);
_tcscat(szCmdLine, _T(" "));
_tcscat(szCmdLine, argv[2]);
大家可能会问,argv[1]和argv[2]是什么呢?argv[1]是系统默认关联的打开程序,这里就是notepad.exe;而 argv[2]就是将要打开的文本文件名,如foo.txt。因为程序是简单的测试,所以没有对输入参数个数进行检测。如果测试程序没有进行关联操作单独运行,就会发生崩溃(可能没有输入参数),这里大家要注意。
好了,得到参数以后,开始调用CreateProcess执行,程序完成。我们测试一下,结果如图3所示。
图3
出现了预期的对话框,点击“确定”以后,又出现了这个对话框,继续点还出现。这里就是本文开始处提醒大家很重要的地方。 CreateProcess在阶段1运行了关联程序后,它会重新回到阶段1,也就是打开要执行的映像,这样就会循环往复地执行我们的对话框,而没有执行后面的程序。于是我尝试不使用CreateProcess而是采用如WinExec或ShellExecute的方式来调用,情况依旧。接着尝试放弃类似 _tcscat(szCmdLine, argv[1])的参数选取方式,采用硬编码,也就是直接调用“c:\windows\notepad.exe”的方式,还是失败。后来,尝试在 CreateProcess调用之前,先把我们关联的Debugger键值清空,运行完CreateProcess把参数正确传递并运行后,再把 Debugger键值进行关联。事实证明,该方法可行。具体编码就是进行两次注册表的读写,详见随文提供的代码。
本文中的测试程序没有很好的解决文本文件路径存在空格的问题。具体来说,如果你的文本文件在桌面,如“c:\Documents and Settings\user\桌面\foo.txt”。在程序中会把该参数截断为“c:\Documents”,这个问题就留给大家一起来研究吧。
总的来说,这种文件关联方式容易被人忽略,而且在实施过程中可能存在一些不确定的因素。但作为一种隐蔽的文件关联方式,应该被杀毒软件列入查杀范围。本文只是作为纯技术交流之用,任何利用此技术用于非法用途的行为均与本文无关。
阅读(830) | 评论(0) | 转发(0) |