I have a project to demonstrate a program similar to the "echo" command in the MS-DOS Command Line. Here is the code in C#:
using System;
namespace arguments
{
class Program
{
static void Main(string[] args)
{
try
{
switch (args[0])
{
case "/?":
string location = System.Reflection.Assembly.GetEntryAssembly().Location;
string name = System.IO.Path.GetFileName(location);
Console.WriteLine("Displays messages\nSyntax: {0} [message]", name);
Environment.Exit(0);
break;
}
if (args.Length >= 0)
{
string x = "";
foreach (var item in args)
{
x += item.ToString() + " ";
}
Console.WriteLine(Convert.ToString(x)); // this should eliminate vulnerabilities.
}
}
catch
{
string location = System.Reflection.Assembly.GetEntryAssembly().Location;
string name = System.IO.Path.GetFileName(location);
Console.WriteLine("Displays messages\nSyntax: {0} [message]", name);
}
}
}
}
This does a pretty efficient job at doing what it's supposed to do. Then I got into trying to exploit it in any way I could.
In command prompt, I ran arguments.exe ", this is supposed to print out ". But that's not really what happened. I then tried the same with the echo command by running echo ", and it, like it's supposed to, printed out ". This is mind boggling because I wouldn't have even thought this would be a problem. I couldn't get it to pose a great threat, just confused me for a minute.
My question is, is there any way to pass the quotation mark (") as argument to this console application?
Here is a picture to demonstrate it a little bit better: http://prntscr.com/cm9yal
void Main(string[] args)
args array here contains the arguments which have been passed to your application. Because arguments may have spaces they can be surrounded by quotes.
For this reason you won't get the string you have placed as argument. You will also loose any number of spaces between quoted parameters.
If you need the raw command line string, use:
string cmdline = System.Environment.CommandLine;
To be able to get the single quote, you'll need to bypass the default parsing performed by the CLR when populating the args array. You can do this by examining Environment.CommandLine, which in the case you describe above will return something along the lines of:
ConsoleApplication1.exe \"
Note, the argument I passed was simply " (not the escaped variant shown).
Related
I have grabbed some data from a website.A string which is named as urlresult in the data is "http:\/\/www.cnopyright.com.cn\/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8&softwareType=1".
what I want to do is to get rid of the first three char #'\' in the string urlresult above . I have tried the function below:
public string ConvertDataToUrl(string urlresult )
{
var url= urlresult.Split('?')[0].Replace(#"\", "") + "?" + urlresult .Split('?')[1];
return url
}
It returns "http://www.cnopyright.com.cn/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\\u5317\\u4eac\\u6c83\\u534e\\u521b\\u65b0\\u79d1\\u6280\\u6709\\u9650\\u516c\\u53f8&softwareType=1" which is incorrect.
The correct result is "http://www.cnopyright.com.cn/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=北京沃华创新科技有限公司&softwareType=1"
I have tried many ways,but it hasn't worked.I have no idea how to get the correct result.
I think you may be misled by the debugger because there's no reason that extra "\" characters should get inserted by the code you provided. Often times the debugger will show extra "\" in a quoted string so that you can tell which "\" characters are really there versus which are there to represent other special characters. I would suggest writing the string out with Debug.WriteLine or putting it in a log file. I don't think the information you provided in the question is correct.
As proof of this, I compiled and ran this code:
static void Main(string[] args)
{
var url = #"http:\/\/www.cnopyright.com.cn\/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8&softwareType=1";
Console.WriteLine("{0}{1}{2}", url, Environment.NewLine,
url.Split('?')[0].Replace(#"\", "") + "?" + url.Split('?')[1]);
}
The output is:
http:\/\/www.cnopyright.com.cn\/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8&softwareType=1
http://www.cnopyright.com.cn/index.php?com=com_noticeQuery&method=wareList&optionid=1221&obligee=\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8&softwareType=1
You can use the System.Text.RegularExpressions.Regex.Unescape method:
var input = #"\u5317\u4eac\u6c83\u534e\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8";
string escapedText = System.Text.RegularExpressions.Regex.Unescape(input);
If I want to show something in a console I usually write it like this: Console.Write("Hello{0}", AnyNumber);.
But if I use Interaction.MsgBox and write Interaction.MsgBox("Hello {0}, AnyNumber"); I am getting an error, why is that?
I like to use placeholders like {0} a lot more than + (string concatenation) when writing, I think it is easier to write it like that...
So my question is: Why can't I use placeholders in MsgBox and is there any other way to use them?
Here is a example how I would like to use it in MsgBox:
static void multiplikation(int tal1, int tal2)
{
if (tal1*tal2 == 100)
{
Interaction.MsgBox("Hello!\nResult:\n" + (tal1 * tal2));
}
else
{
Interaction.MsgBox("Resultat:\n" + (tal1 * tal2));
}
}
static void addition(int tal1, int tal2)
{
if (tal1 + tal2 == 100)
{
Console.Write("Hello!\nResult:{0}\n", (tal1 + tal2));
}
else
{
Console.Write("Resultat:{0}\n", (tal1 + tal2));
}
}
Interaction.MsgBox receives a string as its first parameter. If you want to format a string, you have to do that yourself, and pass the formatted string to Interaction.MsgBox:
Interaction.MsgBox(string.Format("Hello!\nResult:{0}\n", (tal1 + tal2)));
On the other hand, Console.Write was written with overloads that allow the formatting to be performed inside Console.Write.
This is due to the fact that unlike Console.Write, Interaction.Msgbox does not know anything about string.Format: It just displays the string "as is".
Since C# version 6, there is a comfortable way:
Interaction.MsgBox($"Result:\n {tal1 * tal2}");
The '$' is telling the compiler to treat {tal1 * tal2} as an expression and insert the result into the string. More details about this so-called string interpolation:
With string interpolation, expressions within curly braces {} can
also be evaluated. The result will be inserted at the corresponding
location within the string. For example, to calculate the maximum of
foo and bar and insert it, use Math.Max within the curly
braces:Console.WriteLine($"And the greater one is: {
Math.Max(foo, bar) }");
Output:
And the greater one is: 42
Note: Any leading or trailing whitespace (including space, tab and CRLF/newline) between the curly brace and the expression is completely ignored and not included in the output
For all C# versions (especially the ones before C#6) you can do the following:
Instead of having to invoke string.Format every time, you can create a function like
public Microsoft.VisualBasic.MsgBoxResult MsgBox(string msg, params object[] p)
{
var fmt = string.Format(msg, p);
var msgStyle = Microsoft.VisualBasic.MsgBoxStyle.OkOnly;
return Interaction.MsgBox(fmt, msgStyle, "Information");
}
This can be used as follows:
var tal1=1; var tal2=2;
MsgBox("Hello!\nResult:{0}\n", (tal1 + tal2));
Note: This solution supports not only {0}, but also {1}, {2}, ... because I have used a params array. Hence, the following is working too:
MsgBox("Calculation: {0} + {1} = {2}", tal1, tal2, (tal1+tal2));
which outputs Calculation: 1 + 2 = 3.
You can read here (at Microsoft) more about the Interaction.MsgBox method, how to change the style of the messagebox (e.g. how to display Yes/No/Cancel buttons and about the MsgBoxResult values being returned) so you can tailor it to your needs.
This is the complete program, you can run it in LinqPad or Visual Studio:
static void Main(string[] args)
{
var tal1=1; var tal2=2;
MsgBox("Hello!\nResult:{0}\n", (tal1 + tal2));
MsgBox("Calculation: {0} + {1} = {2}", tal1, tal2, (tal1+tal2));
}
public static MsgBoxResult MsgBox(string msg, params object[] p)
{
var fmt=string.Format(msg, p);
var msgStyle= Microsoft.VisualBasic.MsgBoxStyle.OkOnly;
return Interaction.MsgBox(fmt, msgStyle, "Information");
}
Don't forget to add a reference to Microsoft.VisualBasic.dll, using the namespace Microsoft.VisualBasic in order to run this example.
If you're using LinqPad, right-click, choose "Query properties..." then add the dll in "Additional references" and the namespace in "Additional Namespace imports".
Console.WriteLine has an overloads which supports a string.Format type implementation.
http://msdn.microsoft.com/en-us/library/586y06yf(v=vs.110).aspx
As pointed out in the comments, you will need to use string.Format() to replicate that behavior for Interaction.MsgBox.
you can use the string format method http://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx
I want to pass a string to main, but I am having trouble with spaces.
I pass the string "C:\Documents and Settings\desktop\..." to the Main(string[] args) and I had:
args[0] = "C:\Documents"
args[1] = "and"
args[2] = "Settings\desktop\..."
But what I want is:
args[0] = "C:\Documents and Settings\desktop\..."
Any way to keep spaces but concatenate to one element of the string? The code should also work with any number of spaces in a given file path, not just 2 in this case.
This is typically handled by passing the arguments in quotes.
For example, if you call this as:
yourApp.exe "C:\Documents and Settings\desktop..."
You'll get the string in the first arg (args[0]).
For example, using this program:
using System;
internal class Program
{
private static void Main(string[] args)
{
foreach (var arg in args) Console.WriteLine(arg);
Console.ReadKey();
}
}
If you run this with the command line argument as:
"C:\Documents and Settings\desktop..."
(With the quotation marks in place), this will print:
C:\Documents and Settings\desktop...
If that isn't an option, and you only have a single argument, you could always join the results:
using System;
internal class Program
{
private static void Main(string[] args)
{
string argument = String.Join(" ", args);
Console.WriteLine(argument);
Console.ReadKey();
}
}
This will work without wrapping the path in quotes, but it assumes the entire path is a single path, only has one space in between "words", and has no other arguments in place. Personally, I would recommend wrapping the call in quotation marks, as it's a standard convention.
Can't you just quote the string when you call your program from the command line?
EXAMPLE: myprog "This is one argument"
namespace test
{
class Program
{
/*
* EXAMPLE: test arg1 "arg2 with spaces" arg3
* args[0]=arg1...
* args[1]=arg2 with spaces...
* args[2]=arg3...
*/
static void Main(string[] args)
{
for (int i = 0; i < args.Length; i++)
System.Console.WriteLine("args[{0}]={1}...", i, args[i]);
}
}
}
I loaded up a small console app that simply reads and prints the first command line argument passed to the program to the console.
I want to pass a newline to the argument I tried this:
prog.exe \n --> outputs \n
prog.exe "sfs \n sfff" --> outputs sfs \n sfff
prog.exe "ff \\n ff" --> outputs ff \\n ff
prog .exe "ff \\\\n ff" --> outputs ff \\\\n ff
Is there some other escaping I'm suppose to use? Or is there some function I have to call on args[0] to process escaped characters before outputting it to the console?
To clarify, I'm trying to pass a string to my program that has newlines in it. The outputting to console was being used as a test. I could have just as easily inserted a debug break line and inspect the contents of the variable.
The problem you're having is that the strings you get from the command line are not compiled. When you have string literals in your code they are compiled and this is when escape characters are processed and converted into newlines etc. You will probably have to do something like replacing all instances of "\n" in your input string with a newline character.
Edit:
From here (with minor modifications), this will compile your string using the CSharp compiler thus replacing the escape sequences with the appropriate characters:
public static string ParseString(string input)
{
var provider = new Microsoft.CSharp.CSharpCodeProvider();
var parameters = new System.CodeDom.Compiler.CompilerParameters()
{
GenerateExecutable = false,
GenerateInMemory = true,
};
var code = #"
public class TmpClass
{
public static string GetValue()
{
return """ + input + #""";
}
}";
var compileResult = provider.CompileAssemblyFromSource(parameters, code);
if (compileResult.Errors.HasErrors)
{
throw new ArgumentException(compileResult.Errors.Cast<System.CodeDom.Compiler.CompilerError>().First(e => !e.IsWarning).ErrorText);
}
var asmb = compileResult.CompiledAssembly;
var method = asmb.GetType("TmpClass").GetMethod("GetValue");
return method.Invoke(null, null) as string;
}
Passing line breaks in command line arguments works as expected, actually. Quick test in PowerShell:
PS> ./echoargs "a`nb" b c
arg 1: a
b
arg 2: b
arg 3: c
Now, if what you're trying is to do the same thing in cmd that could prove difficult (and is not really obvious from your question – Process.Start would work, though).
If you pass prog .exe "ff \\\\n ff"
you can replace them from inside your code var s = arg[0[.Replace("\" ,#"\\"); like this
From the windows command line, this is impossible. For security, C# parses user input from the command line as entirely literal. There are no escape characters that will automatically create a new line, unless you write code to go through the string and replace \n with the actual newline character.
If you type in \n into the command line, C# will parse that as \\n.
I'm stuck with regular expressions. The program is a console application written in C#. There are a few commands. I want to check the arguments are right first. I thought it'll be easy with Regex but couldn't do that:
var strArgs = "";
foreach (var x in args)
{
strArgs += x + " ";
}
if (!Regex.IsMatch(strArgs, #"(-\?|-help|-c|-continuous|-l|-log|-ip|)* .{1,}"))
{
Console.WriteLine("Command arrangement is wrong. Use \"-?\" or \"-help\" to see help.");
return;
}
Usage is:
program.exe [-options] [domains]
The problem is, program accepts all commands. Also I need to check "-" prefixed commands are before the domains. I think the problem is not difficult to solve.
Thanks...
Since you will end up writing a switch statement to process the options anyway, you would be better off doing the checking there:
switch(args[i])
{
case "-?": ...
case "-help": ...
...
default:
if (args[i][0] == '-')
throw new Exception("Unrecognised option: " + args[i]);
}
First, to parse command line arguments don't use regular expressions. Here is a related question that I think you should look at:
Best way to parse command line arguments in C#?
But for your specific problem with your regular expression - the options are optional and then you match against a space followed by anything at all, where anything can include for example invalid domains and/or invalid options. So far example this is valid according to your regular expression:
program.exe -c -invalid
One way to improve this by being more precise about the allowed characters in a domain rather than just matching anything.
Another problem with your regular expressions is that you don't allow spaces between the switches. To handle that you probably want something like this:
(?:(?:-\?|-help|-c|-continuous|-l|-log|-ip) +)*
I'd also like to point out that you should use string.Join instead of the loop you are currently using.
string strArgs = string.Join(" ", args);
Don't reinvent the wheel, handling command line arguments is a solved problem.
I've gotten good use out of the Command Line Parser Library for .Net.
Actually the easiest way to achieve command line argument parsing is to create a powershell commandlet. That gives you a really nice way to work with arguments.
I have been using this function with success... perhaps it will be useful for someone else...
First, define your variables:
private string myVariable1;
private string myVariable2;
private Boolean debugEnabled = false;
Then, execute the function:
loadArgs();
and add the function to your code:
private void loadArgs()
{
const string namedArgsPattern = "^(/|-)(?<name>\\w+)(?:\\:(?<value>.+)$|\\:$|$)";
System.Text.RegularExpressions.Regex argRegEx = new System.Text.RegularExpressions.Regex(namedArgsPattern, System.Text.RegularExpressions.RegexOptions.Compiled);
foreach (string arg in Environment.GetCommandLineArgs())
{
System.Text.RegularExpressions.Match namedArg = argRegEx.Match(arg);
if (namedArg.Success)
{
switch (namedArg.Groups["name"].ToString().ToLower())
{
case "myArg1":
myVariable1 = namedArg.Groups["value"].ToString();
break;
case "myArg2":
myVariable2 = namedArg.Groups["value"].ToString();
break;
case "debug":
debugEnabled = true;
break;
default:
break;
}
}
}
}
and to use it you can use the command syntax with either a forward slash "/" or a dash "-":
myappname.exe /myArg1:Hello /myArg2:Chris -debug
This regex parses the command line arguments into matches and groups so that you can build a parser based on this regex.
((?:|^\b|\s+)--(?<option_1>.+?)(?:\s|=|$)(?!-)(?<value_1>[\"\'].+?[\"\']|.+?(?:\s|$))?|(?:|^\b)-(?<option_2>.)(?:\s|=|$)(?!-)(?<value_2>[\"\'].+?[\"\']|.+?(?:\s|$))?|(?<arg>[\"\'].+?[\"\']|.+?(?:\s|$)))
This Regex will parse the Following and works in almost all the languages
--in-argument hello --out-stdout false positional -x
--in-argument 'hello world"
"filename"
--in-argument="hello world'
--in-argument='hello'
--in-argument hello
"hello"
helloworld
--flag-off
-v
-x="hello"
-u positive
C:\serverfile
--in-arg1='abc' --in-arg2=hello world c:\\test
Try on Regex101