Выгрузка всех DLL.

Тема в разделе "WASM.WIN32", создана пользователем sysexit, 8 ноя 2010.

  1. sysexit

    sysexit New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2010
    Сообщения:
    176
    Можно ли безболезненно выгрузить все не нужные мне DLL?

    Я пытался пройтись по двухсвязанному списку загруженых моделей, начиная с третьего освобаждаю связкой FreeLibrary, UnmapViewOfFile, но видимо я все делаю не так.

    Код (Text):
    1. invoke MessageBoxA, 0,0,0,0 ; Для загрузке в АП лишних DLL
    2. mov     ecx,eax
    3. xor     eax, eax
    4. assume  fs:nothing
    5. mov     eax,fs:[eax+18h]
    6. mov     eax,[eax+30h]
    7. mov     eax,[eax+0Ch]
    8. mov     esi,[eax+0Ch]
    9. mov     esi,[esi]
    10. mov     esi,[esi]
    11. mov     esi,[esi]
    12. label_:
    13. MOV edi,[esi+18h]
    14. or edi,edi
    15. je exit__
    16. invoke FreeLibrary,EDI
    17. invoke UnmapViewOfFile, EDI
    18. mov esi,[esi]
    19. or esi,esi
    20. je exit__
    21. jmp     label_
    22. exit__:
     
  2. Mentor

    Mentor New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2010
    Сообщения:
    67
    А зачем UnmapViewOfFile после FreeLibrary?

    Что-то подобное должно помочь:
    Код (Text):
    1. while (GetModuleHandle(hModule))
    2.   FreeLibrary(hModule)
     
  3. sysexit

    sysexit New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2010
    Сообщения:
    176
    Потому что FreeLibrary не освобождает память.

    В msdn написано (http://msdn.microsoft.com/en-us/library/ms683152(VS.85).aspx):
    Т.е. память не освободится, пока не будут обнулены счетчики обращений вроде как.
    Только я не понимаю что и где это.

    Короче говоря мне нужно полностью освободить память кроме kernel32.dll и ntdll.dll и собственного образа.
     
  4. Mentor

    Mentor New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2010
    Сообщения:
    67
    LoadLibrary - увеличивает счетчик
    FreeLibrary - уменьшаяет

    если FreeLibrary вызвано столько же раз как LoadLibrary - модуль выгружается, память освобождается (NtUnmapViewOfFile).

    Исключение - GetModuleHandleEx c флагами GET_MODULE_HANDLE_EX_FLAG_PIN или GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT. В первом случае документированными средствами либу не выгрузить, по втором цикл из предыдущего поста должен помочь
     
  5. sysexit

    sysexit New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2010
    Сообщения:
    176
    У меня user32.dll загржается только один раз это сис. загрузчиком, FreeLibrary сколько не вызывай не выгражает память.
     
  6. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    Как ты пришел к такому выводу на основании этого описания?

    как ты узнал, что память не освободилась?

    ненужных длл не бывает. Если они подгрузились, значит они требуются для корректной работы одной из длл в твоем процессе
     
  7. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    MSoft
    он наверно про р3 часть пасущей дряни
     
  8. sysexit

    sysexit New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2010
    Сообщения:
    176
    Ну пример, юзается MessageBoxA из user32.dll которая загружает в след за собой еще десяток dll. После того как отработала MessageBoxA, я более не нуждаюсь в user32.dll и остальных dll кроме kernel32.dll. И мне нужно освободить память, как это сделать?

    FreeLibrary возратила 1, я без проблем после этого мог прочесть данные из проекции якобы освобожденной dll.
     
  9. AlexCab

    AlexCab New Member

    Публикаций:
    0
    Регистрация:
    8 сен 2008
    Сообщения:
    142
    Как раз читал:)

    Рихтер:
    Явная выгрузка 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
    }
     
  10. sysexit

    sysexit New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2010
    Сообщения:
    176
    Я ставил в бесконечный цикл выгрузку user32.dll после миллиона итераций она все равно была в памяти. И FreeLibrary возвращал 1. user32.dll грузится сис. загрузчиком.
     
  11. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    Так посмотри, чему равен счетчик и почему он меняется, если он меняется. Счетчик точно ставится в 0?
     
  12. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    sysexit
    Нельзя. Обьект удалится, ссылки на него останутся. Это приведёт к #AV.
     
  13. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Некоторые библиотеки вроде KERNEL32.DLL или USER32.DLL выгрузить нельзя. Они располагаются в верхней части памяти (выше 0x7FFFFFFF) и их расположение совпадает у всех процессов. В ранних версиях Windows эта память была действительно общей изменение её в одном процессе приводило в изменениям во всех. Сейчас эти страницы имеют атрибут COPY_ON_WRITE и поэтому изменения происходят локально. В любом случае эту память освободить так просто нельзя, да и смысла нет - всё равно у всех процессов одна физическая копия USER32, KERNEL32 и некоторых прочих библиотек (если они только не пытались в них что-то изменить) и память зря почти не расходуется.
     
  14. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Вообще-то, там уже ядро начинается.
     
  15. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    KIV
    Это пограничный диапазон ядра для блокирования инвалидных ссылок. Юзерспейс ниже. Выгрузить можно всё, это если нет рабочих потоков. Просто эти два модуля(есчо и нэйтив) содержат глобальные ссылки и не могут релоцироваться.
     
  16. sysexit

    sysexit New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2010
    Сообщения:
    176
    Т.е. нельзя написать на масме программу использующую MessageBoxA, и после этого выгрузка user32.dll ? Выгрузить не возможно?
     
  17. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    sysexit
    Код (Text):
    1.     // The process references the system DLL, so map this one next. Since
    2.     // we have already mapped this one, we need to do the allocation by
    3.     // hand. Since every application will be statically linked to the
    4.     // system Dll, we'll keep the LoadCount initialized to 0.
    Код (Text):
    1.     //
    2.     // Lock the loaded DLLs to prevent dlls that back link to the exe to
    3.     // cause problems when they are unloaded.
    4.     //
    5.  
    6.     {
    7.         PLDR_DATA_TABLE_ENTRY Entry;
    8.         PLIST_ENTRY Head,Next;
    9.  
    10.         Head = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
    11.         Next = Head->Flink;
    12.  
    13.         while ( Next != Head ) {
    14.             Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
    15.             Entry->LoadCount = 0xffff;
    16.             Next = Next->Flink;
    17.         }
    18.     }
    Код (Text):
    1.             //
    2.             // Since this DLL has TLS, lock it in
    3.             //
    4.  
    5.             Entry->LoadCount = (USHORT)0xffff;
    Код (Text):
    1.         //
    2.         // Now that we have the data table entry, unload it
    3.         //
    4.  
    5.         if ( LdrDataTableEntry->LoadCount != 0xffff ) {
    6.             LdrDataTableEntry->LoadCount--;
    7.             if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL ) {
    8.                 LdrpDereferenceLoadedDll(LdrDataTableEntry);
    9.                 }
    10.         } else {
    11.  
    12.             //
    13.             // if the load count is 0xffff, then we do not need to recurse
    14.             // through this DLL's import table.
    15.             //
    16.             // Additionally, we don't have to scan more LoadCount == 0
    17.             // modules since nothing could have happened as a result of a free on this
    18.             // DLL.
    19.  
    20.             goto leave_finally;
    21.         }
     
  18. sysexit

    sysexit New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2010
    Сообщения:
    176
    Когда вручную загружаю свою DLL, то все она нормально выгружается FreeLibrary.

    В ручную загруженая user32.dll не выгружается никак. В чем дело?

    Проверил тоже самое только вместо user32.dll использовал comctl32.dll, с она нормально выгружается FreeLibrary. Получается некоторые системные dll не выгрузить?
     
  19. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    sysexit
    Проблемы с переводом #17 ?
    Второй приведённый код лочит статически подгруженные модуля.
     
  20. sysexit

    sysexit New Member

    Публикаций:
    0
    Регистрация:
    27 авг 2010
    Сообщения:
    176
    Ну честно говоря да проблемы с английским, хотелось бы человеческий ответ услышать прямой, а не подсказки далекие.

    Блокируется выгрузка только user32.dll или еще каких то dll?