Можно ли подделать консоль windows api? - PullRequest
11 голосов
/ 26 октября 2011

Я написал ssh-сервер на c # и подумал, что было бы неплохо подключить powershell как оболочку. Я попробовал 2 метода, чтобы заставить это работать должным образом, но оба далеко не совершенны. Вот что я попробовал:

  1. Запустите powershell.exe и перенаправьте его стандартный (вход / выход). Это не работать хорошо, так как powershell.exe обнаруживает, что он перенаправлен, изменения это поведение. Более того, он ожидает, что входные данные на стандартный, а не команды. Так что он использует API консоли для чтения команд.
  2. Host powershell в приложении-оболочке. Это имеет преимущество возможность обеспечить "консольную" реализацию для powershell (через PSHostRawUserInterface). Это работает лучше, но вы все равно можете вызвать команды (в основном настоящие консольные приложения) типа "... | more", ожидающие чтобы иметь возможность использовать API консоли, а затем попробуйте прочитать из консоль процесса оболочки.

Итак, я хотел бы, чтобы набор функций заменил обычные консольные функции ввода / вывода, используемые консольными приложениями, чтобы я мог с ними справиться. Но это кажется довольно радикальным с точки зрения того, чтобы быть плохой дизайнерской идеей (imo).

Сейчас у меня идея манипулировать консолью, посылая соответствующие ключи с собственными функциями / Pinvoke, такими как WriteConsoleInput. Я понимаю, что возможно было бы подделать консоль таким образом. Но я не понимаю, как бы я тогда «прочитал», что происходит на консоли.

Также имейте в виду, что это служба, поэтому желательно, чтобы она не вызывала реальное окно консоли, хотя, возможно, в сеансе Windows 0 это не будет отображаться и не имеет значения.

Ответы [ 2 ]

3 голосов
/ 26 октября 2011

Для этого у вас есть PSSession и CmdLet Enter-PSSession.Что будет делать ваш SSH с Powershell, чего не делает PSSession?

Но если вы хотите сделать это, вот решение без написания чего-либо: Использование PowerShell через SSH


Отредактировано 02.11.2011

PowerShell внутри предоставляет еще один способ сделать это без записи чего-либо (бесплатно для личного использования).

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

1 голос
/ 16 ноября 2011

Я установил PowerShellInside в соответствии с предложением JPBlanc, но не использовал его очень долго. Одна вещь, связанная с подключением, слишком ограничивающая, и мне не нравится, когда ее ограничивают (особенно если это ограничение основано на прибыли, но это совершенно другое обсуждение, в которое я не должен вступать). И несмотря на то, что это решение исходной проблемы, оно кажется неудовлетворительным, потому что не решает проблему программирования, с которой я столкнулся.

Однако мне в конечном итоге удалось решить указанную проблему, действительно, используя вызовы windows api в процессе обертки. Поскольку ловушек довольно много, я решил ответить на свой вопрос и дать другим людям, которые смотрят на ту же проблему, несколько указателей. Основная структура выглядит следующим образом:

  • Запустите процесс оболочки с помощью перенаправленного stdin / -out (и stderr, если хотите). (В моем случае stdin и out будут потоками управляющих последовательностей и данных xterm, потому что это путь ssh)
  • Использование GetStdHandle () возвращает перенаправленные маркеры ввода и вывода. Далее SetStdHandle () для CreateFile () из «CONIN $» и «CONOUT $», так что дочерние процессы наследуют консоль и не имеют перенаправлений процесса-оболочки. (Обратите внимание, что для createfile необходим дескриптор безопасности, разрешающий наследование)
  • Настройка режима консоли, размера, заголовка, обработчиков Ctrl-C и т. Д. Примечание: не забудьте установить шрифт, если вам нужна поддержка юникода, я использовал Lucida Console (.FontFamily = 54, .FaceName = "Lucida Console" ). Без этого чтение символов из вывода вашей консоли вернет кодированные версии, с которыми ужасно работать в управляемом коде.
  • Чтение вывода может быть выполнено с помощью SetWinEventHook (), обязательно используйте внеконтекстное уведомление, потому что я вполне уверен, что запуск вашего управляемого приложения в другом контексте процесса / адресном пространстве является плохой идеей ™ (Я так уверен, что даже не пытался). Событие будет запускаться для каждого окна консоли, а не только для вашего собственного. Поэтому отфильтруйте все вызовы обратного вызова по дескриптору окна. Получить дескриптор окна текущего консольного приложения с помощью GetConsoleWindow (). Также не забудьте отменить обратный вызов, когда приложение будет сделано.
  • Обратите внимание, что до этого момента не следует использовать (или делать что-либо, что вызывает загрузку) класс System.Console, иначе скорее всего все пойдет не так. Использование после этой точки будет вести себя так, как если бы подпроцесс записывал в вывод.
  • Создать необходимый подпроцесс (обратите внимание, вы должны использовать .UseShellExecute = false, иначе он не будет наследовать консоль)
  • Вы можете начать ввод данных на консоль, используя WriteConsoleInput ()
  • В этот момент (или в отдельном потоке) вы должны запустить цикл сообщений Windows, иначе вы не получите обратные вызовы уведомлений о событиях консоли. Для этого вы можете просто использовать Application.Run () без параметров. Чтобы разорвать цикл сообщений, вы должны в какой-то момент опубликовать сообщение о выходе из цикла сообщений. Я сделал это с помощью Application.Exit () в событии .Exited подпроцесса. (Обратите внимание, используйте .EnableRaisingEvents, чтобы это работало)
  • Теперь будут выполняться вызовы вашего обратного вызова win, когда что-то на вашей консоли изменится. Обратите внимание на событие прокрутки, это может работать несколько неожиданно. Также не делайте предположений о синхронной доставке. Если подпроцесс записывает 3 строки, то к тому времени, когда вы обрабатываете первое событие, оставшиеся 3 строки могут быть уже записаны. Чтобы быть справедливым, Windows делает хорошую работу по составлению событий таким образом, чтобы вы не были завалены изменениями одного символа и могли не отставать от изменений.
  • Обязательно пометьте все определения PInvoke с помощью CharSet = CharSet.Unicode, если они содержат символ где-либо на входе или выходе. PInvoke.net пропустил довольно много из них.

Чистый результат всего этого: приложение-оболочка для консоли Windows API. Оболочка может читать / записывать перенаправленные stdin и stdout для связи с миром. Конечно, если вы хотите получить фантазию, вы можете использовать любой поток здесь (с именем pipe, tcp / ip и т. Д.). Я реализовал несколько управляющих последовательностей xterm и сумел получить полностью работающую оболочку терминала, которая должна быть способна обернуть любой процесс консоли Windows, преобразовать входные данные xterm во входные данные на входе консоли целевого приложения и обработать вывод приложения в управляющие последовательности xterm. Я даже заставил мышь работать. Запуск powershell.exe в качестве подпроцесса теперь решает исходную проблему запуска powershell в сеансе ssh. Cmd.exe также работает. Если кого-то заинтересует, я посмотрю о том, чтобы выложить где-нибудь полный код.

...