Как запустить программу в домене

При запуске приложения, написанного на C#, операционная система создает процесс, а среда CLR создает внутри этого процесса логический контейнер, который называется доменом приложения и внутри которого работает запущенное приложение.

Для управления домена платформа .NET предоставляет класс AppDomain . Рассмотрим некоторые основные методы и свойства данного класса:

  • Свойство BaseDirectory : базовый каталог, который используется для получения сборок (как правило, каталог самого приложения)
  • Свойство CurrentDomain : домен текущего приложения
  • Свойство FriendlyName : имя домена приложения
  • Свойство SetupInformation : представляет объект AppDomainSetup и хранит конфигурацию домена приложения
  • Метод ExecuteAssembly() : запускает сборку exe в рамках текущего домена приложения
  • Метод GetAssemblies() : получает набор сборок .NET, загруженных в домен приложения

Получим имя и базовый каталог текущего домена и выведем все загруженные в домен сборки:

Работа с локальными и доменными пользователями


using System.Reflection; AppDomain domain = AppDomain.CurrentDomain; Console.WriteLine($»Name: «); Console.WriteLine($»Base Directory: «); Console.WriteLine(); Assembly[] assemblies = domain.GetAssemblies(); foreach (Assembly asm in assemblies) Console.WriteLine(asm.GetName().Name);
Name: HelloApp Base Directory: /Users/eugene/Projects/HelloApp/HelloApp/bin/Debug/net6.0/ System.Private.CoreLib HelloApp System.Runtime System.Console System.Threading Microsoft.Win32.Primitives System.Collections System.Memory

Источник: metanit.com

Как осуществить запуск программы в Windows с правами пользователь домена, когда программа требует повышенные права?

Пользователю домена нужно запустить клиент для просмотра камеры (типа iVMS, точно не знаю как программа называется). При запуске прога требует повышение (логин и пароль). Дать пользователю админ не вариант. Какое есть решение?

  • Вопрос задан 12 окт. 2022
  • 174 просмотра

1 комментарий

Средний 1 комментарий

Ziptar

Костылить через psexec с флагом -l и безусловный запуск самого psexec от имени локального админа. От шаловливых ручек пользователя не защитит, но программе хотелки обломает, если она, конечно, вообще запустится в таком сценарии — что не факт.
В таком сценарии программа будет запускаться в контексте пользователя, являющегося локальным админом, а не в контексте пользователя домена, но с ограниченными привилегиями. Это само по себе может быть неприемлемо.

Других вариантов, кроме выдачи доменному пользователю прав локального админа на его машине, нет.

Решения вопроса 0
Ответы на вопрос 3
системный инженер

клиент для просмотра камеры

Сделать запрет на запуск программ пользователя домена


А точно этому приложению нужны права локального администратора? Возможно, оно просто пишет куда-то какие-то данные, а обычному пользователю туда доступ на запись отсутствует. Попробуйте с помощью Process Explorer посмотреть, куда приложение обращается и что требует повышенных привилегий, после чего назначьте необходимые права

Ответ написан 12 окт. 2022
Нравится 2 1 комментарий

Ziptar

Подобный говнософт обычно принудительно требует прав админа, даже если нет ни единой разумной причины для этого

Чем больше знаю, тем лучше понимаю, как мало знаю.

Решение: не использовать такую программу.

P.S. Скорее всего аналоги так же будут требовать права админа.

Источник: qna.habr.com

Домены приложений в .NET

В современных операционных системах некий функционально законченный блок кода выполняется в специально отведенном для него адресном пространстве – процессе. Код, выполняемый внутри процесса, изолирован. Доступ к коду из другого процесса возможен только через прокси. Прокси находится в адресном пространстве вызывающего процесса и действует как заместитель удаленного объекта. С точки зрения вызывающего объекта прокси – это объект, перенаправляющий вызовы другому процессу.

В отличие от обычного, управляемый (managed) код может проверяться (верифицироваться), в том числе и на наличие потенциально небезопасных операций. Для верифицированного кода можно обеспечить гарантированную безопасность.

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

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

Читайте также:
Список литературы управление государственными программами

Этот механизм позволяет запустить группу приложений в одном процессе, обеспечивая относительную изоляцию их друг от друга, в то же время позволяя им взаимодействовать друг с другом значительно быстрее, чем в случае отдельных процессов. Этот механизм в платформе .NET получил название доменов. Как и в случае процессов для неуправляемого кода, домен позволяет повысить устойчивость системы к сбоям, так как сбой внутри одного из доменов не приводит к сбоям внутри хост-процесса и других приложений.

