в ресурс засовываю DLL. при запуске программы этот ресурс пишется в темповскую папку и грузиться стандартным LoadLibrary. видел на этом сайте статью "запуск программы из памяти". возможно ли сделать это с dll ? у меня есть совсем уж неприличная версия : просто тупо записать адреса нужных функций и вызывать их через call . как считаете это возможно или есть лучший и простой вариант?
Лучший и простой вариант: 1) выделяется память 2) в нее грузится образ DLL с учетом выравнивания из заголовка 3) выполняется релокайшн 4) разрешаются все импорты 5) библиотекой уже о пользоваться, если узнавать адреса экспортируемых функций вручную; чтобы использовать GetProcAddress нужно добавить библиотеку в список PEB_LDR_DATA процесса 6) вызвать DllMain с флагом DLL_PROCESS_ATTACH 7) выгружать библиотеку лучше руками, хотя если поковырять немного, то можно попробовать и с помощью FreeLibrary PS: Для 1 - 4 пунктов исходники выкладывались на форуме несколько раз
а немного поподробнее . а то я не шибкий специалист ))) вот таким макаром вместо специально выделения памяти можно сделать: resP = FindResource ( hInstance, (LPSTR)4000, (LPSTR)1000 ); hP = LoadResource ( hInstance, resP ); sizeP = SizeofResource ( hInstance, resP ); pP = (LPSTR) LockResource ( hP ); ? и поподробнее пункты 3-6 можно расписать ?
Для чужих длл-ок косяки возникают непонятные. Для своих смотри то, что gilg написал. Кто-нибудь видел прогу, которая бы любые длл-ки из памяти могла грузить?
Если все правильно реализовано, косяки могут быть только с вызовом DllMain. Например, если в DllMain создается поток, загрузить вручную такую длл гораздо геморрнее - надо в Peb изменять флаги. Еще в Peb поддерживается хэш-очередь загруженных библиотек, используемая лоадером. В нее влезть похоже что невозможно, а без этого не работают некоторые приятные фичи. Собс-но, вывод - полный аналог виндового лоадера написать не получится, по-любому будут ограничения.
вот, писал когда-то давно РЕ-загрузчик... вроде работает, хотя не исключены лаги)) Код (Text): DWORD GetSectionProtection(DWORD SC) { DWORD result=0; if (SC && IMAGE_SCN_MEM_NOT_CACHED != 0) result = result || PAGE_NOCACHE; if (SC && IMAGE_SCN_MEM_EXECUTE != 0) { if (SC && IMAGE_SCN_MEM_READ != 0) { if (SC && IMAGE_SCN_MEM_WRITE != 0) result = result || PAGE_EXECUTE_READWRITE; else result = result || PAGE_EXECUTE_READ; } else if (SC && IMAGE_SCN_MEM_WRITE != 0) result = result || PAGE_EXECUTE_WRITECOPY; else result = result || PAGE_EXECUTE; } else if (SC && IMAGE_SCN_MEM_READ != 0) { if (SC && IMAGE_SCN_MEM_WRITE != 0) result = result || PAGE_READWRITE; else result = result || PAGE_READONLY; } else if (SC || IMAGE_SCN_MEM_WRITE != 0) result = result || PAGE_WRITECOPY; else result = result || PAGE_NOACCESS; return result; } BOOL ProcessRelocs(long hMap, DWORD dwImageBaseDelta) { PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)(hMap + ((PIMAGE_DOS_HEADER)hMap)->e_lfanew); ULONG pImageBaseRelocation = (ULONG)(RVATOVA(hMap, pImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)); __try { while (((PIMAGE_BASE_RELOCATION)pImageBaseRelocation)->VirtualAddress != 0) { int number = (((PIMAGE_BASE_RELOCATION)pImageBaseRelocation)->SizeOfBlock - 8) / 2; WORD* Rel = (WORD *)(pImageBaseRelocation + 8); for (int i = 0; i < number; i++) { *(PDWORD)(RVATOVA(hMap, ((PIMAGE_BASE_RELOCATION)pImageBaseRelocation)->VirtualAddress + ((0x0FFF)&(Rel[i])))) += dwImageBaseDelta; } pImageBaseRelocation += ((PIMAGE_BASE_RELOCATION)pImageBaseRelocation)->SizeOfBlock; } } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; } return TRUE; } BOOL ProcessImports(long hMap) { IMAGE_THUNK_DATA32 *pThunk; HMODULE hLibModule; PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)(hMap + ((PIMAGE_DOS_HEADER)hMap)->e_lfanew); PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(RVATOVA(hMap, pImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); __try { while (pImageImportDescriptor->Name != 0) { char *name = (char *)RVATOVA(hMap, pImageImportDescriptor->Name); hLibModule = LoadLibrary(name); if (hLibModule == NULL) return FALSE; if (pImageImportDescriptor->TimeDateStamp == 0) pThunk = (IMAGE_THUNK_DATA32 *)RVATOVA(hMap, pImageImportDescriptor->FirstThunk); else pThunk = (IMAGE_THUNK_DATA32 *)RVATOVA(hMap, pImageImportDescriptor->OriginalFirstThunk); while (pThunk->u1.Ordinal != 0) { DWORD dwProcAddr = 0; char *ImportedName; if (((pThunk->u1.Ordinal) & 0x80000000) != 0) { dwProcAddr = (DWORD)GetProcAddress(hLibModule, (char *)(pThunk && 0xFFFF)); } else { PIMAGE_IMPORT_BY_NAME pImageImportByName = (PIMAGE_IMPORT_BY_NAME) RVATOVA(hMap, pThunk->u1.AddressOfData); ImportedName = (char *)&pImageImportByName->Name; dwProcAddr = (DWORD)GetProcAddress(hLibModule, ImportedName); } *(PDWORD)pThunk = dwProcAddr; pThunk++; } pImageImportDescriptor++; } } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; } return TRUE; } DWORD xGetProcAdress(long hMap, int num) { PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)(hMap + ((PIMAGE_DOS_HEADER)hMap)->e_lfanew); PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RVATOVA(hMap, pImageNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); PDWORD AddressOfFunctions = (PDWORD)RVATOVA(hMap, pImageExportDirectory->AddressOfFunctions); for (int i = 0; i < pImageExportDirectory->NumberOfFunctions; i++) if (i == num - 1) return RVATOVA(hMap, AddressOfFunctions[i]); return 0; } HMODULE xLoadLibrary(PBYTE pbDllBuff) { HMODULE hRet = 0; DWORD dwImageBase, dwImageSize, dwHeadersSize, dwImageBaseDelta; PIMAGE_NT_HEADERS pImageNtHeaders; PBYTE pbImage = NULL; __try { pImageNtHeaders = (PIMAGE_NT_HEADERS) (pbDllBuff + ((PIMAGE_DOS_HEADER)pbDllBuff)->e_lfanew); dwImageBase = pImageNtHeaders->OptionalHeader.ImageBase; dwImageSize = pImageNtHeaders->OptionalHeader.SizeOfImage; dwHeadersSize = pImageNtHeaders->OptionalHeader.SizeOfHeaders; DWORD dwNewBase = dwImageBase; while (pbImage == NULL) { pbImage = (PBYTE)GVirtualAlloc((LPVOID)dwNewBase, dwImageSize, MEM_RESERVE, PAGE_NOACCESS); dwNewBase += 0x10000; } dwImageBaseDelta = dwNewBase - dwImageBase - 0x10000; PBYTE pbHeaders = (PBYTE)GVirtualAlloc(pbImage, dwHeadersSize, MEM_COMMIT, PAGE_READWRITE); memcpy(pbHeaders, pbDllBuff, dwHeadersSize); DWORD dwOldProtect; VirtualProtect(pbHeaders, dwHeadersSize, PAGE_READONLY, &dwOldProtect); PIMAGE_SECTION_HEADER pImageSectionHeader = (PIMAGE_SECTION_HEADER) (pImageNtHeaders->FileHeader.SizeOfOptionalHeader + (long)&(pImageNtHeaders->OptionalHeader)); PBYTE pbMem = NULL; DWORD dwRawSectionSize = 0; for (int i = 0; i < pImageNtHeaders->FileHeader.NumberOfSections; i++) { if (pImageSectionHeader->SizeOfRawData > pImageSectionHeader->Misc.VirtualSize) dwRawSectionSize = pImageSectionHeader->Misc.VirtualSize; else dwRawSectionSize = pImageSectionHeader->SizeOfRawData; pbMem = (PBYTE)VirtualAlloc((LPVOID)RVATOVA(pbImage, pImageSectionHeader->VirtualAddress), pImageSectionHeader->Misc.VirtualSize, MEM_COMMIT, PAGE_READWRITE); ZeroMemory(pbMem, pImageSectionHeader->Misc.VirtualSize); memcpy(pbMem, (void *)RVATOVA(pbDllBuff, pImageSectionHeader->PointerToRawData), dwRawSectionSize); pImageSectionHeader++; } for (int i = 0; i < pImageNtHeaders->FileHeader.NumberOfSections; i++) { VirtualProtect((LPVOID)RVATOVA(pbImage, pImageSectionHeader[i].VirtualAddress), pImageSectionHeader[i].Misc.VirtualSize, GetSectionProtection(pImageSectionHeader[i].Characteristics), &dwOldProtect); } if (!ProcessRelocs((long)pbImage, dwImageBaseDelta)) goto end; if (!ProcessImports((long)pbImage)) goto end; } __except (EXCEPTION_EXECUTE_HANDLER) { goto end; } hRet = (HMODULE)pbImage; end: return hRet; }
Например, при создании нового потока GetModuleHandle вызывается для каждой загруженной длл, у которой не стоит флаг LDRP_DONT_CALL_FOR_THREADS. GetModuleHandle работает через хэш-таблицу и, соотв-но, не может найти там нашу длл. В результате создание потока обламывается. Чтобы GetModuleHandle работала нужно либо добавить длл в хэш-таблицу (практически нереально), либо прописать в LDR_DATA_TABLE_ENTRY существующий FullPath, т.е. привязаться к существующему файлу на диске.
Если брать мой случай и конкретную длл, то там не в дллмайн дело, а где-то ещё. Хотя я на правильность реализации и не претендую пока. gilg Слушай, а из каких источников столько информации взял?
Не забывайте, что иногда DLL можно сконвертировать в статический LIB (с помощью Dll2Lib) и линковать прямо в экзешник без лишних ресурсов, эмоций и кода.
Ну да, тип того. Кстати, по поводу FullPath еще один прикол есть. ProcessExplorer валится при попытке просмотра свойств инжектированной длл в которой он пустой.
объяните плиз зачем длл в ресурсы и потом загружать? помоему для всех случаев достаточно способа Quantum-а
n0name Интересно, какой из 2х "из" нужно заменить на "в"? Думаю, что второй. fr0b-p Dll2Lib нормально работает далеко не со всеми Dll. С другой стороны, после конвертирования можно вооружиться отладчиком и пофиксить баги в Lib вручную, но это уже зависит от квалификации.