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

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

  1. Entropy

    Entropy Member

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

    ormoulu Active Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    959
    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.734
    Раздел 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
    Сообщения:
    129
    насколько верно понял то RVA адрес связан с SectionAlignment,просто я хотел понять как вычисляется RVA адрес прежде чем будет записан в IMAGE_SECTION_HEADER.VirtualAddress
     
  5. ormoulu

    ormoulu Active Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    959
    Конкретно 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 - можешь написать сам)

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

    Entropy Member

    Публикаций:
    0
    Регистрация:
    23 авг 2020
    Сообщения:
    129
    то есть делится без остатка на значение SectionAlignment ? обычно значение SectionAlignment = 0x1000
     
  8. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.333
    Entropy,
    диапазон поля SectionAlignment варьируется от 16-байт до 64К, управляется ключами компилятора, по умолчанию значение SectionAlignment = 0x200 = 512
    Сказки дядюшки Римуса о x64 Глава третья. Как Братец Кролик уменьшал размер программы
     
  9. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.159
    Mikl___,
    Это про FileAlignment.