设为首页 加入收藏

TOP

2.14 PE结构:地址之间的转换(一)
2023-09-23 15:44:05 】 浏览:593
Tags:2.14 结构

在可执行文件PE文件结构中,通常我们需要用到地址转换相关知识,PE文件针对地址的规范有三种,其中就包括了VARVAFOA三种,这三种该地址之间的灵活转换也是非常有用的,本节将介绍这些地址范围如何通过编程的方式实现转换。

如下是三种格式的异同点:

  • VA(Virtual Address,虚拟地址):它是在进程的虚拟地址空间中的地址,用于在运行时访问内存中的数据和代码。VA是相对于进程基址的偏移量。在不同的进程中,相同的VA可能映射到不同的物理地址。
  • RVA(Relative Virtual Address,相对虚拟地址):它是相对于模块基址(Module Base Address)的偏移量,用于定位模块内部的数据和代码。RVA是相对于模块基址的偏移量,通过将模块基址和RVA相加,可以计算出相应的VA。
  • FOA(File Offset Address,文件偏移地址):它是相对于文件起始位置的偏移量,用于定位可执行文件中的数据和代码在文件中的位置。通过将文件偏移地址和节表中的指定节的起始位置相加,可以计算出相应的FOA。

VA虚拟地址转换为FOA文件偏移

VA地址代指的是程序加载到内存后的内存地址,而FOA地址则代表文件内的物理地址,通过编写VA_To_FOA则可实现将一个虚拟地址转换为文件偏移地址,该函数的实现方式,首先得到ImageBase镜像基地址,并得到NumberOfSections节数量,有了该数量以后直接循环,通过判断语句将节限定在一个区间内该区间dwVA >= Section_Start && dwVA <= Section_Ends,当找到后,首先通过VA-ImageBase得到当前的RVA地址,接着通过该地址减去VirtualAddress并加上PointerToRawData文件指针,即可获取到文件内的偏移。

#include <iostream>
#include <Windows.h>
#include <ImageHlp.h>

#pragma comment(lib,"Imagehlp.lib")

// 读取NT头
PIMAGE_NT_HEADERS GetNtHeader(PVOID ImageBase)
{
  PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;

  if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  {
    return NULL;
  }

  PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((BYTE*)ImageBase + pDosHeader->e_lfanew);
  if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
  {
    return NULL;
  }

  return pNtHeaders;
}

// 读取PE结构的封装
HANDLE OpenPeFile(LPTSTR FileName)
{
  HANDLE hFile, hMapFile, lpMapAddress = NULL;
  DWORD dwFileSize = 0;

  // CreateFile 既可以创建文件,也可以打开文件,这里则是打开文件的含义
  hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hFile == INVALID_HANDLE_VALUE)
  {
    return 0;
  }

  // 获取到文件大小
  dwFileSize = GetFileSize(hFile, NULL);

  // 创建文件的内存映像
  hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);
  if (hMapFile == NULL)
  {
    return 0;
  }

  // 读取映射中的内存并返回一个句柄
  lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, dwFileSize);
  if (lpMapAddress != NULL)
  {
    return lpMapAddress;
  }

  return 0;
}

// 将 VA(虚拟地址) --> 转换为 FOA(文件偏移)
DWORD VA_To_FOA(HANDLE ImageBase, DWORD dwVA)
{
  PIMAGE_NT_HEADERS pNtHead = NULL;
  PIMAGE_FILE_HEADER pFileHead = NULL;
  PIMAGE_SECTION_HEADER pSection = NULL;
  DWORD NumberOfSectinsCount = 0;
  DWORD dwImageBase = 0;

  pNtHead = GetNtHeader(ImageBase);
  pSection = IMAGE_FIRST_SECTION(pNtHead);

  dwImageBase = pNtHead->OptionalHeader.ImageBase;
  NumberOfSectinsCount = pNtHead->FileHeader.NumberOfSections;
  for (int each = 0; each < NumberOfSectinsCount; each++)
  {
    // 获取节的开始地址与结束地址
    DWORD Section_Start = dwImageBase + pSection[each].VirtualAddress;
    DWORD Section_Ends = dwImageBase + pSection[each].VirtualAddress + pSection[each].Misc.VirtualSize;
    // 判断当前的VA地址落在了那个节上
    if (dwVA >= Section_Start && dwVA <= Section_Ends)
    {
      DWORD RVA = dwVA - pNtHead->OptionalHeader.ImageBase;                                    // 计算RVA
      DWORD FOA = pSection[each].PointerToRawData + (RVA - pSection[each].VirtualAddress);     // 计算FOA
      return FOA;
    }
  }
  return -1;
}

int main(int argc, char * argv[])
{
  HANDLE lpMapAddress = NULL;

  // 打开PE文件
  lpMapAddress = OpenPeFile(L"d://lyshark.exe");

  // 转换
  DWORD FOA = VA_To_FOA(lpMapAddress, 0x401000);
  printf("VA --> FOA 结果为: %x \n", FOA);

  system("pause");
  retur
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇学习笔记 下一篇4.1 应用层Hook挂钩原理分析

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目