Рассчёт RVA адреса

Тема в разделе "WASM.RESEARCH", создана пользователем Entropy, 5 апр 2022.

  1. Entropy

    Entropy Member

    Публикаций:
    0
    Регистрация:
    23 авг 2020
    Сообщения:
    128
    Часто интересовался структурой PE файлов,у меня вызывает вопрос такая вещь как RVA адрес,если быть точнее то меня интересует как он вычисляется, к примеру RVA секции .text
     
  2. ormoulu

    ormoulu Active Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    937
    RVA - Relative Virtual Address это смещение секции файла относительно базового адреса образа в виртуальной памяти.
    К примеру, библиотека .dll загружена по адресу 0x400000, RVA секции .text 0x1000, виртуальный адрес .text - 0x401000.

    Зависит от того, откуда вам нужно вычислить RVA. Если из заголовка PE - смотрите IMAGE_SECTION_HEADER.
     
  3. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    1.699
    Раздел Section Headers: https://docs.microsoft.com/en-gb/windows/win32/debug/pe-format, поле VirtualAddress (сбивающее с толку название) содержит RVA секции. Пример:
    RVA+IMAGE_BASE=VA=0x00001000+0x00400000=0x00401000
     
  4. Entropy

    Entropy Member

    Публикаций:
    0
    Регистрация:
    23 авг 2020
    Сообщения:
    128
    насколько верно понял то RVA адрес связан с SectionAlignment,просто я хотел понять как вычисляется RVA адрес прежде чем будет записан в IMAGE_SECTION_HEADER.VirtualAddress
     
  5. ormoulu

    ormoulu Active Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    937
    Конкретно RVA секции вычисляется примерно так: размер загруженного в память заголовка + размер загруженной в память секции 1 (например, .text) + размер загруженной в память секции 2 + ... +размер загруженной в память секции n, где 1..n это секции расположенные перед нашей секцией (все это естественно выравнено на сколько там позволяет SectionAlignment, загрузчик и размер страницы).

    Можно ли от этого правила отступить и написать RVA от балды вопрос интересный, какие проверки будет делать загрузчик, надо тестировать.
     
  6. x0rum

    x0rum New Member

    Публикаций:
    0
    Регистрация:
    15 июн 2021
    Сообщения:
    9
    А вот ещё немного мягких французских коденгов

    Ф-ия CmcPeMapRva "проецирует" RVA, указывающий внутрь PE- образа на
    смещение внутри файла на диске.
    ULONG всегда 32-бит, т.к. в 64-битной винде размер PE-образа 32-битный, как и на 32-битной винде.
    А структурка CMC_PE_DESC нам нужна чтобы задать, хотим ли мы работать с PE-образом,
    загруженым в память (когда секции отображены по их Virtual Addresses) или передаем PE- образ
    в том виде, в котором он считан с диска ("raw"). Ну и указатель на сам образ тоже в этой структурке.

    А TODO: overlay - можешь написать сам)

    Код (Text):
    1.  
    2. void CmcPeGetHeaders(const void* ImageBase, void** Nt32or64Headers,
    3.   PIMAGE_SECTION_HEADER* SectionHeader)
    4. {
    5.   PIMAGE_DOS_HEADER Dos = (PIMAGE_DOS_HEADER)ImageBase;
    6.   // NT headers 32 and 64 differ only in Optional header
    7.   PIMAGE_NT_HEADERS32 Nt32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)ImageBase + Dos->e_lfanew);
    8.   if (Nt32or64Headers) {
    9.   *Nt32or64Headers = (void*)Nt32;
    10.   }
    11.   if (SectionHeader) {
    12.   *SectionHeader =
    13.   (PIMAGE_SECTION_HEADER)((ULONG_PTR)&Nt32->OptionalHeader +
    14.   Nt32->FileHeader.SizeOfOptionalHeader);
    15.   }
    16. }
    17.  
    18. BOOLEAN CmcPeIs64Bit(const void* ImageBase) {
    19.   PIMAGE_NT_HEADERS32 Nt;
    20.   CmcPeGetHeaders(ImageBase, (void**)&Nt, NULL);
    21.   return Nt->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 ? TRUE : FALSE;
    22. }
    23.  
    24. // |ImageBase| can be either mapped or raw, we don't care, we're just looking into its headers
    25. int CmcPeLocateRva(const void* ImageBase, ULONG Rva, PULONG DiskOfs,
    26.   PULONG OfsInsideSec, PIMAGE_SECTION_HEADER* SecPtr, PUSHORT SecIdx)
    27. {
    28.   ULONG SectionAlignment, SizeOfHeaders;
    29.   union {
    30.   PIMAGE_NT_HEADERS32 Nt32;
    31.   PIMAGE_NT_HEADERS64 Nt64;
    32.   } Bitness;
    33.   PIMAGE_SECTION_HEADER SecHdr;
    34.   CmcPeGetHeaders(ImageBase, (void**)&Bitness.Nt32, &SecHdr);
    35.   if (CmcPeIs64Bit(ImageBase)) {
    36.   SectionAlignment = Bitness.Nt64->OptionalHeader.SectionAlignment;
    37.   SizeOfHeaders = Bitness.Nt64->OptionalHeader.SizeOfHeaders;
    38.   }
    39.   else {
    40.   SectionAlignment = Bitness.Nt32->OptionalHeader.SectionAlignment;
    41.   SizeOfHeaders = Bitness.Nt64->OptionalHeader.SizeOfHeaders;
    42.   }
    43.   ULONG RetDiskOfs, RetOfsInsideSec;
    44.   PIMAGE_SECTION_HEADER RetSecPtr;
    45.   USHORT RetSecIdx;
    46.   if (Rva < SizeOfHeaders) {
    47.   // Supplied RVA points to headers
    48.   RetDiskOfs = Rva;
    49.   RetOfsInsideSec = 0;
    50.   RetSecPtr = NULL;
    51.   RetSecIdx = 0;
    52.   goto Success;
    53.   }
    54.   //
    55.   // TODO: overlay
    56.   //
    57.   // FILE_HEADERs are same for 32- and 64- bit structs
    58.   for (WORD i = 0; i < Bitness.Nt32->FileHeader.NumberOfSections; i++) {
    59.   ULONG SecRawSize = ALIGN_UP_BY(SecHdr[i].SizeOfRawData, SectionAlignment);
    60.   ULONG SecVa = SecHdr[i].VirtualAddress;
    61. //  ULONG secEndRva = SecHdr[i].VirtualAddress + SecHdr[i].Misc.VirtualSize;
    62.   if (Rva >= SecVa && Rva < SecVa + SecRawSize) {
    63.   RetSecIdx = i;
    64.   RetOfsInsideSec = Rva - SecVa;
    65.   RetSecPtr = &SecHdr[RetSecIdx];
    66.   RetDiskOfs = SecHdr[RetSecIdx].PointerToRawData + RetOfsInsideSec;
    67.   goto Success;
    68.   }
    69.   }
    70.   // No sections found
    71.   return -1;
    72. Success:
    73.   if (DiskOfs != NULL) { *DiskOfs = RetDiskOfs; }
    74.   if (OfsInsideSec != NULL) { *OfsInsideSec = RetOfsInsideSec; }
    75.   if (SecPtr != NULL) { *SecPtr = RetSecPtr; }
    76.   if (SecIdx != NULL) { *SecIdx = RetSecIdx; }
    77.   return 0;
    78. }
    79.  
    80. PVOID CmcPeMapRva(const CMC_PE_DESC* PeDesc, ULONG Rva) {
    81.   if (!PeDesc->IsImageMapped) {
    82.   ULONG DiskOfs;
    83.   if (CmcPeLocateRva(PeDesc->Image, Rva, &DiskOfs, NULL, NULL, NULL) < 0) {
    84.   return NULL;
    85.   }
    86.   return (PVOID)((ULONG_PTR)PeDesc->Image + DiskOfs);
    87.   }
    88.   else {
    89.   return (PVOID)((ULONG_PTR)PeDesc->Image + Rva);
    90.   }
    91. }
    92.  
    Код (Text):
    1.  
    2. typedef struct _CMC_PE_DESC {
    3.   void*  Image;
    4.   BOOLEAN  IsImageMapped;
    5. } CMC_PE_DESC;
    6.