新增节-添加代码

思路过程

1、要判断空间是否足够

要判断节目录下面是否有足够的空间添加一个节目录项,一个节目录项需要40个字节的空间,而且整个节目录必须以40个存储 0的字节结尾,也就是所加一个节目录项只是需要 80个字节的空间。

img

2、复制一个相同属性的节,然后在复制过来的基础上进行修改必要的属性

img

3、修改数据

1、修改节的数量 _IMAGE_FILE_HEADER->NumberOfSections

2、修改PE文件内存拉伸后的大小,IMAGE_OPTIONAL_HEADER ->SizeOfImage 3、在文件尾添加空间,按照文件对齐来添加 4、修改节的属性 _IMAGE_SECTION_HEADER->Characteristics 5、修改节的名字 _IMAGE_SECTION_HEADER->Name 6、修改节在内存中的大小IMAGE_SECTION_HEADER->Misc.VirtualSize, 这个尺寸可以直接修改为 SizeOfRawData 7、修改在内存中偏移的地址VirtualAddress ,是上一个节的VirtualAddress值加上Misc.VirtualSize,然后按文件对齐后的尺寸

3503C+1D4000=20 903C‬(按对齐后的大小)=20A000

img

8.修改在文件中对齐的大小SizeOfRawData,这个值和内存中对齐前的一样 9.修改在文件中的偏移PointerToRawData,实际就是上一个节的在文件中的偏移PointerToRawData+在文件中对齐后的尺寸SizeOfRawData 10.修改最后一个节 Characteristics ,节的属性,60000020 表示代码节属性

当空间不足时

1、有些程序会在节表到节的空白区之间添加一些信息,导致节表下面没有空间

程序的DOS头到PE签名之间有一处区域DOS Stub,不影响程序的运行,数据也是程序的一些说明信息,对我们来说就是垃圾数据,所以我们可以将PE到节表末尾这一部分整体上移,把Dos Stub这块数据覆盖了,接着修改DOS头中的e_lfanew字段的值为上移后PE签名的地址即可,那么此时下面就会空出来一部分,我们就可以先将这部分全部修改成0x00,再往这片区域新增节表即可

2、如果第一条的空间也不足, 就扩大最后一个节的尺寸,扩大最后一个节不影响其它节。 扩大节的步骤: (Ex 新增节的大小)

代码方式实现添加节

添加节并实现插入shellcode

VOID TestAddSecInCode()
{
    PVOID pFileBuffer = NULL;
    PVOID pImageBuffer = NULL;
    PVOID pNewBuffer = NULL;
    PVOID pNewImageBuffer = NULL;
​
    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_FILE_HEADER pPEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeaderUP = NULL;
    PBYTE codeBegin = NULL;
    BOOL isOk = FALSE;
    DWORD size = 0;
    /*File->fileBuffer*/
    ReadPEFile(file_path, &pFileBuffer);
    if (!pFileBuffer)
    {
        printf("文件->缓冲区失败");
        return;
    }
    /*FileBuffer->ImageBuffer*/
    CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer);
    if (!pImageBuffer)
    {
        printf(" 复制文件到缓冲区失败");
        free(pFileBuffer);
        return;
    }
    pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
