新增节-添加代码

  1. 准备工作:
  2. 手动实现:
  3. 代码实现:

准备工作:

1、判断是否有足够的空间可以添加一个节表.

判断条件:SizeOfHeader - (DOS + 垃圾数据 + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小

2、需要修改的数据

  1. 添加一个新的节(可以copy一份)
  2. 在新增节后面 填充一个节大小的000
  3. 修改PE头中节的数量
  4. 修改sizeOfImage的大小
  5. 再原有数据的最后,新增一个节的数据(内存对齐的整数倍).
  6. 修正新增节表的属性

手动实现:

复制一个exe程序(本文复制IPMSG.exe)用于实验,用010打开,找到节表信息,发现有4个节,且发现节表后面的空白区足够放下代码。为了使得添加完代码后的程序具有可执行的特征,选择复制第一个节点的所有信息(40个字节),复制到最后一个节点后面:

image-20230913215045606

假设在新的节中添加4096个字节。

修改节的数量:

image-20230913215449723

修改SizeOfImage(原始值为0022B000)为0022C000

image-20230913215849209

插入4096个字节的内容,在文件末尾:

image-20230919201450144

修改添加节点的成员信息:

Name:改为tttt

VirtualSize:直接改成在文件中对齐后的长度1000

VirtualAddress:等于SizeOfImage修改前的大小

SizeOfRawData:1000

PointerToRawData:用上一个节点的PointerToRawData+SizeOfRawData = 22 2200

Characteristics:无需修改

保持后打开文件,能够正常打开,说明添加节点成功。

代码实现:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#include <memory.h>

int GetFilesize(FILE* fptr);
char* ReadFilea(const char* Filepath);  

void addSection(char* Filepath) {
    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_NT_HEADERS pNTHeader = NULL;
    PIMAGE_FILE_HEADER pPEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    
    char* pFileBuffer = ReadFilea(Filepath);
    if(!pFileBuffer) {
        printf("读取文件失败");
        return;
    }
    
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    pNTHeader = (PIMAGE_NT_HEADERS)(pFileBuffer + (pDosHeader->e_lfanew));
    pPEHeader = (PIMAGE_FILE_HEADER)(pFileBuffer + (pDosHeader->e_lfanew) + 4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(pFileBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)(pFileBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
    
    DWORD restSpace = pOptionHeader->SizeOfHeaders - ((uintptr_t)pSectionHeader + pPEHeader->NumberOfSections - (uintptr_t)pFileBuffer);
    if(restSpace < 80) {
        printf("剩余空间不够");
        return;
    }
    
    PIMAGE_SECTION_HEADER new_pSectionHeader = pSectionHeader + pPEHeader->NumberOfSections;

    //修改添加节点的成员信息: 
    //Name:改为tttt
    strcpy((char*)new_pSectionHeader->Name,".tttt"); 
    //VirtualSize:直接改成在文件中对齐后的长度1000
    new_pSectionHeader->Misc.VirtualSize = 0x1000; 
    //VirtualAddress:等于SizeOfImage修改前的大小
    new_pSectionHeader->VirtualAddress = pOptionHeader->SizeOfImage;
    //SizeOfRawData:1000
    new_pSectionHeader->SizeOfRawData = 0x1000;
    //PointerToRawData:用上一个节点的PointerToRawData+SizeOfRawData = 22 2200
    new_pSectionHeader->PointerToRawData = (new_pSectionHeader-1)->PointerToRawData + (new_pSectionHeader-1)->SizeOfRawData;
    //Characteristics:无需修改
    new_pSectionHeader->Characteristics = pSectionHeader->Characteristics;
    
    //插入全0的节表
    LPVOID new_sectionBegin = LPVOID(new_pSectionHeader + 1);
    memset(new_sectionBegin,0,40);
    //修改节的数量
    pPEHeader->NumberOfSections += 1;
    //修改SizeOfImage(插入4096个字节)
    pOptionHeader->SizeOfImage += 0x1000;
    
    //写回文件
    FILE* nFp1;
    nFp1 = fopen("D:\\ipmsg\\IPMsg_2_3.exe", "rb"); 
    int size_file = GetFileszie(nFp1);
    fclose(nFp1);
    nFp1 = fopen("D:\\ipmsg\\IPMsgnew_2_3.exe", "wb"); 
    if(!nFp1) {
        printf("打开写出文件失败\n");
        free(pFileBuffer);
        return ;
    }
    //把修改完的写回去
    fwrite(pFileBuffer, size_file, 1, nFp1);
    //新节表填充 
    LPVOID new_Buffer = malloc(0x1000);
    if(!new_Buffer) {
        printf("给新结点申请空间失败");
        free(pFileBuffer);
        return;
    }
    memset(new_Buffer,0,0x1000);
    fwrite(new_Buffer,0x1000,1,nFp1);
    fclose(nFp1);
    free(new_Buffer); free(pFileBuffer);
    new_Buffer = NULL; pFileBuffer = NULL;
}

char* ReadFilea(const char *Filepath) {
    FILE* fptr = NULL;
    fptr = fopen(Filepath,"rb");
    if(!fptr) {
        printf("打开失败");
        return NULL;
    }
    int filesize = 0;
    filesize = GetFilesize(fptr);
    if (filesize == 0) {
        printf("获取文件大小失败");
        return NULL;
    }
    char* FileBuffer = (char*)malloc(filesize);
    if(!FileBuffer) {
        printf("开辟空间失败");
        return NULL;
    }
    size_t n=fread(FileBuffer,  1, filesize, fptr);//将文件内容读到内存中
    if(!n) {
        printf("读取数据失败");
        free(FileBuffer);
        FileBuffer = NULL;
        fclose(fptr);
        return NULL;
    }
    fclose(fptr);
    return FileBuffer;
}
    
int GetFilesize(FILE* fptr) {
    int num = 0;
    fseek(fptr, 0, SEEK_END);
    num = ftell(fptr);
    fseek(fptr, 0, SEEK_SET);
    return num;
}

int main() {
    char* path = (char*)"D:\\ipmsg\\IPMsg_2_3.exe";
    addSection(path);
    return 0;
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1666739907@qq.com
github