FileBuffer和ImageBuffer

  1. 代码实现从文件–FileBuffer–ImageBuffer–NewBuffer–硬盘的过程
  2. RVA和FOA互相转换

文件从FileBuffer经过拉伸后成为ImageBuffer,此时还无法运行,但已经很接近运行的状态了。

代码实现从文件–FileBuffer–ImageBuffer–NewBuffer–硬盘的过程

#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include <stdlib.h>
#include <malloc.h>
#include<windows.h>
#include<memory.h>

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

void  FileToImage() {
    char* pFileBuffer = NULL;
    PIMAGE_DOS_HEADER pDosHeader = NULL;//DOS头 
    PIMAGE_NT_HEADERS pNTHeader = NULL;//NT头 
    PIMAGE_FILE_HEADER pPEHeader = NULL;//PE头 
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;//可选PE头 
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;//节表头
    
    pFileBuffer = ReadFilea("D:\\ipmsg\\IPMsg_2.exe");
    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);
    char* fptr = (pFileBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
    pSectionHeader = PIMAGE_SECTION_HEADER(fptr);

    char* pImageBuffer = NULL;
    pImageBuffer = (char*)malloc(pOptionHeader->SizeOfImage);
    if(!pImageBuffer)
        printf("申请空间失败!\n");
    //申请空间的大小为SizeOfImage
    
    memset(pImageBuffer, 0, pOptionHeader->SizeOfImage);
    //一定要初始化
    memcpy(pImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders);
    //头部信息可以先直接全部复制
    //注意复制的大小为SizeOfHeaders
    
    for(size_t i = 0; i<pPEHeader->NumberOfSections; i++) {//size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数 
        memcpy((void*)(pImageBuffer + pSectionHeader->VirtualAddress), (void*)(pFileBuffer + pSectionHeader->PointerToRawData), pSectionHeader->SizeOfRawData);
        //将FileBuffer中从第一个节点开始,把SizeOfRawData大的节点复制到pImageBuffer+VirtualAddress处
        pSectionHeader++; 	
    }
    //复制节点(拉伸)
    
    //拉伸后存盘
    FILE* nFp;
    nFp = fopen("D:\\ipmsg\\IPMsg_new2.exe", "wb");//复制到指定位置
    fwrite(pImageBuffer, pOptionHeader->SizeOfImage, 1, nFp);
    fclose(nFp);


    //还原后存盘
    char* NewFileBuffer = NULL;
    NewFileBuffer = (char*)malloc(0x22A600);//开辟一个空间,但是由于生成的文件不知道多大,所以不好计算,我就直接计算了未拉伸的文件长度
    if(!NewFileBuffer)
        printf("申请空间失败!\n");
    memset(NewFileBuffer, 0, 0x22A600);
    //不要忘记初始化
    memcpy(NewFileBuffer, pImageBuffer, pOptionHeader->SizeOfHeaders);
    //头部还是保持不变
    fptr = (pFileBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
    pSectionHeader = PIMAGE_SECTION_HEADER(fptr);
    //让其重新指向第一个节点 
    for(size_t i = 0; i < pPEHeader->NumberOfSections; i++) {
        memcpy((void*)(NewFileBuffer + pSectionHeader->PointerToRawData), (void*)(pImageBuffer + pSectionHeader->VirtualAddress), pSectionHeader->SizeOfRawData);
        pSectionHeader++;
    } 
    FILE* nFp1;
    nFp1 = fopen("D:\\ipmsg\\IPMsg_2.exe", "wb");
    fwrite(NewFileBuffer, 0x22A600, 1, nFp1);
    
    fclose(nFp1);
    free(NewFileBuffer); NewFileBuffer = NULL;
    free(pImageBuffer); pImageBuffer = NULL;
    free(pFileBuffer); pFileBuffer = NULL;
}

char* ReadFilea(const char *Filepath ){
    FILE* fptr = NULL;
    fptr = fopen(Filepath,"rb");
    if(!fptr) {
        printf("打开失败");
        return NULL;
    }
    int filesize = 0;
    filesize = GetFileszie(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 GetFileszie(FILE* fptr) {
    int num = 0;
    fseek(fptr, 0, SEEK_END);
    num = ftell(fptr);
    fseek(fptr, 0, SEEK_SET);
    return num;
}
    
int main() {
    //PrintNTHeaders();
    FileToImage();
}

要注意执行完后生成的.exe程序还没法执行。

RVA和FOA互相转换

RVA:文件被装载到内存后相对基址的偏移地址。

FOA:文件偏移地址,即文件在硬盘上相对文件开头的偏移地址。

image-20230829204920600

DWORD RvaToFileOffset(PVOID pBuffer, DWORD dwRva) {
    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;
    if(!pBuffer) {
        printf("(RvaToFileOffset)Can't open file!\n");
        return 0;
    }
    printf("ImageOffset: %#x\n", dwRva);
    pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
    pNTHeader = (PIMAGE_NT_HEADERS)(pBuffer + (pDosHeader->e_lfanew));
    pPEHeader = (PIMAGE_FILE_HEADER)(pBuffer + (pDosHeader->e_lfanew) + 4);
    pOptionHeader = PIMAGE_OPTIONAL_HEADER32(pBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)(pBuffer + pPEHeader->SizeOfOptionalHeader);

    char* fptr = (char *)(pBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
    if(dwRva <= pOptionHeader->SizeOfHeaders) //先判断是否在头部
        return (DWORD)dwRva;
    else {
        for(size_t i = 0; i < pPEHeader->NumberOfSections; i++) {
        //判断 :   文件对齐+文件偏移>file_offset>文件偏移  (即是在文件的哪个节中)
            pSectionHeader = PIMAGE_SECTION_HEADER(fptr);
            if ((dwRva >= pSectionHeader->VirtualAddress) && (dwRva < pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize))
                return dwRva - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
            else 
                fptr = fptr + IMAGE_SIZEOF_SECTION_HEADER;
        }
    }
}
    
DWORD FoaToImageOffset(PVOID pBuffer, DWORD dwFoa) {
    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;
    if(!pBuffer) {
        printf("(FoaToImageOffset)Can't open file!\n");
        return 0;
    }
    printf("FileOffset: %#x\n", dwFoa);
    pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
    pNTHeader = (PIMAGE_NT_HEADERS)(pBuffer + (pDosHeader->e_lfanew));
    pPEHeader = (PIMAGE_FILE_HEADER)(pBuffer + (pDosHeader->e_lfanew) + 4);
    pOptionHeader = PIMAGE_OPTIONAL_HEADER32(pBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)(pBuffer + pPEHeader->SizeOfOptionalHeader);
    char* fptr = (char*)(pBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
    
    if (dwFoa <= pOptionHeader->SizeOfHeaders)
        return (DWORD)dwFoa;
    else {
        for (size_t i = 0; i < pPEHeader->NumberOfSections; i++) {
            //判断 :   文件对齐+文件偏移>file_offset>文件偏移  (即是在文件的哪个节中)
            pSectionHeader = PIMAGE_SECTION_HEADER(fptr);
            if ((dwFoa >= pSectionHeader->PointerToRawData) && (dwFoa < pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData))
                return dwFoa - pSectionHeader->PointerToRawData + pSectionHeader->VirtualAddress;
            else 
                fptr = fptr + IMAGE_SIZEOF_SECTION_HEADER;
        }
    }
}
void operate() {
    LPVOID pFileBuffer = NULL;
    size_t pRVA = 0x12345;
    size_t pFOA = 0x23456;
    pFileBuffer = ReadFilea("C:\\Windows\\System32\\notepad.exe");
    
    DWORD ret_FOA1 = RvaToFileOffset(pFileBuffer, pRVA);
    printf("内存偏移%#x 转换为文件中的偏移: %#x\n", pRVA, ret_FOA1);
    DWORD ret_RVA1 = FoaToImageOffset(pFileBuffer, pFOA);
    printf("文件偏移%#x 转换为内存中的偏移: %#x\n", pFOA, ret_RVA1);
    free(pFileBuffer);
}
int main() {
    PrintNTHeaders();
    operate();
}

在之前的输出PE头信息中添加代码即可。

滴水逆向——RVA与FOA相互转换_rva转foa_「已注销」的博客-CSDN博客


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