​
    pNewImageBuffer = malloc(pOptionHeader->SizeOfImage + 0x1000);
    if (pNewImageBuffer == NULL)
    {
        printf("NewImage分配失败");
        free(pNewImageBuffer);
        return;
    } 
    memset(pNewImageBuffer, 0, pOptionHeader->SizeOfImage + 0x1000);//空间初始化
    printf("pNewImageBuffer的起始位置:%p\n", (char*)pNewImageBuffer);
    memcpy(pNewImageBuffer, pImageBuffer, pOptionHeader->SizeOfImage);
    
    //pNewImageBuffer重新定义头部信息
    PIMAGE_DOS_HEADER pDosHeader_2 = (PIMAGE_DOS_HEADER)pNewImageBuffer;
    PIMAGE_FILE_HEADER pPEHeader_2 = (PIMAGE_FILE_HEADER)((DWORD)((DWORD)pNewImageBuffer + pDosHeader->e_lfanew) + 4);
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader_2 = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pNewImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
    PIMAGE_SECTION_HEADER pSectionHeader_2 = (PIMAGE_SECTION_HEADER)(((DWORD)pNewImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
    PIMAGE_SECTION_HEADER pSectionHeader_2_1 = pSectionHeader_2;
​
    // 判断有没有80个字节的空间添加节目录信息
    // 用SizeOfHeader头大小,减去DOS头到最后一个节目录的值 就可以判断空间是否足够
    // 计算DOS头到最后一个节目录大小
    //计算最后一个节目录位置
    pSectionHeader_2_1 = pSectionHeader_2 + (pPEHeader_2->NumberOfSections);
    DWORD addOfSecSize = pOptionHeader_2->SizeOfHeaders - ((DWORD)pSectionHeader_2 + 40 - (DWORD)pNewImageBuffer);
    printf("节的空闲大小:%i\n", addOfSecSize);
    if (addOfSecSize < 80)
    {
        printf("剩余空间不足");
        return;
    }
    //复制节到新的节表
    codeBegin =(PBYTE)pSectionHeader_2_1;
    memcpy(codeBegin, pSectionHeader_2, 40);
    //修改属性
    pPEHeader_2->NumberOfSections += 1;//修改节的数量
    pOptionHeader_2->SizeOfImage += 0x1000;//修改sizeofimage的大小
    pSectionHeader_2 += pPEHeader_2->NumberOfSections - 1;//指向新加节表的位置
​
    //修改节表属性
    sprintf((char*)pSectionHeader_2->Name, "%s", ".tttt");
    pSectionHeader_2->Misc.VirtualSize = 0x1000; //修改这个节在内存中大小,没有对齐的大小,这里写与添加的空间一样大
    pSectionHeaderUP = pSectionHeader_2 - 1;
    //修改在内存中RVA偏移地址,是上一个节的VirtualAddress值加上Misc.VirtualSize,然后按文件对齐后的尺寸
    pSectionHeader_2->VirtualAddress = (pSectionHeaderUP->VirtualAddress + pSectionHeaderUP->Misc.VirtualSize+pOptionHeader_2->SectionAlignment)/pOptionHeader_2->SectionAlignment*pOptionHeader_2->SectionAlignment;
    pSectionHeader_2->SizeOfRawData = 0x1000;//修改在文件对齐后的大小
    pSectionHeader_2->PointerToRawData = pSectionHeaderUP->PointerToRawData + pSectionHeaderUP->SizeOfRawData;
    //添加代码  
    //将代码复制到空闲区
    codeBegin = (PBYTE)((DWORD)pNewImageBuffer + pSectionHeader_2->VirtualAddress);
    memcpy(codeBegin, shellcode, SHELLCODELENGTH);
    //修正E8
    DWORD callAddr = (MESSAGEBOXADDR - (pOptionHeader_2->ImageBase + ((DWORD)(codeBegin + 0xD) - (DWORD)pNewImageBuffer)));
    *(PDWORD)(codeBegin + 9) = callAddr;
    //修正E9
    DWORD jmpAddr = ((pOptionHeader_2->AddressOfEntryPoint + pOptionHeader_2->ImageBase) - (pOptionHeader_2->ImageBase + ((DWORD)(codeBegin + SHELLCODELENGTH) - (DWORD)pNewImageBuffer)));
    *(PDWORD)(codeBegin + 0xE) = jmpAddr;
    //修改OEP
    pOptionHeader_2->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)pNewImageBuffer;
    //ImageBuffer->NewBuffer
    size = CopyImageBufferToNewFileBuffer(pNewImageBuffer, &pNewBuffer);
    printf("ImageBufferToNewFileBuffer");
    if (size == 0 || !pNewBuffer)
    {
        printf("存盘失败");
        free(pFileBuffer);
        free(pImageBuffer);
        free(pNewBuffer);
        return;
    }
    printf("ImageBufferToNewFileBuffer");
    isOk = MemoryToFile(pNewBuffer, size, write_file_path);
    printf("MemoryToFile");
    if (isOk)
    {
        printf("存盘成功");
        return;
    }
    free(pFileBuffer);
    free(pImageBuffer);
    free(pNewBuffer);
    return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值