是否有可能伪造Windows控制台API?

时间:2011-10-26 11:18:03

标签: c# powershell windows-console

我已经在c#中编写了一个ssh服务器,我认为将PowerShell作为shell连接是很好的。我已经尝试了两种方法来使其正常工作,但两者都远非完美。这是我尝试过的:

  1. 启动powershell.exe并重定向它的std(in / out)。事实并非如此 运行良好,因为powershell.exe检测到它被重定向,更改 这是行为。更重要的是,它期望输入数据在stdid上,而不是 命令。所以它使用控制台api来读取命令。
  2. 在“包装器”应用程序中托管powershell。这具有优势 能够为powershell提供“控制台”实现(通过 PSHostRawUserInterface)。这样做效果更好,但您仍然可以调用 命令(主要是真正的控制台应用程序),如“... | more”,这是期望的 能够使用控制台api,然后尝试从中读取 包装过程的控制台。
  3. 所以我想做的是有一组函数替换控制台应用程序使用的常规控制台输入/输出函数,所以我可以处理它们。但这似乎相当激烈,以至于成为一个糟糕的设计理念(imo)。

    现在我的想法是通过发送具有本机/ Pinvoke函数(如WriteConsoleInput)的相关键来操纵控制台。我认为有可能以这种方式伪造控制台。但我不知道如何“读取”控制台上发生的事情。

    另外请记住,这是一项服务,所以最好它不应该产生一个真正的控制台窗口,尽管可能在Windows会话0中不会出现并且无关紧要。

2 个答案:

答案 0 :(得分:3)

为此目的,你有PSSession和Enter-PSSession CmdLet。您的Powershell SSH与PSSession没有做什么?

但如果你想这样做,这是一个没有写任何东西的解决方案:Using PowerShell through SSH


已编辑02/11/2011

PowerShell inside提供另一种方式来做任何事情而不用写任何东西(免费供个人使用)。

Host03 sample,或许可以提供基本代码来执行您要执行的操作。

答案 1 :(得分:1)

我按照JPBlanc的建议安装了PowerShellInside,但是很长时间没有使用它。一个连接的东西太局限了,我不喜欢被限制(特别是如果这个限制是以利润为基础的,那就是我不应该进行的其他讨论)。尽管是原始问题的解决方案,但它感觉不尽如人意,因为它并没有解决我遇到的编程问题。

然而,我最终设法解决了这个问题,实际上是通过在包装过程中使用windows api调用。因为存在很多陷阱,所以我决定回答我自己的问题,并让其他人在一些指针上查看相同的问题。基本结构如下:

  • 使用重定向的stdin / -out(如果需要,还可以使用stderr)启动包装器进程。 (在我的情况下,stdin和out将是xterm控制序列和数据的流,因为这是ssh方式)
  • 使用GetStdHandle()检索重定向的输入和输出句柄。接下来SetStdHandle()'" CONIN $"的CreateFile()和" CONOUT $",这样子进程继承控制台并且没有包装进程的重定向。 (请注意,createfile需要一个允许继承的安全描述符)
  • 设置控制台模式,大小,标题,Ctrl-C处理程序等。注意:如果你想要unicode支持,请务必设置字体,我使用了Lucida Console(.FontFamily = 54,.FaceName = " Lucida Console")。如果没有这个,从控制台输出中读取字符将返回代码管理版本,这在托管代码中很难使用。
  • 可以使用SetWinEventHook()完成读取输出,请务必使用上下文通知,因为我非常确定托管应用程序突然在另一个进程上下文/地址空间中运行是一个错误Idea™(我确定我甚至没有尝试过)。该事件将针对每个控制台窗口触发,而不仅仅是您自己的窗口。因此,通过窗口句柄过滤对回调的所有调用。使用GetConsoleWindow()返回当前控制台应用程序的窗口句柄。在应用程序完成时也不要忘记取消回调。
  • 注意,到目前为止,请确保不要使用(或做任何导致负载的事情)System.Console类,否则很可能会出错。在此点之后的用法将表现为子进程已写入输出。
  • 生成所需的子进程(注意,必须使用.UseShellExecute = false或者它不会继承控制台)
  • 您可以使用WriteConsoleInput()
  • 开始向控制台提供输入
  • 此时(或在单独的线程上)您必须运行Windows消息循环,否则您将不会收到控制台事件通知回调。您只需使用无参数Application.Run()即可。要打破消息循环,您必须在某个时刻将退出消息发布到消息循环。我在子进程的.Exited事件中使用Application.Exit()完成了这个操作。 (注意使用.EnableRaisingEvents来实现此目的)
  • 当控制台上的内容发生变化时,现在将调用您的win事件回调。注意滚动事件,这可能有些意外。也不要假设同步传递。如果子进程写入3行,则在处理第一个事件时,可能已经写入了剩余的3行。公平地说,Windows在编写事件方面做得很好,这样你就不会对单个字符的变化感到茫然,并且可以跟上变化。
  • 如果输入或输出中包含任何字符,请确保使用CharSet = CharSet.Unicode标记所有PInvoke定义。 PInvoke.net错过了其中的一些。

所有这些的最终结果:Windows控制台api的包装器应用程序。包装器可以读/写重定向的stdin和stdout以与世界通信。当然,如果你想得到想象,你可以在这里使用任何流(命名为管道,tcp / ip等...)。我实现了一些xterm控制序列,并设法获得一个完全正常工作的终端包装器,它应该能够包装任何Windows控制台进程,将xterm输入转换为目标应用程序控制台输入上的输入并处理应用程序'输出到xterm控制序列。我甚至让鼠标工作。启动powershell.exe作为子进程现在解决了在ssh会话中运行powershell的原始问题。 Cmd.exe也有效。如果有人感兴趣,我会在某处发布完整的代码。