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

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

  1. Entropy

    Entropy Member

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

    ormoulu Well-Known Member

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

    ormoulu Well-Known Member

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

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

    x0rum New Member

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

    Ф-ия 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
    Сообщения:
    266
    то есть делится без остатка на значение SectionAlignment ? обычно значение SectionAlignment = 0x1000
     
  8. Mikl___

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

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

    rmn Well-Known Member

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

    Entropy Member

    Публикаций:
    0
    Регистрация:
    23 авг 2020
    Сообщения:
    266
    скорее всего rva адрес зависит значения поля SectionAlignment,во всех pe-файлах rva начинается с 0x1000
     

    Вложения:

    • pe_rva_info.PNG
      pe_rva_info.PNG
      Размер файла:
      57,6 КБ
      Просмотров:
      113
  11. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    602
    rva это смещение в отображенном в память файле, отличается от сырых(файловых) из за страничной гранулярности памяти(0x1000 это размер физической страницы):preved:
     
  12. Entropy

    Entropy Member

    Публикаций:
    0
    Регистрация:
    23 авг 2020
    Сообщения:
    266
    видимо такая страничная гранулярность во всех версиях Windows,у меня есть мысль,если значения rva адреса на кратно SectionAlignment тогда неправилен,то есть rva адрес может быть любым главное что бы он был кратен SectionAlignment
     
  13. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    602
    На меньшей гранулярности чем страница не может быть изменен тип памяти, те атр. секции.

    Код (Text):
    1. if (((Hdr)->OptionalHeader).SectionAlignment < ((Hdr)->OptionalHeader).FileAlignment) { \
    2.         return STATUS_INVALID_IMAGE_FORMAT;                         \
    3.     }
    - ядерная проверка валидности.

    PE Format