PE之移动导出表

本文介绍了移动PE文件的导出表的目的,包括保护程序、加密前的关键操作,并详细阐述了移动导出表的过程,涉及到RVA与FOA转换、地址修复等关键步骤,同时提供了代码示例展示整个操作流程。
摘要由CSDN通过智能技术生成

1、移动各种表的目的

(1)在程序启动时,系统会根据导入导出表等进行初始化工作。为了保护程序,一般会对exe程序的二进制进行加密等工作,但是一旦将这些表也进行了加密,那么系统在初始化的时候没办法找到这些表,也无法启动程序。
(2)在对程序加密之前,需要对一些关键的表进行移动后,再对原来的数据进行加密,这样才不能破坏原来的程序。
(3)学会移动各种表,是对程序加密/破解的基础。

2、如何移动导出表

上一篇文章,提到了如何对导出表进行解析,导出表的结构如图下。
在这里插入图片描述
导出表的位置是在可选PE头的第一项,如图,我们可以通过PE头找到其在所在地址,但是注意的是该地址是在内存(RVA)中的偏移,需要将其转为文件偏移(FOA)
在这里插入图片描述
移动过程
在这里插入图片描述
在这里插入图片描述
注意点:
(1)需要将原来的数据目录项指向新的位置,存的是RVA
(2)导出函数地址表,名称表和序号表都指向的是RVA
(3)导出名称表里存的名称也是RVA。以上都需要将存在文件中的位置转为RVA,然后修复以上地址

4、代码如下

第一部分将文件读到内存中


LPVOID ReadFileBuffer(LPCSTR siFilename) {
   
    int file_size = 0;
    FILE* fp = NULL;
    fopen_s(&fp,siFilename, "rb");
    if (fp == NULL) {
   
        printf("%d", GetLastError());
        return NULL;
    }
    fseek(fp, 0, SEEK_END);
    file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    LPVOID file_buffer_addr = (LPVOID)malloc(file_size);
    if (file_buffer_addr == NULL) {
   
        return NULL;
    }
    memset(file_buffer_addr, 0, file_size);
    if (file_buffer_addr != NULL) {
   
        fread(file_buffer_addr, sizeof(char), file_size, fp);
        fclose(fp);
        return file_buffer_addr;
    }
    else {
   
        fclose(fp);
        free(file_buffer_addr);
        file_buffer_addr = NULL;
        return NULL;
    }
   

   
}

第二部分:RVA转FOA



DWORD RVAtoFOA(DWORD dwROAAddress,char * FileBuffer){
   
    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 dwNumberofSections = NULL;
    //DWORD dwSizeofImage = NULL;
    //DWORD dwSizeofHeaders = NULL;
    DWORD dwSizeofOptionHeader = NULL;
    DWORD dwVirtualAddress = NULL;
    DWORD dwSizeofRawData = NULL;
    DWORD dwPointerRawData = NULL;
    //DWORD dwVirtualAddress = NULL;
    DWORD dwImageBase = NULL;
    DWORD dwFOAaddress = 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));
    dwImageBase = option_header->ImageBase;
    dwNumberofSections = file_header->NumberOfSections;
    //dwSizeofImage = option_header->SizeOfImage;
    //dwSizeofHeaders = option_header->SizeOfHeaders;
    dwSizeofOptionHeader = file_header->SizeOfOptionalHeader;
    
    section_header = (PIMAGE_SECTION_HEADER)((char*)option_header + dwSizeofOptionHeader);
    if (dwROAAddress <= section_header->VirtualAddress) {
     //如果小于第一个节的virtualAddress,说明在头部。
        dwFOAaddress = dwROAAddress;
        return dwFOAaddress;
    }
    //dwVirtualAddress = section_header->VirtualAddress;
    for (int i = 0; i < dwNumberofSections; i++) {
   
        //printf("%x", ((PIMAGE_SECTION_HEADER)((char*)section_header + 40))->VirtualAddress);
        if (dwROAAddress  >= section_header->VirtualAddress && dwROAAddress < ((PIMAGE_SECTION_HEADER
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值