Можно ли безболезненно выгрузить все не нужные мне DLL? Я пытался пройтись по двухсвязанному списку загруженых моделей, начиная с третьего освобаждаю связкой FreeLibrary, UnmapViewOfFile, но видимо я все делаю не так. Код (Text): invoke MessageBoxA, 0,0,0,0 ; Для загрузке в АП лишних DLL mov ecx,eax xor eax, eax assume fs:nothing mov eax,fs:[eax+18h] mov eax,[eax+30h] mov eax,[eax+0Ch] mov esi,[eax+0Ch] mov esi,[esi] mov esi,[esi] mov esi,[esi] label_: MOV edi,[esi+18h] or edi,edi je exit__ invoke FreeLibrary,EDI invoke UnmapViewOfFile, EDI mov esi,[esi] or esi,esi je exit__ jmp label_ exit__:
А зачем UnmapViewOfFile после FreeLibrary? Что-то подобное должно помочь: Код (Text): while (GetModuleHandle(hModule)) FreeLibrary(hModule)
Потому что FreeLibrary не освобождает память. В msdn написано (http://msdn.microsoft.com/en-us/library/ms683152(VS.85).aspx): Т.е. память не освободится, пока не будут обнулены счетчики обращений вроде как. Только я не понимаю что и где это. Короче говоря мне нужно полностью освободить память кроме kernel32.dll и ntdll.dll и собственного образа.
LoadLibrary - увеличивает счетчик FreeLibrary - уменьшаяет если FreeLibrary вызвано столько же раз как LoadLibrary - модуль выгружается, память освобождается (NtUnmapViewOfFile). Исключение - GetModuleHandleEx c флагами GET_MODULE_HANDLE_EX_FLAG_PIN или GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT. В первом случае документированными средствами либу не выгрузить, по втором цикл из предыдущего поста должен помочь
У меня user32.dll загржается только один раз это сис. загрузчиком, FreeLibrary сколько не вызывай не выгражает память.
Как ты пришел к такому выводу на основании этого описания? как ты узнал, что память не освободилась? ненужных длл не бывает. Если они подгрузились, значит они требуются для корректной работы одной из длл в твоем процессе
Ну пример, юзается MessageBoxA из user32.dll которая загружает в след за собой еще десяток dll. После того как отработала MessageBoxA, я более не нуждаюсь в user32.dll и остальных dll кроме kernel32.dll. И мне нужно освободить память, как это сделать? FreeLibrary возратила 1, я без проблем после этого мог прочесть данные из проекции якобы освобожденной dll.
Как раз читал Рихтер: Явная выгрузка DLL Если необходимость в DLL отпадает, ее можно выгрузить из адресного пространства процесса, вызвав функцию. BOOL FreeLibrary(HINSTANCE hinstDll); Вы должны передать в FreeLibrary значение типа HINSTANCE, которое идентифицирует выгружаемую DLL. Это значение Вы получаете после вызова LoadLibrary(Ex). На самом деле LoadLibrary и LoadLibraryEx лишь увеличивают счетчик числа пользователей указанной библиотеки, a FreeLibrary и FreeLibraryAndExitThread его уменьшают Так, при первом вызове LoadLibrary дум загрузки DLL система проецирует образ DLL-файла иа адресное пространство вызывающего процесса и присваивает единицу счетчику числа пользователей этой DLL Если поток того же процесса вызывает LoadLibrary для той же DLL еще раз, DLL больше не проецируется; система просто увеличивает счетчик числа ее пользователей — вот и все. Чтобы выгрузить DLL из адресного пространства процесса, FreeLibrary придется теперь вызывать дважды: первый вызов уменьшит счетчик до 1, второй — до 0. Обнаружив, что счетчик числа пользователей DLL обнулен, система отключит ее. После этого попытка вызова какой-либо функции из данной DLL приведет к нарушению доступа, так как код по указанному адресу уже не отображается на адресное пространство процесса. Система поддерживает в каждом процессе свой счетчик DLL, т. e. если поток процесса А вызывает приведенную ниже функцию, а затем тот же вызов делает поток в процессе В, то MyLib.dll проецируется на адресное пространство обоих процессов, а счетчики числа пользователей DLL в каждом из них приравниваются 1. HINSTANCE hinstDll = LoadLibrary("MyLib.dll"); Если же поток процесса В вызовет далее: FreeLibrary(hinst011); счетчик числа пользователей DLL в процессе В обнулится, что приведет к отключению DLL oт адресного пространства процесса В. Но проекция DLL на адресное пространство процесса А нс затрагивается, и счетчик числа пользователей DLL в нем остается прежним. Чтобы определить, спроецирована ли DLL на адресное пространство процесса, поток может вызывать функцию GеtМоdu1еНапd1е: HINSTANCE GetModuleHandle(PCTSTR pszModuleName); Например, следующий код загружает MyLib.dll, только если она еще не спроецирована на адресное пространство процесса HINSTANCE hinstDll = GetHoduleHandle("MyLib"); // подразумевается расширение .dll if (hinstDll == NULL) { hinstDll = LoadLibrary("MyLib"); // подразумевается расширение .dll }
Я ставил в бесконечный цикл выгрузку user32.dll после миллиона итераций она все равно была в памяти. И FreeLibrary возвращал 1. user32.dll грузится сис. загрузчиком.
Некоторые библиотеки вроде KERNEL32.DLL или USER32.DLL выгрузить нельзя. Они располагаются в верхней части памяти (выше 0x7FFFFFFF) и их расположение совпадает у всех процессов. В ранних версиях Windows эта память была действительно общей изменение её в одном процессе приводило в изменениям во всех. Сейчас эти страницы имеют атрибут COPY_ON_WRITE и поэтому изменения происходят локально. В любом случае эту память освободить так просто нельзя, да и смысла нет - всё равно у всех процессов одна физическая копия USER32, KERNEL32 и некоторых прочих библиотек (если они только не пытались в них что-то изменить) и память зря почти не расходуется.
KIV Это пограничный диапазон ядра для блокирования инвалидных ссылок. Юзерспейс ниже. Выгрузить можно всё, это если нет рабочих потоков. Просто эти два модуля(есчо и нэйтив) содержат глобальные ссылки и не могут релоцироваться.
Т.е. нельзя написать на масме программу использующую MessageBoxA, и после этого выгрузка user32.dll ? Выгрузить не возможно?
sysexit Код (Text): // The process references the system DLL, so map this one next. Since // we have already mapped this one, we need to do the allocation by // hand. Since every application will be statically linked to the // system Dll, we'll keep the LoadCount initialized to 0. Код (Text): // // Lock the loaded DLLs to prevent dlls that back link to the exe to // cause problems when they are unloaded. // { PLDR_DATA_TABLE_ENTRY Entry; PLIST_ENTRY Head,Next; Head = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; Next = Head->Flink; while ( Next != Head ) { Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); Entry->LoadCount = 0xffff; Next = Next->Flink; } } Код (Text): // // Since this DLL has TLS, lock it in // Entry->LoadCount = (USHORT)0xffff; Код (Text): // // Now that we have the data table entry, unload it // if ( LdrDataTableEntry->LoadCount != 0xffff ) { LdrDataTableEntry->LoadCount--; if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL ) { LdrpDereferenceLoadedDll(LdrDataTableEntry); } } else { // // if the load count is 0xffff, then we do not need to recurse // through this DLL's import table. // // Additionally, we don't have to scan more LoadCount == 0 // modules since nothing could have happened as a result of a free on this // DLL. goto leave_finally; }
Когда вручную загружаю свою DLL, то все она нормально выгружается FreeLibrary. В ручную загруженая user32.dll не выгружается никак. В чем дело? Проверил тоже самое только вместо user32.dll использовал comctl32.dll, с она нормально выгружается FreeLibrary. Получается некоторые системные dll не выгрузить?
Ну честно говоря да проблемы с английским, хотелось бы человеческий ответ услышать прямой, а не подсказки далекие. Блокируется выгрузка только user32.dll или еще каких то dll?