Возникли проблемы с обработкой TLS загружаемого образа. Перед обработкой TLS я проделал такие шаги: 1) Загрузил дисковый PE-образ в память 2) Выделил память в куче и спроецировал туда секции и заголовки 3) Обработал релоки и импорт Теперь надо обработать TLS, если он имеется. Я написал такой код: Code (C++): bool LoadPE_HasTLS(LoadPE_CONTEXT* ctx) { return LoadPE_DirectoryExists(ctx, IMAGE_DIRECTORY_ENTRY_TLS); } DWORD LoadPE_GetTLS(LoadPE_CONTEXT* ctx) { return ctx->pPeHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; } void LoadPE_ProcessTLS(LoadPE_CONTEXT* ctx) { if (LoadPE_HasTLS(ctx)) { PIMAGE_TLS_DIRECTORY32 tls = PIMAGE_TLS_DIRECTORY32(ctx->pbRealImageBase + LoadPE_GetTLS(ctx)); std::cout << "StartAddress: " << std::hex << tls->StartAddressOfRawData << std::endl; std::cout << "EndAddress: " << std::hex << tls->EndAddressOfRawData << std::endl; std::cout << "CallbackAddress: " << std::hex << tls->AddressOfCallBacks << std::endl; std::cout << "Callbacks: " << std::endl; PIMAGE_TLS_CALLBACK* cb_addr = (PIMAGE_TLS_CALLBACK *)(ctx->pbRealImageBase + tls->AddressOfCallBacks); while (*cb_addr++) { std::cout << cb_addr << std::endl; } } } Но при вычислении условия цикла программа крашится. Что у меня не так? Кроме того, я не до конца понимаю механизм работы TLS, хотя сегодня и прочитал несколько статей. В директории TLS имеется структура с указателями на данные и на массив адресов коллбэков. Коллбэки вызываются загрузчиком, а что делать с адресами данных? Где и для чего выделять память под индекс? Блок данных можно получить при помощи _readfswdord(0x2C). Что с ним делать дальше? PS. Загрузчик работает, осталось только вот это.
Нет, не смотрел. Пытаюсь разобраться по статьям, но не получается. Все, что у меня пока получилось - это вызвать коллбэки до старта программы, но это никак не связано с написанием PE-лоадера. Может проблема быть связана с тем, что адреса в структуре TLS абсолютные, а мой загрузчик загружает образ по рандомному адресу и делает релокацию?
Не может быть, а так и есть. TLS - это, вроде бы, единственное место в заголовках, где хранятся VA, а не RVA.
Может, в моей функции обработки релоков чего-то не хватает? Code (C++): void LoadPE_PerformRelocation(const LoadPE_CONTEXT* ctx) { DWORD Delta = (DWORD)ctx->pbRealImageBase - ctx->dwPreferImageBase; PIMAGE_BASE_RELOCATION Reloc = ctx->pRelocs; const DWORD RelocDirSize = ctx->dwRelocDirSize; DWORD Offset = 0; while (Offset != RelocDirSize) { const DWORD FixupCount = (Reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); const PIMAGE_FIXUP_ENTRY Fixup = PIMAGE_FIXUP_ENTRY((DWORD(Reloc) + sizeof(IMAGE_BASE_RELOCATION))); for (int i = 0; i < FixupCount; ++i) { if (Fixup[i].Type == IMAGE_REL_BASED_HIGHLOW) { LoadPE_PatchAddress(ctx, Reloc, &Fixup[i], Delta); } } Offset += Reloc->SizeOfBlock; Reloc = PIMAGE_BASE_RELOCATION(DWORD(Reloc) + Reloc->SizeOfBlock); } }
Что копировать, откуда и куда? Непонятно. >Третье поле AddressOfIndex - это адрес, куда загрузчик запишет индекс блока данных потока Какого блока данных? Как получить его адрес? >создаваемого при запуске программы, этот индекс, соответсвенно будет равен нулю А потом как будет меняться этот индекс? >В это поле необходимо поместить адрес из секции данных Секция данных большая, какой именно адрес? >Первым делом нужно найти указатель на блок данных, чтобы скопировать реальные данные Копировать откуда и куда? >Указатель на массив адресов (адресов блоков данных) можно получить из структуры TIB Ок, получил. Что с ним делать? >но помня, что индекс первого потока равен нулю, получаем А если потоков много, кто будет именять индекс?