информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Где водятся OGRыВсе любят медАтака на Internet
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
 Умер Никлаус Вирт 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / operating systems
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Даже если "забить" всю память это не поможет. 25.08.05 18:45  Число просмотров: 2613
Автор: leo <Леонид Юрьев> Статус: Elderman
<"чистая" ссылка>
Даже если "забить" всю память это не поможет.

Пока dll подгружена хотя-бы одним процессом, она отображена на память, dll-файл открыт и его неполучится удалить или изменить. Чтобы это было возможно dll не должна иметь разделяемых секций, например иметь одну не-константную секцию с кодом/данными. Простейший способ - упаковать dll каким-нибудь exe-упаковщиком.

Другой вариант -- с помощью отладочных привилегий вмешаться в работу процесса использующего dll, разорвать отображение на dll и сделать копии страниц.

Но лучше "просто" отобразить dll в свою память, сделав работу загрузчика.
<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-серверы для которых нет активных объектов. Другими словами, просто чистится кэш.
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 1 s   Design: Vadim Derkach