进程对象在Mono中不起作用

时间:2015-11-12 16:21:18

标签: bash mono

我尝试运行一个简单的命令转义但没有响应,没有输出缓冲区,但如果我删除" $"符号效果很好。我该怎么办?

public class Executor
{
    private Process proc;

    public Executor ()
    {
        this.proc = new Process();
        this.proc.StartInfo.UseShellExecute = false;
        this.proc.StartInfo.RedirectStandardError = true;
        this.proc.StartInfo.RedirectStandardInput = true;
        this.proc.StartInfo.RedirectStandardOutput = true;
    }

    public String call(String command){
        this.proc.StartInfo.FileName = "/bin/bash";
        this.proc.StartInfo.Arguments = "-c $'" + stringToHexEscape(command) + "'";

        this.proc.Start();
        String result = this.proc.StandardOutput.ReadToEnd ();
        this.proc.WaitForExit();
        this.proc.Close ();

        return result;
    }

    public String stringToHexEscape(String buffer){
        byte[] ba = Encoding.Default.GetBytes(buffer);
        String hexString = BitConverter.ToString(ba);
        if (String.IsNullOrEmpty (hexString))
            return "";
        return ("\\x" + hexString.Replace("-", "\\x")).Trim();
    }
}

在命令中尝试:

Executor executor = new Executor ();
String result = this.executor.call (
    "[ -f ~/.ssh/id_rsa.pub ] && echo \"Found\" || echo \"Not found\""
);
Console.WriteLine("stdout: {0}", result);

但结果是空字符串。从bash工作正常:

me@Unknow:~$ /bin/bash -c $'echo \x61'
a

1 个答案:

答案 0 :(得分:0)

针对已修改的问题进行了更新:

手头的核心问题是子进程I / O std / err重定向到父进程。如果您将其设置为true,则可以通过UseShellExecute查看:

Process.StartInfo.UseShellExecute = true;

你将能够想要你正在尝试'执行',但实际上你正在使用内置函数进行bash评估。当然,在这种情况下你不能使用shell重定向,因为Process类是不可能的。创建一个使用UseShellExecute = true但没有重定向的控制台测试应用程序,您将看到您的评估按预期工作,现在您只需捕获该输出。

有很多方法,很多人使用BASHISM技术,例如使用coproc和/或其他子进程输出重定向(即使用exec创建另一个输出并重定向子输出。)哪种方式更好? ...如果你在你的应用程序中不断地这样做,有些人会说使用posix shell,它不像dash那样进行子进程替换...但是再次,个人偏好。

这是我多次使用的pipe技术,因为我不必更改(破解)我的bash评估字符串,只是重定向我感兴趣捕获的一些(或全部)输出

顺便说一下:也许我错过了什么。至于阻止injections,具有进程权限的任何人都可以strace任何系统调用,包括这些调用,从而观察您的shell / bash调用,并通过gdb对这些进程进行代码注入...

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;

namespace consoleEcho
{
    class MainClass
    {
        [DllImport ("libc")]
        private static extern int system (string exec);

        public static void Main (string[] args)
        {
            Process.Start ("mkfifo", "/tmp/fifo");

            system (" [ -f ~/.ssh/id_rsa.pub ] && echo 'Found' >/tmp/foobar || echo 'Not found' >/tmp/foobar ");

            var proc = new Process ();
            proc.StartInfo.FileName = "cat";
            proc.StartInfo.Arguments = "/tmp/foobar";
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.RedirectStandardError = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.Start();
            String result = proc.StandardOutput.ReadToEnd ();
            proc.WaitForExit();
            proc.Close ();
            Console.WriteLine(result);

            Process.Start ("rm", "/tmp/fifo");
        }
    }
}

外壳输出:

Not found

(我的ssh文件不在标准位置......)

问题更新前的原文:

当你已经进入一个时,你正在开始一个新的bash / shell解释器,即:

bash -c echo -e '\x61'

bash -c echo $'\x61'

从bash的CLI运行时,两者都返回一个空字符串。

跳过第二个解释器并直接调用echo:

        proc.StartInfo.FileName = "echo";
        proc.StartInfo.Arguments = " '\x61' ";

剪切/粘贴示例:

using System;
using System.Diagnostics;

namespace consoleEcho
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            Process proc = new Process();
            proc.StartInfo.FileName = "echo";
            proc.StartInfo.Arguments = " '\x61' ";
            proc.StartInfo.UseShellExecute = false; 
            proc.StartInfo.RedirectStandardError = true;
            proc.StartInfo.RedirectStandardInput = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.Start();
            var output = proc.StandardOutput.ReadToEnd ();
            Console.WriteLine("stdout: {0}", output);
        }
    }
}