Попутно домены играют ещё одну вспомогательную роль. В обычных приложениях загруженную DLL можно выгрузить при помощи функции FreeLibrary. К сожалению, в CLR для сборок такой возможности не существует. Казалось бы, нет способа заменить исполняемый модуль без перезапуска процесса. Но так как домен приложений является в некоторой степени аналогом процесса, то при выгрузке домена происходит выгрузка и всех загруженных в него сборок.

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

ПРИМЕЧАНИЕ

Для взаимодействия между доменами используется инфраструктура Remoting. При этом данные передаются по специализированному каналу, предназначенному для обмена между доменами. Этот канал недокументирован и используется только для внутренних целей. Имя класса канала System.Runtime.Remoting.Channels.CrossAppDomainChannel. Обратите внимание на то, что в случае передачи по значению сборка с кодом класса должна быть доступна в обоих доменах, а при передаче по ссылке в вызывающем домене должны быть доступны метаданные.

Для каждого домена создаётся свой собственный экземпляр сборщика мусора, свои собственные настройки безопасности и собственные статические переменные.

Загрузка сборок в каждый домен происходит независимо. Таким образом, в каждом домене будет свой собственный экземпляр класса Assembly, даже если они используют одну и ту же сборку. Однако существует способ добиться того, чтобы код загружаемых сборок совместно использовался (share) разными доменами. Сборка, используемая совместно несколькими доменами, называется нейтральной по отношению к домену (domain-neutral). Режим доступа к сборкам может быть одним из трех:

  • Режим, в котором нейтральность к домену обеспечивается только для mscorlib.dll. Это поведение по умолчанию. Используется в случае однодоменного приложения.
  • Нейтральность к домену для всех сборок. Этот режим рекомендуется использовать для мультидоменных приложений, в каждом из доменов которых выполняется один и тот же код.
  • Нейтральность к домену для всех сборок со строгим (strong) именем. Этот режим рекомендуется использовать для мультидоменных приложений, в каждом из доменов которых выполняется разный код.

Способ использования сборок является компромиссом между использованием ресурсов и производительностью. Дело в том, что при разделении сборок среде исполнения необходимо обеспечить уникальность значений для статических полей. Поэтому использование общих сборок приводит к некоторой потере производительности при работе со статическими полями.

В том случае, если для каждого домена установлены свои права (permissions) выполнения кода, общее использование сборок невозможно и для каждого домена будет загружена своя копия.

Указать режим доступа можно при создании домена, передав в качестве параметра экземпляр класса AppDomainSetup, у которого свойство LoaderOptimization установлено определенным образом. Это свойство может принимать следующие значения:

Значение Описание
NotSpecified Использовать оптимизацию, заданную хост-процессом или оптимизацию по умолчанию (SingleDomain).
SingleDomain Указывает, что приложение, скорее всего, будет содержать только один домен, и в разделении кода сборок нет необходимости.
MultiDomain Указывает, что приложение содержит много доменов с одинаковым кодом, и загрузчик будет пытаться сделать по возможности общими все ресурсы.
MultiDomainHost Указывает, что, скорее всего, приложение будет содержать несколько доменов с уникальным кодом, и загрузчик обеспечит разделяемый доступ к сборкам со строгим именем.

Не существует какой-либо определенной связи между потоками операционной системы (threads) и доменами. Домен может порождать любое количество потоков, так же как поток может перейти к выполнению кода не в том домене, который его создал. Для каждого потока можно определить, в каком домене он в текущий момент выполняется, вызвав Thread.GetDomain(). Внутри потока текущий домен можно получить из свойства AppDomain.CurrentDomain.

Читайте также:
Как выделить приоритет программе

Работа с доменами

Для представления домена в программе служит специальный класс – AppDomain. Этот класс позволяет создавать и выгружать домены (завершать их работу), а также получать о них информацию и управлять ими.

Создание домена

Создать домен можно при помощи вызова AppDomain.CreateDomain(). Этот метод перегружен, и позволяет задавать помимо имени домена права доступа и настройки. В настройках можно указать файл конфигурации, разрешить теневое копирование сборок, определить каталог запуска приложения и многое другое. Пример создания домена приведён ниже:

AppDomain newDomain = AppDomain.CreateDomain(«NewDomain»);

Кроме того, домен можно создать из неуправляемого приложения. Для этого используется основанный на COM API, предоставляемый CLR.

Создание объектов

Создать объект внутри домена можно при помощи вызова AppDomain.CreateInstanceFrom(). Метод возвращает ссылку на специальный объект-обертку. Пользоваться такой оберткой напрямую нельзя. Для этого сначала нужно получить ссылку на прокси. Сделать это можно, вызвав ObjectHandle.Unwrap или сразу использовав метод CreateInstanceFromAndUnwrap.

