• 逆向笔记——PE文件相对虚拟地址(RVA)转文件偏移地址(FOA)


    手工

    编译一个带有全局变量的exe
    这是代码

    
    #include <stdio.h>
    
    int globalVar = 0x12345678;
    
    void main()
    {
    	printf("globalVar = %x, RVA=%x
    ",globalVar,&globalVar);	//RVA=424a30 | FOA=424a30-400000=24a30
    
    }
    

    打印出来的是全局变量globalVar 在内存中的地址 VA=424a30

    PETool看基址=00400000,RVA=VA-ImageBase=424a30-00400000 = 24a30

    再看看在内存中、文件中的对齐方式
    1、如果在内存中和文件中的对齐方式是一致的,那么 RVA=FOA=24a30
    2、如果它们的对齐方式不一样,那么 FOA = 节.PointToRawData+差值偏差
    差值偏差=RVA - 节.VirtuallAddress,如果想不通,看下图:

    我这里的对齐方式是一样的,所以FOA=24a30

    PE编辑工具打开exe文件,找24a30地址的值,改之为 66666666

    保存,运行exe看这时候的值

    代码实现 RVA->FVA

    步骤:

    代码:

    
    #include <stdio.h>
    #include <windows.h>
    /************************
    功能:内存中的相对虚拟偏移转换为文件中的偏移
    步骤:假设x是需要计算FOA的内存地址
    	1、先计算 RVA = x-ImageBase
    	2、计算差值偏差 y = RVA-节.VirtualAddress
    	3、计算FOA=节.PointToRawData+y
    *************************/
    unsigned char* FileBuffer(const char* FileName);
    unsigned char* RVAToFVA(unsigned char* x) //x的位置
    {
    	unsigned char* FVA=NULL;
    	unsigned char* RVA=NULL;
    	PIMAGE_DOS_HEADER pDosHeader;
    	PIMAGE_NT_HEADERS pNtHeaders;
    	PIMAGE_SECTION_HEADER pSectionHeader;
    
    	//打开文件映射到filebuffer
    	unsigned char* fileBuffer = FileBuffer("test.exe");
    
    	//得到 PIMAGE_OPTIONAL_HEADER=>ImageBase  PIMAGE_SECTION_HEADER=>VirtualAddress  PointToRawData
         pDosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
         pNtHeaders = (PIMAGE_NT_HEADERS)(fileBuffer + pDosHeader->e_lfanew);
         pSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders+1);
    	 printf("%x
    ",pNtHeaders->OptionalHeader.ImageBase);
    	 RVA = x-pNtHeaders->OptionalHeader.ImageBase;
    	 //判断是否在DOS+NT头部内,是则RVA=FOA
    	 if(x<=(unsigned char*)pNtHeaders->OptionalHeader.SizeOfHeaders)
    	 {
    		FVA = RVA;
    		printf("在头部FVA=RVA=%x
    ",FVA);
    		return FVA;
    	 }
    	
    	 //判断在哪个节
    	 unsigned int i=0;
    	 for(i=0;i<pNtHeaders->FileHeader.NumberOfSections;i++)
    	 {
    		printf("%x
    ",pSectionHeader[i].PointerToRawData);
    
    		printf("%x
    ",pSectionHeader[i].VirtualAddress);
    
    		if(RVA>=(unsigned char*)pSectionHeader[i].VirtualAddress && RVA<=(unsigned char*)(pSectionHeader[i].VirtualAddress+pSectionHeader[i].Misc.VirtualSize) )
    		{
    			//在这个节:计算偏差->计算FOA
    
    			FVA = pSectionHeader[i].PointerToRawData+(RVA-pSectionHeader[i].VirtualAddress);
    			printf("在%s节中,FVA=%x
    ", pSectionHeader[i].Name,FVA);
    			return FVA;
    		}
    	 }
    	return NULL;
    }
    
    void main()
    {
    	unsigned char* x = (unsigned char*)0x424a30;
    	RVAToFVA(x); //内存中的虚拟地址
    }
    
    //将PE文件读到FileBuffer
    unsigned char* FileBuffer(const char* FileName)
    {
         unsigned char* Heap = NULL;
         FILE* Stream;
    
         //打开文件
         Stream = fopen(FileName,"rb");
         //计算文件大小
         fseek(Stream,0,SEEK_END);
         long FileSize = ftell(Stream);
         fseek(Stream,0,SEEK_SET);
    
         //分配堆空间
         Heap = (unsigned char*)malloc(sizeof(char)*FileSize);
         //将文件拷到堆
         fread(Heap,sizeof(char),FileSize,Stream);
         fclose(Stream);
    
    	 return Heap;
    }
    

    FVA->RVA 原理同上

          设x 为节数据的任意一位置

          1.计算差值偏移:
    差值 = x - 节.PointerToRawData(节数据在文件中开始的位置)

          2.计算RVA
    RVA = 差值 + 节.VirtuallAddress(节数据在内存中展开的位置)

          3.计算虚拟地址:
    VA = RVA + ImageBase

    判断x在哪一个节中的条件: x <= 节.PointerToRawData + 节.SizeofRawData

  • 相关阅读:
    jsonp跨域请求
    Vue-cli脚手架安装
    微信小程序获取用户信息“授权失败”场景的处理
    微信小程序
    获取url参数
    [git] github 使用简单记录
    [翻译]《高级英汉翻译理论与实践》摘录
    [Java] 模板引擎 Velocity 随笔
    [Java] 垃圾回收 ( Garbage Collection ) 的步骤演示
    [Java] 垃圾回收机制 ( Garbage Collection ) 简介
  • 原文地址:https://www.cnblogs.com/Erma/p/12597677.html
Copyright © 2020-2023  润新知