PE中增加节,并插入自己代码

PE文件的基础知识大家可以自行百度。

1、在PE中末尾添加一个节

在PE末尾中添加一个节,需要注意:
(1)RVA和FOA的转换
(2)需要修改SizeofImage的大小
(3)需要修改PE头中节的数量
(4)如果现有的节表后面添加的空间不足,可以移动NT头和节表
(5)新增加节表的属性根据自己的需要修改
(6)新增节的RVA 需要注意计算,需要计算上一个节RVA对齐后的尺寸
计算公式如下:

 //计算内存中对齐的大小
    DWORD VirtulaSize = NULL;
    if (section_header->SizeOfRawData < section_header->Misc.VirtualSize) {
        VirtulaSize = ((section_header->Misc.VirtualSize /0x1000)+1) * 0x1000;
    }
    else
    {
        VirtulaSize = (section_header->SizeOfRawData/0x1000+1)*0x1000;
    }
    pAddsection->VirtualAddress = section_header->VirtualAddress + VirtulaSize;

在这里插入图片描述

2、添加节区的代码如下

BOOL AddSection(char* FileBuffer, LPCSTR NewFileName) {
    PIMAGE_DOS_HEADER dos = NULL;
    PIMAGE_NT_HEADERS nt = NULL;
    PIMAGE_FILE_HEADER file_header = NULL;
    PIMAGE_SECTION_HEADER section_header = NULL;
    PIMAGE_OPTIONAL_HEADER option_header = NULL;
    dos = (PIMAGE_DOS_HEADER)FileBuffer;
    nt = (PIMAGE_NT_HEADERS)(FileBuffer + dos->e_lfanew);
    file_header = (PIMAGE_FILE_HEADER)(&(nt->FileHeader));
    option_header = (PIMAGE_OPTIONAL_HEADER)(&(nt->OptionalHeader));
    section_header = PIMAGE_SECTION_HEADER((char*)option_header + file_header->SizeOfOptionalHeader);
    //添加大小为0x1000的节
    option_header->SizeOfImage = option_header->SizeOfImage + 0x1000; 
    
    //1、计算后续空间能不能增加节表
    DWORD dwNumofSection = file_header->NumberOfSections;
    DWORD dwLfanew = dos->e_lfanew;
    DWORD dwSizeofHeader = option_header->SizeOfHeaders;
    printf("%d,%d,", sizeof(*nt), sizeof(*section_header));
    DWORD dwSizeNowHeader = dwLfanew + sizeof(*nt) + dwNumofSection * sizeof(*section_header);
    //1.1  后续空间无法添加节表,移动头部信息
    if (dwSizeofHeader - dwSizeNowHeader < 2 * sizeof(section_header)) {
        memcpy(FileBuffer + 0x40, FileBuffer + dos->e_lfanew, sizeof(*nt) + dwNumofSection * sizeof(*section_header));
       
        dos->e_lfanew = 0x40;
        nt = (PIMAGE_NT_HEADERS)(FileBuffer + dos->e_lfanew);
        file_header = (PIMAGE_FILE_HEADER)(&(nt->FileHeader));
        option_header = (PIMAGE_OPTIONAL_HEADER)(&(nt->OptionalHeader));
        section_header = PIMAGE_SECTION_HEADER((char*)option_header + file_header->SizeOfOptionalHeader);
        DWORD dwNumofSection = file_header->NumberOfSections;
        DWORD dwLfanew = dos->e_lfanew;
        DWORD dwSizeofHeader = option_header->SizeOfHeaders;
        printf("%d,%d,", sizeof(*nt), sizeof(*section_header));
        DWORD dwSizeNowHeader = dwLfanew + sizeof(*nt) + dwNumofSection * sizeof(*section_header);
       
    }
    //1.2添加两个节表
    //(1)移动到最后一个节表处
    for (int i = 0; i < dwNumofSection-1; i++) {
        section_header = section_header + 1;
    }
    //(2)添加节表
    DWORD dwAddSectionAddress = dwSizeNowHeader;
    PIMAGE_SECTION_HEADER pAddsection = (PIMAGE_SECTION_HEADER)malloc(sizeof(IMAGE_SECTION_HEADER));
    if (pAddsection == NULL) {
        return FALSE;
    }
    memset(pAddsection, 0, sizeof(*pAddsection));
    char newName[] = ".newSec";
    memcpy(pAddsection, newName, 8);

    //计算内存中对齐的大小
    DWORD VirtulaSize = NULL;
    if (section_header->SizeOfRawData < section_header->Misc.VirtualSize) {
        VirtulaSize = ((section_header->Misc.VirtualSize /0x1000)+1) * 0x1000;
    }
    else
    {
        VirtulaSize = (section_header->SizeOfRawData/0x1000+1)*0x1000;
    }
    //添加节表信息
    pAddsection->VirtualAddress = section_header->VirtualAddress + VirtulaSize;
    pAddsection->Misc.VirtualSize = 0x600;
    pAddsection->SizeOfRawData = 0x1000;
    pAddsection->PointerToRawData = section_header->PointerToRawData + section_header->SizeOfRawData;
    pAddsection->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
    //写入到fileBuffer中
    memcpy(FileBuffer + dwAddSectionAddress, pAddsection, 40);
    char secode_section[40] = { 0 };
    memcpy(FileBuffer + dwAddSectionAddress + 40, secode_section, 40);
    // 将节的数量加1
    file_header->NumberOfSections = file_header->NumberOfSections + 1;

    //申请新的空间
    DWORD* AddSectionSpace = (DWORD*)malloc(_msize(FileBuffer) +0x1000);
    if (AddSectionSpace == NULL) {
        return FALSE;
    }
    memset(AddSectionSpace, 0, _msize(AddSectionSpace));
    memcpy(AddSectionSpace, FileBuffer, _msize(FileBuffer));
    AddCode((char*)AddSectionSpace, NewFileName, file_header->NumberOfSections);
    return TRUE;
}

