Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
| | | | |
дык - это старая тема :) 26.08.05 19:29 Число просмотров: 2752
Автор: NKritsky <Nickolay A. Kritsky> Статус: Elderman
|
Он конечно выгружает длл, но файловые секции остаются закэшироваными в RAM. Но не на уровне объектов типа "dll" а уже на уровне своппера, как физические страницы. Тут z0 может лучше разъяснит :) с упоминанием всех ntdll!ZwXXX и ntdll!IoXXX функций. Тема эта лечится походу только изменением last modification time на файле. утилита touch, или просто F4->F2->Esc в фаре.
|
<operating systems>
|
[NT] выгрузить dll из памяти 25.08.05 13:17
Автор: Woland Статус: Незарегистрированный пользователь
|
как известно, после вызова FreeLibrary, даже если ни один процесс больше не использует библиотеку, она всё равно "висит" в памяти. есть ли возможность полностью выгрузить одну-единственную dll, так, чтобы при последующем вызове LoadLibrary она в любом случае загружалась из файла?
всё, что нарыл в инете - так это информация о ключе HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AlwaysUnloadDll, параметр default = 1 которого, заставляет систему выгружать ВСЕ неиспользуемые dll. а как быть, если надо выгрузить всего одну?
единственное, что пришло на ум - это занять и освободить весь имеющийся объём свободной физической памяти.
есть ли более гуманные способы?
заранее благодарен за ответы.
|
|
всем спасибо, createfile/closehandle замечательно работает... :) 01.09.05 07:11
Автор: Woland Статус: Незарегистрированный пользователь
|
|
|
вовсе нет 25.08.05 20:05
Автор: z0 <z0> Статус: Member
|
> как известно, после вызова FreeLibrary, даже если ни один > процесс больше не использует библиотеку, она всё равно > "висит" в памяти
это не так. если ни один процесс не прилинкован к этой длл статически и количество
LoadLibrary == FreeLibrary то длл не "висит" в памяти а полностью выгружается т.е.
ZwUnmapViewOfFile() -> ZwClose(секция) -> ZwClose(файл)
могу показать на примере или смотрите код ntdll!LdrUnloadDll()
|
| |
по всей видимости, Вы правы. 26.08.05 09:09
Автор: Woland Статус: Незарегистрированный пользователь
|
> это не так. если ни один процесс не прилинкован к этой длл
по всей видимости, Вы правы.
специально написал программу, вызывающую из длл функцию типа int test (int Arg) { return (Arg+5);}
после исследования в софтайсе (правил непосредственно в памяти аргумент вызова и константу в возвращаемом значении) выяснилось, что при каждом запуске код в длл возвращался к исходному виду, а код самого ехе - модуля оставался с изменениями. по всей видимости, в этом всё дело.
объясню ситуацию. имеются два процесса - А и В, написанные сторонними разработчиками. процесс В после запуска А проверяет в памяти его целостность (контрольную сумму) и внедряет свою длл через CreateRemoteThread и LoadLibrary. длл при запуске - распаковывается и выполняет кучу разных проверок. после завершения А при его повторном запуске В выдаёт ошибку - "нарушение целостности". я думал, что вся проблема в том, что в памяти остаётся распакованная (соответственно, контрольная сумма другая) внедрённая длл. теперь же склонен считать, что проблема в том, что при повторном запуске сохраняются изменения, сделанные В при внедрении кода (VirtualAllocEx и WriteProcessMemory).
есть какие-нибудь способы избежать этого?
|
| | |
пофиксить багу 26.08.05 14:35
Автор: z0 <z0> Статус: Member
|
> есть какие-нибудь способы избежать этого?
поточнее плиз. итак запускается А, он запускает В, затем А внедряет в В некую длл,
которая проверяет в адресном пространстве В нечто и принимает решение
я так понял после завершения В и последующего завершения А производится перезапуск
А который в свою очередь перезапускает В, снова внедряет в В длл которая принимает
на этот раз некорректное решение, так? а если между этими событиями машину ребутнуть
то все Ок?
в этом случае скорее всего речь идет о баге в длл, конкретно в процедуре принятия
решения. исправляйте или жалуйтесь разработчику
|
| | | |
всё немного не так. 26.08.05 17:54
Автор: Woland Статус: Незарегистрированный пользователь
|
> поточнее плиз. итак запускается А, он запускает В, затем А > внедряет в В некую длл, > которая проверяет в адресном пространстве В нечто и > принимает решение
если А и В поменять местами - то всё верно.... :)
> А который в свою очередь перезапускает В, снова внедряет в
В (который у Вас в данном случае А :) ) ничего не перезапускает. он сидит и ждёт, когда другой процесс будет запущен.
> событиями машину ребутнуть > то все Ок?
ребутить не обязательно. можно запустить несколько копий фотошопа, например, хорошо ещё помогает нечто вроде:
MEMORYSTATUS mst;
GlobalMemoryStatus(&mst);
PVOID pvMem = VirtualAlloc(NULL, mst.dwTotalPhys,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
ZeroMemory(pvMem, mst.dwTotalPhys);
VirtualFree(pvMem, NULL, MEM_RELEASE);
> в этом случае скорее всего речь идет о баге в длл,
как я уже говорил, в тестовой программе (да и в любой другой) после изменения её дебагером (по крайней мере, в секции с кодом, с данными не проверял), и последующего перезапуска - загрузится именно изменённая копия. т.е., если пофиксить условный переход в проверке вида
bool a = true;
if (a == true) return 2; else return 3; , то при следующем запуске (уже без отладчика) процедура вернёт 3.
так что не думаю, что речь идёт о баге в длл.
|
| | | | |
дык - это старая тема :) 26.08.05 19:29
Автор: NKritsky <Nickolay A. Kritsky> Статус: Elderman
|
Он конечно выгружает длл, но файловые секции остаются закэшироваными в RAM. Но не на уровне объектов типа "dll" а уже на уровне своппера, как физические страницы. Тут z0 может лучше разъяснит :) с упоминанием всех ntdll!ZwXXX и ntdll!IoXXX функций. Тема эта лечится походу только изменением last modification time на файле. утилита touch, или просто F4->F2->Esc в фаре.
|
| | | | | |
точно 29.08.05 17:55
Автор: z0 <z0> Статус: Member
|
> Он конечно выгружает длл, но файловые секции остаются > закэшироваными в RAM. Но не на уровне объектов типа "dll" а > уже на уровне своппера, как физические страницы. Тут z0 > может лучше разъяснит :) с упоминанием всех ntdll!ZwXXX и > ntdll!IoXXX функций. Тема эта лечится походу только > изменением last modification time на файле. утилита touch, > или просто F4->F2->Esc в фаре.
спасибо хоть ты объяснил о чем идет речь
это действительно проблема и проблема иногда не имеющая решения, сам недавно
наступал на нее. смысл такой - если на странице памяти стоит атрибут READ-ONLY, то
изменения этой страницы под отладчиком (в данном случае речь идет именно о
kernel-mode отладчике - ну например софтайсе) не приводят к соответсвующему
сигналу в кеш что страница изменена (dirty) поэтому кеш будет считать что страница
никогда не изменялась и будет ее подсовывать без перезагрузки из файла.
для юзер-моде страниц решение весьма простое - VirtualProtect с протектом 4 или 40 и
все Ок, а вот для kernel-mode страниц придется поизвращаться поскольку ZwVirtualProtect
НЕ экспортируется ntoskrnl.exe
в данном конкретном случае изменение файла dll может помочь. ну например убедившись
что ссылок на длл нет CreateFile(GENERIC_READ | GENERIC_WRITE) и CloseHandle
|
| | | | | | |
речь как раз не об отладчике 30.08.05 15:49
Автор: Woland Статус: Незарегистрированный пользователь
|
> спасибо хоть ты объяснил о чем идет речь
:))
> речь идет именно о > kernel-mode отладчике - ну например софтайсе) не приводят к
речь как раз не об отладчике. по всей видимости, если один процесс меняет содержимое памяти другого через WriteProcessMemory - получаем ту же самую картину. другого объяснения я не вижу.
> что ссылок на длл нет CreateFile(GENERIC_READ | > GENERIC_WRITE) и CloseHandle
ок. спасибо. если это действительно единственное решение в данной ситуации - будем пробовать..
|
| | | | | | | |
[UPD]MSDN/CreateFileMapping 30.08.05 16:00
Автор: Killer{R} <Dmitry> Статус: Elderman Отредактировано 30.08.05 19:13 Количество правок: 1
|
Цитата из ремарок:
A mapped file and a file accessed by means of the input and output (I/O) functions (ReadFile and WriteFile) are not necessarily coherent.
Так что это документировано.. Если я конечно понял то о чем речь в этом тредею
[UPD]
Соответственно чтобы чтото записать в файл, который был когдато промаплен в память (а длл именно мапится), так чтобы изменения отразились, полагаю надо просто открыть мапу с PAGE_READWRITE на этот файл и записать в нее.
|
| | | | | | |
Не экспортируется потому, что такой функции нет в ядре 30.08.05 11:47
Автор: amirul <Serge> Статус: The Elderman
|
> для юзер-моде страниц решение весьма простое - > VirtualProtect с протектом 4 или 40 и > все Ок, а вот для kernel-mode страниц придется > поизвращаться поскольку ZwVirtualProtect > НЕ экспортируется ntoskrnl.exe
lkd> x nt!zw*virtual*
8050bc4e nt!ZwQueryVirtualMemory = <no type information>
8050c40a nt!ZwWriteVirtualMemory = <no type information>
8050b672 nt!ZwLockVirtualMemory = <no type information>
8050b4a6 nt!ZwFlushVirtualMemory = <no type information>
8050c32e nt!ZwUnlockVirtualMemory = <no type information>
8050b4e2 nt!ZwFreeVirtualMemory = <no type information>
8050bcee nt!ZwReadVirtualMemory = <no type information>
8050afba nt!ZwAllocateVirtualMemory = <no type information>
8050b91a nt!ZwProtectVirtualMemory = <no type information>
---
Более того, kernel32!VirtualProtect() - просто stub для kernel32!VirtualProtectEx(), а тот в свою - stub для ntdll!NtProtectVirtualMemory(), который в свою очередь является просто гейтом в nt!NtProtectVirtualMemory()
Это все легко видно в отладчике.
|
| | | | | | | |
ну блин совсем уже нету? 01.09.05 18:15
Автор: z0 <z0> Статус: Member
|
> Более того, kernel32!VirtualProtect() - просто stub для > kernel32!VirtualProtectEx(), а тот в свою - stub для > ntdll!NtProtectVirtualMemory(), который в свою очередь > является просто гейтом в nt!NtProtectVirtualMemory() > > Это все легко видно в отладчике.
ну это правильно, а дальше-то что? что ж ты дальше не посмотрел?
ntdll!NtProtectVirtualMemory (или Zw* что одно и тоже) что вызывает?
правильно, уходит в ядро в функцию какую-то неэкспортируемую
подгрузи символы и увидишь ее название - _ZwProctectVirtualMemory
и не говори после этого что ее нет в ядре
такие все блин грамотные пошли, ну как ядро может в принципе жить без такой
функции подумай, а что MS-девелоперы не экспортировали ее - это свинство и здорово
ограничивает возможности драйверов по управлению useraddressspace
раз ты так все хорошо видишь в отладчике то посмотри как загружается в каждый
новый процесс ntdll.dll - кое что новое узнаешь
|
| | | | | | | | |
Что значит "дальше не посмотрел"? Дальше (после... 02.09.05 12:28
Автор: amirul <Serge> Статус: The Elderman Отредактировано 02.09.05 12:29 Количество правок: 1
|
> > Более того, kernel32!VirtualProtect() - просто stub > для > > kernel32!VirtualProtectEx(), а тот в свою - stub для > > ntdll!NtProtectVirtualMemory(), который в свою очередь > > является просто гейтом в nt!NtProtectVirtualMemory() > > > > Это все легко видно в отладчике.
> ну это правильно, а дальше-то что? что ж ты дальше не > посмотрел?
Что значит "дальше не посмотрел"? Дальше (после nt!NtProtectVirtualMemory) валидирование аргументов и уход в nt!MiProtectVirtualMemory(). Только это уж точно к делу не относится. Или надо смотреть ЕЩЕ дальше?
> ntdll!NtProtectVirtualMemory (или Zw* что одно и тоже) что > вызывает? > правильно, уходит в ядро в функцию какую-то > неэкспортируемую > подгрузи символы и увидишь ее название - > _ZwProctectVirtualMemory > и не говори после этого что ее нет в ядре
Название этой функции я написал выше. Это nt!NtProtectVirtualMemory() (она не экспортируется, но речь то не о ней, ты ее вообще не упоминал), а функции ZwVirtualProtect() ни в ядре, ни в юзерспейсе действительно нет.
> такие все блин грамотные пошли, ну как ядро может в > принципе жить без такой
Давай не будем меряться письками, скажи просто в чем проблема?
> функции подумай, а что MS-девелоперы не экспортировали ее - > это свинство и здорово > ограничивает возможности драйверов по управлению > useraddressspace
Во-первых это очень редко нужно, во-вторых эту функцию ОЧЕНЬ легко найти, если уж СИЛЬНО захочется.
> раз ты так все хорошо видишь в отладчике то посмотри как > загружается в каждый > новый процесс ntdll.dll - кое что новое узнаешь
Не понял о чем ты. Просвети уж
|
| | | | | | | | | |
да конечное Nt а не Zw чего-то я перепутал извини 06.09.05 17:44
Автор: z0 <z0> Статус: Member
|
|
| | | | | | | | | | |
Не так. Просто ты назвал эту функцию вообще неправильно (а не только префикс перепутал) 09.09.05 01:19
Автор: amirul <Serge> Статус: The Elderman
|
Если же тебя интересует как найти эту самую nt!NtProtectVirtualMemory, то рекомендую обратить внимание на экспортируемую nt!KeServiceDescriptorTable
Номер сервиса можно или вбить в код или искать например по ntdll-ному stub-у
|
|
Даже если "забить" всю память это не поможет. 25.08.05 18:45
Автор: leo <Леонид Юрьев> Статус: Elderman
|
Даже если "забить" всю память это не поможет.
Пока dll подгружена хотя-бы одним процессом, она отображена на память, dll-файл открыт и его неполучится удалить или изменить. Чтобы это было возможно dll не должна иметь разделяемых секций, например иметь одну не-константную секцию с кодом/данными. Простейший способ - упаковать dll каким-нибудь exe-упаковщиком.
Другой вариант -- с помощью отладочных привилегий вмешаться в работу процесса использующего dll, разорвать отображение на dll и сделать копии страниц.
Но лучше "просто" отобразить dll в свою память, сделав работу загрузчика.
|
|
В библиотеке COM есть специальная функция для этого, что-то... 25.08.05 18:06
Автор: Neznaika <Alex> Статус: Member
|
В библиотеке COM есть специальная функция для этого, что-то вроде "CoFreeUnusedLibraries".
Можно аккуратно посмотреть, что она делает -- далее по аналогии.
Удачи!
|
| |
Еще вариант 25.08.05 19:23
Автор: Neznaika <Alex> Статус: Member
|
Если надо сделать так, чтобы в любом случае Dll загружалась из файла - то можно каждый раз перед LoadLibrary переименовывать файл на диске. Или даже получать уникальное имя, копировать в %Temp%, и далее загружать библиотеку из %Temp%
|
| |
Если не ошибаюсь, то CoFreeUnusedLibraries() просто... 25.08.05 18:31
Автор: leo <Леонид Юрьев> Статус: Elderman
|
Если не ошибаюсь, то CoFreeUnusedLibraries() просто выгружает (посредством FreeLibrary()) все загруженные (посредством LoadLibrary()) dll-COM-серверы для которых нет активных объектов. Другими словами, просто чистится кэш.
|
|
|