9X 环境中Windows提供了想光的API函数用于隐藏系统进程。但是到了 2000 以上系统,已经无法真正的做到对于进程的隐藏,除非编写底层驱动。但是我们可以通过一些变通的办法来达到隐藏进程的目的,其中一个就是远程注入。简单的说就是先编写一个 API的DLL,然后将这个DLL库注入到一个系统进程中,作为它的一个线程去执行。
要实现DLL注入,首先需要打开目标进程。
hRemoteProcess  =  OpenProcess ( PROCESS_CREATE_THREAD  |  //允许远程创建线程
    PROCESS_VM_OPERATION  |  //允许远程VM操作
    PROCESS_VM_WRITE ,   //允许远程VM写
    FALSE ,  dwRemoteProcessId  )
由于我们后面需要写入远程进程的内存地址空间并建立远程线程,所以需要申请足够的权限(PROCESS_CREATE_THREAD、VM_OPERATION、VM_WRITE)。
如果进程打不开,以后的操作就别想了。进程打开后,就可以建立远线程了,不过别急,先想想这个远线程的线程函数是什么?我们的目的是注入一个DLL。而且我们知道用LoadLibrary可以加载一个DLL到本进程的地址空间。于是,自然会想到如果可以在目标进程中调用LoadLibrary,不就可以把 DLL加载到目标进程的地址空间了吗?对!就是这样。远线程就在这儿用了一次,建立的远线程的线程函数就是LoadLibrary,而参数就是要注入的 DLL的文件名。 ( 这里需要自己想一想,注意到了吗,线程函数ThreadProc和LoadLibrary函数非常相似,返回值,参数个数都一样 )  还有一个问题,LoadLibrary这个函数的地址在哪儿?也许你会说,这个简单,GetProcAddress就可以得出。于是代码就出来了。
char  * pszLibFileRemote = "my.dll" ;
PTHREAD_START_ROUTINE pfnStartAddr  = ( PTHREAD_START_ROUTINE ) GetProcAddress ( GetModuleHandle ( "Kernel32" ),  "LoadLibraryA" );
CreateRemoteThread (  hRemoteProcess ,  NULL ,  0 ,  pfnStartAddr ,  pszLibFileRemote ,  0 ,  NULL );
     但是不对!不要忘了,这是远线程,不是在你的进程里,而pszLibFileRemote指向的是你的进程里的数据,到了目标进程,这个指针都不知道指向哪儿去了,同样pfnStartAddr这个地址上的代码到了目标进程里也不知道是什么了,不知道是不是你想要的LoadLibraryA了。但是,问题总是可以解决的,Windows有些很强大的API函数,他们可以在目标进程里分配内存,可以将你的进程中的数据拷贝到目标进程中。因此 pszLibFileRemote的问题可以解决了。
char  * pszLibFileName = "my.dll" ; //注意,这个一定要是全路径文件名,除非它在系统目录里;原因大家自己想想。
//计算DLL路径名需要的内存空间
int  cb  = ( 1  +  lstrlenA ( pszLibFileName )) *  sizeof ( char );
//使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲区
pszLibFileRemote  = ( char  *)  VirtualAllocEx (  hRemoteProcess ,  NULL ,  cb ,  MEM_COMMIT ,  PAGE_READWRITE );
//使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间
iReturnCode  =  WriteProcessMemory ( hRemoteProcess ,  pszLibFileRemote , ( PVOID )  pszLibFileName ,  cb ,  NULL );
     OK,现在目标进程也认识pszLibFileRemote了,但是pfnStartAddr好像不好办,我怎么可能知道LoadLibraryA在目标进程中的地址呢?其实Windows为我们解决了这个问题,LoadLibraryA这个函数是在Kernel32 . dll这个核心DLL里的,而这个 DLL很特殊,不管对于哪个进程,Windows总是把它加载到相同的地址上去。因此你的进程中LoadLibraryA的地址和目标进程中 LoadLibraryA的地址是相同的 ( 其实,这个DLL里的所有函数都是如此 ) 。至此,DLL注入结束了。
 
但是目前还有一个问题,上面的方法是无法将DLL注入到系统进程中去的,原因是进程级别不够。那么我们就要提升注入程序的进程级别。使用下面的函数:
void  EnableDebugPriv (  void  )
{
  HANDLE hToken ;
  LUID sedebugnameValue ;
  TOKEN_PRIVILEGES tkp ;
  if  ( !  OpenProcessToken (  GetCurrentProcess (),
   TOKEN_ADJUST_PRIVILEGES  |  TOKEN_QUERY , & hToken  ) )
   return ;
  if  ( !  LookupPrivilegeValue (  NULL ,  SE_DEBUG_NAME , & sedebugnameValue  ) ){
   CloseHandle (  hToken  );
   return ;
 }
  tkp . PrivilegeCount  =  1 ;
  tkp . Privileges [ 0 ]. Luid  =  sedebugnameValue ;
  tkp . Privileges [ 0 ]. Attributes  =  SE_PRIVILEGE_ENABLED ;
  if  ( !  AdjustTokenPrivileges (  hToken ,  FALSE , & tkp ,  sizeof  tkp ,  NULL ,  NULL  ) )
   CloseHandle (  hToken  );
}
 
 
 