AppDomain newDomain = AppDomain.CreateDomain(«NewDomain»); MBRClass mbrcls = (MBRClass)newDomain.CreateInstanceFromAndUnwrap(«myasm.dll», «MBRClass»);

Существует также возможность запустить внутри домена сборку, содержащую точку входа (проще говоря, исполняемый (.exe) файл .NET). Для этого нужно вызвать метод AppDomain.ExecuteAssembly.

AppDomain newDomain = AppDomain.CreateDomain(«NewDomain»); newDomain.CreateInstanceFromAndUnwrap(«myapp.exe»);

Выгрузка домена

Ненужный домен можно выгрузить, для этого достаточно вызвать метод AppDomain.Unload. Схема выгрузки при этом следующая. Если поток, вызвавший Unload, находится в том домене, который подлежит выгрузке, то для выгрузки будет создан другой поток.

Если домен не может быть выгружен, то исключение CannotUnloadAppDomainException будет возбуждено именно в этом потоке, а не в потоке, вызвавшем Unload. Однако если поток, вызвавший Unload, находится за пределами выгружаемого домена, этот поток получит исключение.

Потоки внутри домена при его выгрузке будут завершены при помощи метода Thread.Abort().

События, генерируемые доменом

У домена есть несколько очень важных событий. Вот их краткое описание:

Событие Описание
AssemblyLoad Вызывается при загрузке каждой сборки.
AssemblyResolve Вызывается, если стандартный алгоритм не смог найти сборку. Это событие позволяет загрузить сборку самостоятельно из любого хранилища. Следует быть внимательным, так как повторная загрузка одной и той же сборки не контролируется.
ResourceResolve Вызывается, если в ресурсах не обнаружен требуемый ресурс. Позволяет загрузить ресурс самостоятельно
TypeResolve Вызывается, если не удалось определить, в какой сборке находится запрашиваемый тип, и позволяет загрузить его самостоятельно.
UnhandledException Вызывается в случае необработанного исключения (не перехваченного прикладным кодом).
ProcessExit Вызывается, если завершается процесс. Позволяет принудительно освободить используемые неуправляемые ресурсы, удалить временные файлы и т.д.
DomainUnload Вызывается, если произошла выгрузка домена.

Теневое копирование файлов

Когда сборка загружается в домен, то файл сборки оказывается заблокированным и удалить его уже нельзя. Для того чтобы этого избежать существует специальный механизм теневого копирования. Суть его в том, что перед загрузкой сборка копируется во временный каталог и только оттуда загружается. При этом оригинальный файл сборки оказывается незаблокированным и его можно заменить.

Включить этот механизм можно только до загрузки первой сборки. Для этого нужно установить свойство AppDomain.ShadowCopyFiles в true, или, при создании, передать в качестве параметра экземпляр класса AppDomainSetup с соответствующим свойством, установленным в true.

Практика

Утилита запуска приложений в домене

Давайте попробуем создать утилиту, которая будет запускать .NET-приложения в отдельном домене, но внутри одного процесса.

Для начала создадим класс DomainManager, который будет заниматься управлением доменами. За запуск приложения будет отвечать его метод RunApp(string fname), которому нужно передать имя файла сборки, содержащей запускаемое приложение.

Создадим домен и добавим его во внутренний список:

AppDomain dom = AppDomain.CreateDomain(fname); domains.Add(dom);

Затем нам необходимо внутри домена запустить код приложения. Для этого создадим вспомогательный класс. Вот его код:

using System; namespace RSDN.NETShell < publicclass DomainRunner : MarshalByRefObject < privatestring executeAssembly; publicstring ExecuteAssembly < get return executeAssembly;> set > publicvoid Run() < //Запускаем приложение AppDomain.CurrentDomain.ExecuteAssembly(ExecuteAssembly); > > >

Читайте также:
Альбом что тебе нравится к программе я ты мы

Обратите внимание на то, что этот объект унаследован от MarshalByRefObject, а значит, передаваться будет по ссылке. Это означает, что код его методов будет выполняться в том домене, в котором этот объект создан, а в других доменах он будет представлен прокси-объектом, перенаправляющим вызовы к основному объекту.

Создадим экземпляр этого класса и укажем ему сборку с приложением:

DomainRunner dr = (DomainRunner)dom.CreateInstanceFromAndUnwrap( «netshell.exe», «RSDN.NETShell.DomainRunner»); dr.ExecuteAssembly = fname;

Метод AppDomain.CreateInstanceFromAndUnwrap создает экземпляр запрошенного класса, находящегося в сборке с указанным именем, и возвращает ссылку на его прокси.

