Почему вычитается VirtualAddress или опять про РЕ

Тема в разделе "WASM.BEGINNERS", создана пользователем yurza, 25 сен 2009.

  1. yurza

    yurza New Member

    Публикаций:
    0
    Регистрация:
    5 мар 2008
    Сообщения:
    69
    Решил по изучать РЕ формат вроде все было понятно но вот запнулся об таблицу Экспорта. Пытаюсь понять алгоритм еcли не прав поправьте
    К примеру, сделали мы MapViewOfFile какой-нибудь dll с диска
    Получили адрес, к примеру, base=1AC0000h
    далее получаем RVA директории IMAGE_DIRECTORY_ENTRY_EXPORT = 13CB0h
    Код (Text):
    1. DWORD RVA_EXPORT=pImOpHe->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    Определяем, в какой секции находится таблица Экспорта т.е.
    Код (Text):
    1. Section->VirtualAddress<=RVA_EXPORT<pSH->VirtualAddress + pSH->Misc.VirtualSize
    Нашли эту секцию, определяем поля из неё
    Код (Text):
    1. Sec_for_export->VirtualAddress =1000h
    2. Sec_for_export->PointerToRawData=400h
    PointerToRawData-это я как понял файловое смешение, т.е. получается base+PointerToRawData=1AC0000+400=1AC0400 -это получается адрес начала раздела, по которому лежит таблица Экспорта теперь к адресу начала прибавим RVA_EXPORT получаем 1AC0400+13CB0=1AD40B0 и теперь надо вычесть
    VirtualAddress
    Вроде все понятно но вот почему мы вычитаем VirtualAddress не где я не нашел объяснения(везде в описания просто пишет вычитаем и всё) но не объясняют почему.
    За раннее благодарен.
     
  2. IceT

    IceT IceT

    Публикаций:
    0
    Регистрация:
    13 авг 2009
    Сообщения:
    233
    Адрес:
    RU
    RVA - это смещение относительно Base, но только тогда, когда файл промаплен с учетом выравниваний в памяти. Т.е. ты прибавляешь к началу секции RVA, но это смещение не относительно начала секции, потому приходится вычитать VA. Чтобы не париться - мапь файл с флагом SEC_IMAGE и к RVA достаточно будет прибавить адрес загрузки модуля, чтобы получить адрес в памяти.
     
  3. TbI_TyT

    TbI_TyT New Member

    Публикаций:
    0
    Регистрация:
    2 мар 2009
    Сообщения:
    58
    yurza
    Когда компиллер строит код, он видит в твоем коде используемые ссылки на данные и делает предположение, что твой код вероятно будет загружен по адресу с численным значением указанным в ImageBase. Однако это значение характеризует код при работе в уже загруженном виртуальном адресном пространстве процесса, но сами данные-то находятся на диске, в файле и тут возникает понятие, что есть еще и файловый образ! Который имеет совершенно другую базу, это начало твоего файла! По этому и разнятся смещения в виртуального и файлового образа, поэтому если ты конвертишь из файлового в виртуальный, ты вычитыаешь файловый, а прибавляешь виртуальный адрес секции! ;)
     
  4. TbI_TyT

    TbI_TyT New Member

    Публикаций:
    0
    Регистрация:
    2 мар 2009
    Сообщения:
    58
    Замечу, если пишешь тулзы по работе с PE , то лучше не юзай MapViewOfFile , а делай все ручками! ;) Почему не буду говорить, просто напиши тулзу которая чего-нить с образом, к примеру находит адреса ф-ций и проверь их через GetProcAddress. Ну и прогони тулзу по папке %windir%\system32\ , после прогона найдешь файлы на которых MapViewOfFile поведет себя не корректно! Еще советую сделать Self-архивы метров скажем на 200, разными архиваторами WinRar, 7z, etc ну и на них тоже тестить!
    После тестов скажешь спасибо, что намекнул на хреновость мысли при работе с MapViewOfFile ;)
     
  5. TbI_TyT

    TbI_TyT New Member

    Публикаций:
    0
    Регистрация:
    2 мар 2009
    Сообщения:
    58
    В довесок ко всему дам советы!

    1)
    Забудь закладываться на размеры секций в их хидерах, надо минималить между ними и размером файла! Это значение и есть искомый размер секции в файле, иначе бага!

    ObjLen = MIN(OBJ.SizeOfRawData,OBJ.misc.VirtualSize);
    ObjLen = MIN(ObjLen, FileLength);

    Это истинный размер!

    2)
    А вот истинные начала секции:

    ObjRaw = ALLIGN(OBJ.PointerToRawData,PE->OptionalHeader.FileAlignment);
    ObjRva = ALLIGN(OBJ.VirtualAddress,PE->OptionalHeader.SectionAlignment);

    Если не послушаешься, то твоя тулза нае..ся на WinUpack'e !!!

    3)
    Истинный адрес начало области, где лежат хидеры секций, вычисляется по :
    FirstObjRaw = PEHeaderRaw + 4+sizeof(IMAGE_FILE_HEADER)+PE->FileHeader.SizeOfOptionalHeader;

    тоже самое делает и макрос IMAGE_FIRST_SECTION как-то так из winnt.h, он Правильный! И ему ВЕРИТЬ!!!
     
  6. yurza

    yurza New Member

    Публикаций:
    0
    Регистрация:
    5 мар 2008
    Сообщения:
    69
    Огромное спасибо за советы и за ответ но вот опять у меня возник ещё один пытаюсь разобраться теперь с Bound-импорт
    Алгоритм у меня такой (мучаю calc.exe)
    Нахожу RVA
    Код (Text):
    1. RVA_Bound=pImOpHe->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress
    Оно равно 238h по этому адресу находится TimeDateStamp за ней находится смешение OffsetModuleName по которому находится имени DLL т.е. 238h+0038h=270h смотрим действительно там находится SHELL32.dll дальше за OffsetModuleName идет поле NumberOfModuleForwarderRefs это как я понял количество структур IMAGE_BOUND_FORWARDER_REF но ведь там ноль на подскажите в чем не правильность алгоритма ведь из рисунка видно что там есть ещё dll.

    [​IMG]
     
  7. TbI_TyT

    TbI_TyT New Member

    Публикаций:
    0
    Регистрация:
    2 мар 2009
    Сообщения:
    58
    yurza
    Код (Text):
    1. void DisplayBoundImp(CPE32 * PEImg)
    2. {
    3.   char  ts[30];
    4.   BYTE *FO;
    5.   BYTE *BndBegin;
    6.   IMAGE_BOUND_IMPORT_DESCRIPTOR *Bound;
    7.   IMAGE_BOUND_FORWARDER_REF     *BForwRef;
    8.  
    9.   Bound = PEImg->GetBound();
    10.   BndBegin = (BYTE *)Bound;
    11.   printf("/*-------------------------------------------------/\n");
    12.   if(Bound == NULL)
    13.   {
    14.     printf("Bound Import not found\n");
    15.     return;
    16.   }
    17.   if(Bound == CORRUPTED)
    18.   {
    19.     printf("Bound Import corrupted\n");
    20.     return;
    21.   }
    22.   printf("Bound Import Table\n\n");
    23.  
    24.   for(; Bound->OffsetModuleName; Bound++)
    25.   {
    26.     ZeroMemory(ts,30);
    27.     _ctime32_s(ts,30,(__time32_t*)&Bound->TimeDateStamp);
    28.     FO = BndBegin + Bound->OffsetModuleName;
    29.     BForwRef = (IMAGE_BOUND_FORWARDER_REF *)
    30.       ((BYTE *)Bound+sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR));
    31.  
    32.     printf("TimeDateStamp\t\t: 0x%.8X\n",Bound->TimeDateStamp);
    33.     printf("TimeDateStamp(GMT)\t: %s",ts);
    34.     printf("OffsetModuleName\t: 0x%.8X -> %s\n",Bound->OffsetModuleName,FO);
    35.     printf("NumOfModuleForwRefs\t: 0x%.4X\n\n",Bound->NumberOfModuleForwarderRefs);
    36.     if(Bound->NumberOfModuleForwarderRefs)
    37.       printf("Forward Modules:\n");
    38.  
    39.     for(WORD i= 0; i< Bound->NumberOfModuleForwarderRefs; i++)
    40.     {
    41.       ZeroMemory(ts,30);
    42.       _ctime32_s(ts,30,(__time32_t*)&BForwRef[i].TimeDateStamp);
    43.       FO = (BYTE *)BndBegin+BForwRef[i].OffsetModuleName;
    44.  
    45.       printf("\tTimeDateStamp\t\t: 0x%.8X\n",BForwRef[i].TimeDateStamp);
    46.       printf("\tTimeDateStamp(GMT)\t: %s",ts);
    47.       printf("\tModuleName(Offset)\t: 0x%.8X\n",BForwRef[i].OffsetModuleName);
    48.       printf("\tModuleName\t\t: %s\n",FO);
    49.       printf("\tReserved\t\t: 0x%.8X\n",BForwRef[i].Reserved);
    50.       printf("\n");
    51.     } /* Forward */
    52.   }  
    53. }
     
  8. TbI_TyT

    TbI_TyT New Member

    Публикаций:
    0
    Регистрация:
    2 мар 2009
    Сообщения:
    58
    yurza
    Грубо говоря, системный загрузчик должен учитывать, что привязанным может быть не только тот модуль что грузится, но и те модули к которым он привязан!
    ЗЫ:
    Ноут отремонтируют, думаю написать статейку про привязки, стоит ли? Может позволить уговорить себя великому "влом" ? )))
     
  9. TbI_TyT

    TbI_TyT New Member

    Публикаций:
    0
    Регистрация:
    2 мар 2009
    Сообщения:
    58
    Бред, все что не сорец, не читай. Не проснулся еще )))
     
  10. yurza

    yurza New Member

    Публикаций:
    0
    Регистрация:
    5 мар 2008
    Сообщения:
    69
    Ага, спасибо просто читая по стать здесь на сайте От зеленого к красному: Глава 2: там пример работа с Bound есть кусок кода
    Код (Text):
    1. for (int i=0;i«Bound-»NumberOfModuleForwarderRefs;i++)
    2.     {
    3.         Bound++;
    4.         printf("DLL Name:%s TimeDateStamp:%X\n",
    5.               (long)Bound+(long)(Bound-»OffsetModuleName),
    6.               Bound-»TimeDateStamp);
    7.     }
    Это, меняя и смутило, думал так получается все библиотеки из Bound Importa но, посидев в отладчике, понял, что надо к началу Bound прибавлять значения OffsetModuleName в цикле while(Bound->OffsetModuleName) и так получить все имена dll, но все равно спасибо.