最后我们来做一个简单的例子:
首先编写注入程序的代码
// DLLAdd.cpp : Defines the entry point for the application.
//
#include  "stdafx.h"
#include  "winnt.h"
void  EnableDebugPriv ();
int  APIENTRY WinMain ( HINSTANCE hInstance ,
                      HINSTANCE hPrevInstance ,
                      LPSTR     lpCmdLine ,
                      int        nCmdShow )
{
  EnableDebugPriv ();
   // TODO: Place code here.
  HANDLE hRemoteProcess ;
  HANDLE hRemoteThread ;
  //PWSTR pszLibFileRemote;
 //LPCWSTR pszLibFileName;
  BOOL iReturnCode ;
  char  * pszLibFileRemote = "RemoteDLL.dll" ;
  char  * pszLibFileName = "C:\\RemoteDLL.dll" ; //注意,这个一定要是全路径文件名,除非它在系统目录里
  hRemoteProcess  =  OpenProcess ( PROCESS_CREATE_THREAD
         | PROCESS_VM_OPERATION
         | PROCESS_VM_WRITE ,
         FALSE , 0x3E0 ); //0x3E0是进程的id,测试时是explorer的进程id,可以用spy++去查找。
 //计算DLL路径名需要的内存空间
  int  cb  = ( 1  +  lstrlenA ( pszLibFileName )) *  sizeof ( char );
  //使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲区
  pszLibFileRemote  = ( char  *)  VirtualAllocEx ( hRemoteProcess ,  NULL ,  cb ,
             MEM_COMMIT ,  PAGE_READWRITE );
  //使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间
  iReturnCode  =  WriteProcessMemory ( hRemoteProcess ,
     pszLibFileRemote , ( PVOID )  pszLibFileName ,  cb ,  NULL );
  //计算LoadLibraryW的入口地址
  PTHREAD_START_ROUTINE pfnStartAddr  = ( PTHREAD_START_ROUTINE )
           GetProcAddress ( GetModuleHandle ( TEXT ( "Kernel32" )),
           "LoadLibraryA" );
  //启动远程线程LoadLibraryW,通过远程线程调用用户的DLL文件
  hRemoteThread  =  CreateRemoteThread (  hRemoteProcess ,  NULL ,  0 ,
           pfnStartAddr ,  pszLibFileRemote ,  0 ,  NULL );

  return  0 ;
}
 
//提升权限
void  EnableDebugPriv (  void  )
{
  HANDLE hToken ;
  LUID sedebugnameValue ;
  TOKEN_PRIVILEGES tkp ;
  if  ( !  OpenProcessToken (  GetCurrentProcess (),
   TOKEN_ADJUST_PRIVILEGES  |  TOKEN_QUERY , & hToken  ) )
   return ;
  if  ( !  LookupPrivilegeValue (  NULL ,  SE_DEBUG_NAME , & sedebugnameValue  ) ){
   CloseHandle (  hToken  );
   return ;
 }
  tkp . PrivilegeCount  =  1 ;
  tkp . Privileges [ 0 ]. Luid  =  sedebugnameValue ;
  tkp . Privileges [ 0 ]. Attributes  =  SE_PRIVILEGE_ENABLED ;
  if  ( !  AdjustTokenPrivileges (  hToken ,  FALSE , & tkp ,  sizeof  tkp ,  NULL ,  NULL  ) )
   CloseHandle (  hToken  );
}
 
 

然后编写需要注入的DLL的代码

#include  "stdafx.h"
#include  "winnt.h"
#include  < stdlib . h >
BOOL APIENTRY DllMain (  HANDLE hModule ,
                        DWORD  ul_reason_for_call ,
                        LPVOID lpReserved
       )
{
  char  szProcessId [ 64 ];
  int  i = 1 ;
  switch ( ul_reason_for_call )
 {
  case  DLL_PROCESS_ATTACH :
  {
    _itoa ( GetCurrentProcessId (), szProcessId , 10 );
    MessageBox ( NULL , szProcessId , "RemoteDLL" , MB_OK );
  }
  default :
   return  TRUE ;
 }
}
 
将编译好的dll放到C盘根目录下面运行注入程序。我们可以发现弹出了一个标示了被注入进程id的对话框。
如上,只要我们再dll中编写我们需要的代码,就可以隐秘的在电脑里执行我们需要的事情。