Чтобы не тормозить основной поток на время работы приложения, будем производить запуск в отдельном потоке. Так как передать параметры делегату потока нельзя, создадим вспомогательный внутренний класс.

private class AppRunControl < private DomainManager parent; private DomainRunner domainRunner; private AppDomain domain; public AppRunControl(DomainManager prnt, DomainRunner dr, AppDomain dm) < parent = prnt; domainRunner = dr; domain = dm; >publicvoid Run() < domainRunner.Run(); parent.TerminateApp(domain); >>

В методе Run этого класса мы вызываем метод Run экземпляра DomainRunner, а по его завершении выгружаем домен.

Создадим и запустим поток.

AppRunControl rc = new AppRunControl(this, dr, dom); Thread rt = new Thread(new ThreadStart(rc.Run)); rt.Start();

Для оповещения при изменении списка доменов создадим событие, и метод, вызывающий это событие.

public event EventHandler DomainListChanged; protectedvirtualvoid OnDomainListChanged() < if(DomainListChanged != null) DomainListChanged(this, EventArgs.Empty); >

По завершению запуска приложения вызовем метод OnDomainListChanged().

Для остановки приложения создадим метод TerminateApp().

public void TerminateApp(AppDomain domain)

Сравнение расхода памяти

Сравним расход памяти при запуске приложений внутри домена и отдельными процессами. Будем запускать последовательно экземпляры приложения, и сравнивать занимаемую ими память по показаниям Task Manager.

Кол-во экз.Способ запуска Отдельный процесс Один процесс
1 9.1 9.1
2 18.2 16.8
3 27.2 18.4
4 36.2 19.9
5 45.2 21.9

Как мы видим, при запуске 1-2 приложений расход памяти почти одинаков, однако далее разница становится все больше и больше, и уже при 5 запущенных экземплярах расход уменьшается более чем в 2 раза.

Тестирование времени доступа

Давайте сравним время доступа при прямом вызове, вызове через границу домена и при вызове через границу процесса.

Сначала создадим тестовый класс с единственным методом.

using System; namespace RSDN.NETShell < publicclass TestClass : MarshalByRefObject < publicint TestMethod(int par1, byte[] par2, string par3) < return 0; > > >

Потом сделаем нашу утилиту remoting-сервером.

ChannelServices.RegisterChannel(new TcpChannel(888)); RemotingConfiguration.RegisterWellKnownServiceType ( typeof(TestClass),»TestClass»,WellKnownObjectMode.Singleton);

Затем напишем тест, последовательно измеряющий скорость трех вариантов доступа.

string[] res = newstring[4]; res[0] = «Running test . «; constint iterCount = 100000; int st; TestClass tc = new TestClass(); st = Environment.TickCount; for(int i = 0; i < iterCount; i++) tc.TestMethod(55, newbyte[20], «Test string»); res[1] = «Direct call » + (Environment.TickCount — st).ToString() + » ms»; AppDomain dom = AppDomain.CreateDomain(«test»); tc = (TestClass)dom.CreateInstanceAndUnwrap(«netshell», «RSDN.NETShell.TestClass»); tc.TestMethod(0, null, null); st = Environment.TickCount; for(int i = 0; i < iterCount; i++) tc.TestMethod(55, newbyte[20], «Test string»); res[2] = «Crossdomain call » + (Environment.TickCount — st).ToString() + » ms»; tc = (TestClass) Activator.GetObject(typeof(TestClass), «tcp://localhost:888/TestClass»); tc.TestMethod(0, null, null); st = Environment.TickCount; for(int i = 0; i < iterCount; i++) tc.TestMethod(55, newbyte[20], «Test string»); res[3] = «Crossprocess call » + (Environment.TickCount — st).ToString() + » ms»; textBox.Lines = res;

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

Результаты работы теста.

Running test . Direct call 20 ms Crossdomain call 5649 ms Crossprocess call 66866 ms

Выводы

Из проведенных тестов можно сделать следующие выводы:

  • Использование нескольких доменов внутри одного процесса вместо нескольких процессов приводит к существенной экономии ресурсов и существенно повышает скорость взаимодействия.
  • Скорость взаимодействия между доменами значительно ниже вызовов внутри домена, следовательно, объем данных, передающихся через границу домена, надо стараться сделать как можно меньше;
  • Скорость взаимодействия между процессами значительно ниже скорости взаимодействия между доменами внутри одного процесса.

Делать выводы из всего описанного выше предоставляю вам, уважаемый читатель.

Эта статья опубликована в журнале RSDN Magazine #1-2003. Информацию о журнале можно найти здесь

Источник: www.rsdn.org

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru