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

发布于 2024-12-12 03:55:50 字数 685 浏览 0 评论 0原文

我用 C# 编写了一个 ssh 服务器,我认为将 powershell 作为 shell 连接起来会很漂亮。我尝试了两种方法来使其正常工作,但这两种方法都远非完美。这是我尝试过的:

  1. 启动 powershell.exe 并将其重定向为 std(in/out)。这不 工作良好,因为 powershell.exe 检测到它被重定向,发生变化 这是行为。更重要的是,它期望 stdid 上的输入数据,而不是 命令。所以它使用控制台api来读取命令。
  2. 在“包装”应用程序中托管 powershell。这样做的好处是 能够为 powershell 提供“控制台”实现(通过 PSHostRawUserInterface)。这效果更好,但您仍然可以调用 命令(主要是真正的控制台应用程序),例如“... | more”,期望 能够使用控制台 api,然后尝试从 包装器进程的控制台。

所以我想做的是用一组函数替换控制台应用程序使用的常规控制台输入/输出函数,这样我就可以处理它们。但这似乎相当激烈,以至于成为一个糟糕的设计理念(我认为)。

现在,我的想法是通过使用 WriteConsoleInput 等本机/Pinvoke 函数发送相关键来操作控制台。我猜想也许可以通过这种方式伪造控制台。但我不知道如何“读取”控制台上发生的情况。

另请记住,它是一项服务,因此最好它不应该生成实际的控制台窗口,尽管可能在 Windows 会话 0 中不会显示并且无关紧要。

I've written a ssh server in c# and I thought it'd be neat to hook up powershell as a shell. I've tried 2 methods to get this to work properly but both are far from perfect. Here's what I've tried:

  1. Launch powershell.exe and redirect it's std(in/out). This doesn't
    work well since powershell.exe detects it is redirected, changes
    it's behaviour. What's more, it expects input data on the stdid, not
    commands. So it uses the console api to read commands.
  2. Host powershell in a "wrapper" application. This has the advantage of
    being able to provide a "console" implementation to powershell (via
    the PSHostRawUserInterface). This works better, but you can still invoke
    commands (mostly real console applications) like "... | more", that expect
    to be able to use the console api, and subsequently try to read from the
    console of the wrapper process.

So what I'd like to do is have a set of functions replace the regular console input/output functions that console applications use, so I can handle them. But that seems rather drastic to the point of being a bad design idea (imo).

Right now I am on the idea of manipulating the console by sending the relevant keys with native/Pinvoke functions like WriteConsoleInput. I gather that it might be possible to fake the console that way. But I don't see how I would then "read" what happens on the console.

Also keep in mind, it's a service, so preferably it shouldn't spawn an actual console window, although perhaps in windows session 0 that wouldn't show up and not matter.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猫性小仙女 2024-12-19 03:55:50

您已获得用于此目的的 PSSession 和 Enter-PSSession CmdLet。使用 Powershell 的 SSH 会做什么而 PSSession 不会做什么?

但如果你想这样做,这里有一个不写任何东西的解决方案: 使用通过 SSH 的 PowerShell


编辑于 2011 年 2 月 11 日

PowerShell 内部提供了另一种无需编写任何内容即可完成此操作的方法(免费供个人使用)。

Host03 示例,也许可以提供基本代码来完成您想做的事情。

You've got PSSession for this purpose and the Enter-PSSession CmdLet. What will your SSH with Powershell do that PSSession is not doing ?

But if you want to do that here is a solution whithout writting anything : Using PowerShell through SSH


Edited 02/11/2011

PowerShell inside provide another way to do it whithout writting anything (free for personal usage).

Host03 sample, can perhaps provide basic code to do what you wat to do.

红焚 2024-12-19 03:55:50

