Решил по изучать РЕ формат вроде все было понятно но вот запнулся об таблицу Экспорта. Пытаюсь понять алгоритм еcли не прав поправьте К примеру, сделали мы MapViewOfFile какой-нибудь dll с диска Получили адрес, к примеру, base=1AC0000h далее получаем RVA директории IMAGE_DIRECTORY_ENTRY_EXPORT = 13CB0h Код (Text): DWORD RVA_EXPORT=pImOpHe->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; Определяем, в какой секции находится таблица Экспорта т.е. Код (Text): Section->VirtualAddress<=RVA_EXPORT<pSH->VirtualAddress + pSH->Misc.VirtualSize Нашли эту секцию, определяем поля из неё Код (Text): Sec_for_export->VirtualAddress =1000h Sec_for_export->PointerToRawData=400h PointerToRawData-это я как понял файловое смешение, т.е. получается base+PointerToRawData=1AC0000+400=1AC0400 -это получается адрес начала раздела, по которому лежит таблица Экспорта теперь к адресу начала прибавим RVA_EXPORT получаем 1AC0400+13CB0=1AD40B0 и теперь надо вычесть VirtualAddress Вроде все понятно но вот почему мы вычитаем VirtualAddress не где я не нашел объяснения(везде в описания просто пишет вычитаем и всё) но не объясняют почему. За раннее благодарен.
RVA - это смещение относительно Base, но только тогда, когда файл промаплен с учетом выравниваний в памяти. Т.е. ты прибавляешь к началу секции RVA, но это смещение не относительно начала секции, потому приходится вычитать VA. Чтобы не париться - мапь файл с флагом SEC_IMAGE и к RVA достаточно будет прибавить адрес загрузки модуля, чтобы получить адрес в памяти.
yurza Когда компиллер строит код, он видит в твоем коде используемые ссылки на данные и делает предположение, что твой код вероятно будет загружен по адресу с численным значением указанным в ImageBase. Однако это значение характеризует код при работе в уже загруженном виртуальном адресном пространстве процесса, но сами данные-то находятся на диске, в файле и тут возникает понятие, что есть еще и файловый образ! Который имеет совершенно другую базу, это начало твоего файла! По этому и разнятся смещения в виртуального и файлового образа, поэтому если ты конвертишь из файлового в виртуальный, ты вычитыаешь файловый, а прибавляешь виртуальный адрес секции!
Замечу, если пишешь тулзы по работе с PE , то лучше не юзай MapViewOfFile , а делай все ручками! Почему не буду говорить, просто напиши тулзу которая чего-нить с образом, к примеру находит адреса ф-ций и проверь их через GetProcAddress. Ну и прогони тулзу по папке %windir%\system32\ , после прогона найдешь файлы на которых MapViewOfFile поведет себя не корректно! Еще советую сделать Self-архивы метров скажем на 200, разными архиваторами WinRar, 7z, etc ну и на них тоже тестить! После тестов скажешь спасибо, что намекнул на хреновость мысли при работе с MapViewOfFile
В довесок ко всему дам советы! 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, он Правильный! И ему ВЕРИТЬ!!!
Огромное спасибо за советы и за ответ но вот опять у меня возник ещё один пытаюсь разобраться теперь с Bound-импорт Алгоритм у меня такой (мучаю calc.exe) Нахожу RVA Код (Text): 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.
yurza Код (Text): void DisplayBoundImp(CPE32 * PEImg) { char ts[30]; BYTE *FO; BYTE *BndBegin; IMAGE_BOUND_IMPORT_DESCRIPTOR *Bound; IMAGE_BOUND_FORWARDER_REF *BForwRef; Bound = PEImg->GetBound(); BndBegin = (BYTE *)Bound; printf("/*-------------------------------------------------/\n"); if(Bound == NULL) { printf("Bound Import not found\n"); return; } if(Bound == CORRUPTED) { printf("Bound Import corrupted\n"); return; } printf("Bound Import Table\n\n"); for(; Bound->OffsetModuleName; Bound++) { ZeroMemory(ts,30); _ctime32_s(ts,30,(__time32_t*)&Bound->TimeDateStamp); FO = BndBegin + Bound->OffsetModuleName; BForwRef = (IMAGE_BOUND_FORWARDER_REF *) ((BYTE *)Bound+sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR)); printf("TimeDateStamp\t\t: 0x%.8X\n",Bound->TimeDateStamp); printf("TimeDateStamp(GMT)\t: %s",ts); printf("OffsetModuleName\t: 0x%.8X -> %s\n",Bound->OffsetModuleName,FO); printf("NumOfModuleForwRefs\t: 0x%.4X\n\n",Bound->NumberOfModuleForwarderRefs); if(Bound->NumberOfModuleForwarderRefs) printf("Forward Modules:\n"); for(WORD i= 0; i< Bound->NumberOfModuleForwarderRefs; i++) { ZeroMemory(ts,30); _ctime32_s(ts,30,(__time32_t*)&BForwRef[i].TimeDateStamp); FO = (BYTE *)BndBegin+BForwRef[i].OffsetModuleName; printf("\tTimeDateStamp\t\t: 0x%.8X\n",BForwRef[i].TimeDateStamp); printf("\tTimeDateStamp(GMT)\t: %s",ts); printf("\tModuleName(Offset)\t: 0x%.8X\n",BForwRef[i].OffsetModuleName); printf("\tModuleName\t\t: %s\n",FO); printf("\tReserved\t\t: 0x%.8X\n",BForwRef[i].Reserved); printf("\n"); } /* Forward */ } }
yurza Грубо говоря, системный загрузчик должен учитывать, что привязанным может быть не только тот модуль что грузится, но и те модули к которым он привязан! ЗЫ: Ноут отремонтируют, думаю написать статейку про привязки, стоит ли? Может позволить уговорить себя великому "влом" ? )))
Ага, спасибо просто читая по стать здесь на сайте От зеленого к красному: Глава 2: там пример работа с Bound есть кусок кода Код (Text): for (int i=0;i«Bound-»NumberOfModuleForwarderRefs;i++) { Bound++; printf("DLL Name:%s TimeDateStamp:%X\n", (long)Bound+(long)(Bound-»OffsetModuleName), Bound-»TimeDateStamp); } Это, меняя и смутило, думал так получается все библиотеки из Bound Importa но, посидев в отладчике, понял, что надо к началу Bound прибавлять значения OffsetModuleName в цикле while(Bound->OffsetModuleName) и так получить все имена dll, но все равно спасибо.