3、修改入口点

在增加节之后,可以往增加的节中添加自己的代码,并将程序入口点修改到自己的代码处。其中需要注意点如下:
(1)需要关闭PE的地址随机化功能,可以通过修改OptionHeader头中的DllCharacteristics = 0x8100,来绕过地址随机化。
(2)计算E8和E9的时候,CALL 偏移:跳转地址 = 当前地址+5+x ->x = 跳转地址 -当前地址-5。求出x就是E8(CALL指令的硬编码)后的跳转偏移。
(3)需要进行RVA和FOA的转换,所有的地址都是加载到内存后的地址。
代码如下:其中AddNumSction是需要将代码插入到哪个节中

BOOL AddCode(char* FileBuffer, LPCSTR NewFileName,INT AddNumSction) {
    PIMAGE_DOS_HEADER dos = NULL;
    PIMAGE_NT_HEADERS nt = NULL;
    PIMAGE_FILE_HEADER file_header = NULL;
    PIMAGE_SECTION_HEADER section_header = NULL;
    PIMAGE_OPTIONAL_HEADER option_header = NULL;
    DWORD dwSizeofOptionHeader = NULL;
    DWORD dwVirtualAddress = NULL;
    DWORD dwPointerRawData = NULL;
    DWORD dwEntryCode = NULL;
    DWORD dwImageBase = NULL;
    DWORD dwUnInitDataSize = NULL;
    DWORD dwNumofSection = NULL;
    DWORD dwCodeWirteAddress = NULL;
    dos = (PIMAGE_DOS_HEADER)FileBuffer;
    nt = (PIMAGE_NT_HEADERS)(FileBuffer + dos->e_lfanew);
    file_header = (PIMAGE_FILE_HEADER)(&(nt->FileHeader));
    option_header = (PIMAGE_OPTIONAL_HEADER)(&(nt->OptionalHeader));
    dwSizeofOptionHeader = file_header->SizeOfOptionalHeader;
    section_header = (PIMAGE_SECTION_HEADER)((char*)option_header + dwSizeofOptionHeader);
    
    dwNumofSection = file_header->NumberOfSections;
    
    dwImageBase = option_header->ImageBase;
    dwEntryCode = option_header->AddressOfEntryPoint + dwImageBase;
    DWORD Charac = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
  /*  for (int i = 0; i < dwNumofSection; i++) {
        if (section_header->SizeOfRawData > 0 && (section_header->Characteristics & Charac)) {
            break;
        
        }
        section_header = (PIMAGE_SECTION_HEADER)((char*)section_header + 40);
    }*/
    for (int i = 0; i < AddNumSction-1; i++) {
        section_header = (PIMAGE_SECTION_HEADER)((char*)section_header + 40);
    }
    dwUnInitDataSize = section_header->Misc.VirtualSize;
    dwPointerRawData = section_header->PointerToRawData;
    dwVirtualAddress = section_header->VirtualAddress;
    dwCodeWirteAddress = dwUnInitDataSize + dwPointerRawData;
    HMODULE user32 = LoadLibraryA("user32.dll");
    if (user32 == NULL) {
        return FALSE;
    }
    DWORD MessageboxAAddress = (DWORD)GetProcAddress(user32, "MessageBoxA");
    //printf("%llx ", MessageboxAAddress);
  
    char message[] = "你是一个傻逼";
    //MessageBoxA(0, message, 0, 0);
    //MessageBoxA(0, message, 0, 0);
    char buffer[22] = {0x6A,0x00,     //push 0 
                       0x6A,0x00,     //push 0 
                       0xB8,0x00,0x00,0x00,0x00,  //mov eax,[message]
                       0x50,                      //push eax
                       0x6A,0x00,                 //push 0
                       0xE8,0x00,0x00,0x00,0x00,
                       0xE9,0x00,0x00,0x00,0x00};
    //printf("%d",sizeof(message));
    //去掉地址随机化
    option_header->DllCharacteristics = 0x8100;
    
    //将代码写入到FileBuffer中
    memcpy(FileBuffer + dwCodeWirteAddress, buffer, sizeof(buffer));
    //将要写入的输出字符写到fileBuffer中
    memcpy(FileBuffer + dwCodeWirteAddress + sizeof(buffer), message, sizeof(message));
    //计算CALL 偏移:跳转地址 = 当前地址+5+x   ->x = 跳转地址 -当前地址-5
    DWORD ChangeCodeAddress = dwCodeWirteAddress + 13;
    DWORD dwCallShift = MessageboxAAddress - (dwImageBase + dwVirtualAddress + dwUnInitDataSize +12+5);
    //改变E8后面的跳转偏移
    *(DWORD*)((char*)FileBuffer + ChangeCodeAddress) = dwCallShift;
   
    //改变第三个参数
    DWORD dwTextAddress = dwUnInitDataSize + sizeof(buffer) + dwImageBase + dwVirtualAddress;
    /*DWORD TextShift = (dwImageBase + dwVirtualAddress + dwCodeWirteAddress + sizeof(buffer) - (dwImageBase +dwVirtualAddress+dwCodeWirteAddress+13));*/
    *(DWORD*)((char*)FileBuffer + dwCodeWirteAddress + 5) = dwTextAddress;
    
    //Jmp到原入口地址
    DWORD EntryCodeShift = dwEntryCode - (dwImageBase + dwVirtualAddress + dwUnInitDataSize + sizeof(buffer));
    *(DWORD*)((char*)FileBuffer + dwCodeWirteAddress + 18) = EntryCodeShift;
    //修改入口地址
    
    *(&(option_header->AddressOfEntryPoint)) = dwVirtualAddress+ dwUnInitDataSize;
    FILE* fpp = NULL;
    fopen_s(&fpp,NewFileName,"wb+");
    //printf("%x",_msize(FileBuffer));
    if (fpp == NULL) {
        return FALSE;
    }
    fwrite(FileBuffer, sizeof(char), _msize(FileBuffer)/sizeof(char), fpp);
    fflush(fpp);
    fclose(fpp);
    return TRUE;
}

4、结果

修改前:只有9个段,并且EP为112C1
在这里插入图片描述
修改后:增加了一个区段,并且入口地址修改成了自己的地址
在这里插入图片描述

并且增加了可读可执行的属性
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值