我按照 JPBlanc 的建议安装了 PowerShellInside,但没有使用很长时间。唯一的联系太有限了,我不喜欢受到限制(特别是如果这种限制是基于利润的,但那是我不应该参与的另一个讨论)。尽管它是原始问题的解决方案,但感觉并不令人满意,因为它没有解决我遇到的编程问题。

然而,我最终确实设法解决了上述问题,实际上是通过在包装器进程中使用 Windows api 调用。因为存在很多陷阱,所以我决定回答我自己的问题,并给其他看到同样问题的人一些指导。基本结构如下:

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

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

I installed PowerShellInside as suggested by JPBlanc, but didn't use it for very long. The one connection thing is just too limiting, and I don't like being limited (especially if that limitation is profit based but thats a whole other discussion i shouldn't get into). And despite being a solution to the original problem, it feels unsatisfactory because it doesn't solve the programming problem I ran into.

However, I did eventually manage to solve said problem, indeed by using the windows api calls in a wrapper process. Because there are quite a few pitfalls, I decided to anwser my own question and give others looking at the same problem some pointers. The basic structure is as follows:

  • Start the wrapper process with redirected stdin/-out (and stderr if you want). (In my case stdin and out will be streams of xterm control sequences and data, because that is the ssh way)
  • Using GetStdHandle() retrive the redirected input and output handles. Next SetStdHandle()'s to the CreateFile() of "CONIN$" and "CONOUT$", such that child processes inherits the the console and does not have the redirections of the wrapper process. (Note that a security descriptor allowing inheriting is needed for createfile)
  • Setup the console mode, size, title, Ctrl-C handler's, etc. Note: be sure to set a font if you want unicode support, I used Lucida Console (.FontFamily = 54, .FaceName = "Lucida Console"). Without this, reading the characters from your console output will return codepaged versions, which are horrible to work with in managed code.
  • Reading output can be done with the SetWinEventHook(), be sure to use out-of-context notification, because I'm pretty sure that having your managed application suddenly run in another process context/address space is a Bad Idea™ (I'm so sure that I didn't even try). The event will fire for every console window, not just your own. So filter all calls to the callback by window handle. Retrive the window handle of the current console application with GetConsoleWindow(). Also don't forget to unhook the callback when the application is done.
  • Note, upto this point be sure not to use (or do anything that causes the load of) the System.Console class, or things more than likely will go wrong. Usage after this point will behave as if the sub process had written to the output.
  • Spawn the needed sub process (Note, you must use .UseShellExecute = false or it will not inherit the console)
  • You can start providing input to the console using WriteConsoleInput()
  • At this point (or on a separate thread) you have to run a windows message loop or you will not recieve console event notification callbacks. You can simply use the parameterless Application.Run() to do this. To break the message loop, you must at some point post an exit message to your message loop. I did this with Application.Exit() in the subprocess's .Exited event. (Note use .EnableRaisingEvents for this to work)
  • Calls will now be made to your win event callback when something on your console changes. Pay attention to the scroll event, this might work somewhat unexpected. Also make no assumptions about synchronous delivery. If the sub process writes 3 lines, by the time you are processing the first event, the remaining 3 lines might already have been written. To be fair, windows does a nice job of composing events such that you don't get swamped with single character changes and can keep up with the changes.
  • Be sure to mark all PInvoke definitions with CharSet=CharSet.Unicode if they contain a character anywhere in the input or output. PInvoke.net missed quite a few of these.

The net result of all of this: a wrapper application for the windows console api. The wrapper can read/write the redirected stdin and stdout to communicate with the world. Ofcourse if you want to get fancy you could use any stream here (named pipe, tcp/ip, etc..). I implemented a few xterm control sequences and managed to get a fully working terminal wrapper that should be capable of wrapping any windows console process, translate the xterm input to input on the target application's console input and process the application's output to xterm control sequences. I even got the mouse to work. Starting powershell.exe as sub process now solves the original problem of running powershell in a ssh session. Cmd.exe also works. If anyone is interrested I'll see about posting the full code somewhere.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文