PE加节代码

2009-10-13 Nie.Meining Coding

工作需要,写了个加节代码。网上有个汇编的,考虑不太周全。
感谢看雪宝图,感谢小伟同学。上代码:

////////////////////////////////////////////////////////

//        PE 加节的函数

//        strFilePath为要改动的文件路径

//        strSecFilePath为节文件,节文件里面是新加节的内容。

//        省略了一些错误处理过程,比如fread失败等

//

//        by Fypher

//        http://hi.baidu.com/nmn714

//

bool addSection(char* strFilePath, char* strSecFilePath)

{

    //打开要改动的文件

    FILE *fFile = fopen(strFilePath,"rb+");

    if(!fFile)

    {

        return false;

    }

    //打开节文件

    FILE *fSec = fopen(strSecFilePath,"rb");

    if(!fSec)

    {

        fclose(fFile);

        return false;

    }

    //读取PE文件头:

    DWORD dwPE_Header_OffSet;

    fseek(fFile,0x3C,SEEK_SET);

    fread(&dwPE_Header_OffSet,1,4,fFile);

 

    IMAGE_NT_HEADERS PE_Header;

    DWORD Head_Len = sizeof(IMAGE_NT_HEADERS);

    fseek(fFile,dwPE_Header_OffSet,SEEK_SET);

    fread(&PE_Header,1,Head_Len,fFile);

    //判断是否有效的PE文件

    if(PE_Header.Signature != IMAGE_NT_SIGNATURE)

    {

        fclose(fFile);

        fclose(fSec);

        return false;

    }

    //计算新节的偏移地址:

    DWORD dwMySectionOffSet = dwPE_Header_OffSet;

    dwMySectionOffSet += 0x4;        //sizeof("PE\0\0")

    dwMySectionOffSet += sizeof(IMAGE_FILE_HEADER);

    dwMySectionOffSet += sizeof(IMAGE_OPTIONAL_HEADER32);

    dwMySectionOffSet += PE_Header.FileHeader.NumberOfSections * 0x28;   //NumberOfSections * sizeof(IMAGE_SECTION_HEADER)

    //检查PE头的空间够不够大

    if(dwMySectionOffSet + 0x28 > PE_Header.OptionalHeader.SizeOfHeaders)

    {

        //空间不够,这里的处理方法是直接返回false

        fclose(fFile);

        fclose(fSec);

        return false;

    }

    //读取新节位置处的内容,本该是全0

    BYTE oldBuff[0x28];

    fseek(fFile,dwMySectionOffSet,SEEK_SET);

    fread(oldBuff,1,0x28,fFile);

    for(int i=0;i!=0x28;++i)

    {

        if(oldBuff[i])

        {

            //竟然不是0?说明这个空间已经被那什么延迟加载占用了

            //只有抹掉image_directory_entry_bound_im,腾出空间。

            //此处严重感谢小伟同学

            BYTE zeroBuff[8] = {0};

            fseek(fFile,dwPE_Header_OffSet + 0xD0,SEEK_SET);

            fwrite(zeroBuff,1,8,fFile);

            break;

        }

    }

 

    //从节文件中获取新节的长度

    fseek(fSec,0,SEEK_END);

    DWORD secLength = ftell(fSec);

    //填充新节的信息

    IMAGE_SECTION_HEADER mySec = {0};

    //新节的名字,暂时叫.ns

    mySec.Name[0]='.';

    mySec.Name[1]='n';

    mySec.Name[2]='s';

    mySec.Misc.VirtualSize = secLength;

 

    //新节的RVA

    mySec.VirtualAddress = PE_Header.OptionalHeader.SizeOfImage;

    //SizeOfRawDataEXE文件中是对齐到FileAlignMent的整数倍的值

    mySec.SizeOfRawData = secLength;

    mySec.SizeOfRawData /= PE_Header.OptionalHeader.FileAlignment;

    mySec.SizeOfRawData++;

    mySec.SizeOfRawData *= PE_Header.OptionalHeader.FileAlignment;

 

    //从节文件中读新节的内容

    fseek(fSec,0,SEEK_SET);  

    BYTE* secBuff = (BYTE*)malloc(mySec.SizeOfRawData);

    memset(secBuff,0,mySec.SizeOfRawData);

    fread(secBuff,1,secLength,fSec);

    //读最后一节的SizeOfRawData以及PointerToRawData

    //用来计算新节的PointerToRawData,即文件结束位置

    DWORD dwLastSection_SizeOfRawData,dwLastSection_PointerToRawData;

    fseek(fFile,dwMySectionOffSet - 0x18,SEEK_SET);   

    fread(&dwLastSection_SizeOfRawData,1,4,fFile);

    fread(&dwLastSection_PointerToRawData,1,4,fFile);

 

    //文件结束位置

    DWORD endPosition = dwLastSection_SizeOfRawData + dwLastSection_PointerToRawData;

 

    //按理说,文件应该在这个地方结束,但是也有可能有人硬加了垃圾在末尾,

    //比如或劣质的捆绑技术。因此得把差值算出来

    fseek(fFile,0,SEEK_END);

    DWORD fileLength = ftell(fFile);

    DWORD deltaLength = fileLength - endPosition;    //deltaLength就是垃圾长度。

 

    //设置新节的 PointerToRawData

    mySec.PointerToRawData = endPosition + deltaLength;

 

    //设置新节的属性

    mySec.Characteristics = 0x0E0000020;        //可读可写可执行

    //写入新节的信息

    fseek(fFile,dwMySectionOffSet,SEEK_SET);

    fwrite(&mySec,1,sizeof(IMAGE_SECTION_HEADER),fFile);

    //增加NumberOfSections

    WORD sections = PE_Header.FileHeader.NumberOfSections + 1;

    fseek(fFile,dwPE_Header_OffSet + 0x06,SEEK_SET);

    fwrite(&sections,1,2,fFile);

    //增加SizeOfImage

    DWORD sizeOfImage = PE_Header.OptionalHeader.SizeOfImage;

    sizeOfImage +=

        (mySec.Misc.VirtualSize/PE_Header.OptionalHeader.SectionAlignment + 1)

        * PE_Header.OptionalHeader.SectionAlignment;

    fseek(fFile, dwPE_Header_OffSet + 0x50, SEEK_SET);

    fwrite(&sizeOfImage, 1, 4, fFile);

    //在文件的最后写入我们的新节具体内容

    fseek(fFile,0,SEEK_END);

    fwrite(secBuff,1,mySec.SizeOfRawData,fFile);

 

    //结束

    free(secBuff);

    fclose(fFile);

    fclose(fSec);

    return true;

}

 

不用CreateFile、ReadFile等函数是故意的,为了不调用API。因为工作平台是Linux。

评论:

KennethCaT
2017-09-11 14:54
wh0cd4544929
KennethCaT
2017-09-04 15:04
wh0cd871215

发表评论:

Powered by emlog