病毒常用技术之远程线程 插入技术 转帖 推荐人:WD 今天真是一个令人倒霉的天气的 今天早上早早的爬起来,本想趁着今天的好天气好心情,写上一篇好的技术文章不想该死的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
// VirtualFreeEx( hProcess, lpParBuf, ParamSize, MEM_DECOMMIT ); CloseHandle( hThread ); CloseHandle(hProcess); return TRUE; }。