In pseudo code, I want put an arbitrary number of arguments to printf depending on the length of the argv, where the argv[1] is the format string.
int main(int argc, char *argv[]) {
printf(argv[1], argv[2], ...);
}
Uses can call the program as ./prog "%s %s" a b, ./prog "%s %s %s" a b c, and so on.
Could anybody let me know how to achieve this in C?
You need a loop for this:
int main(int argc, char *argv[])
{
int i;
for (i=1;i<argc;i++) {
printf("%s", argv[i]);
}
}
Here's something I just hacked together right now, it does does minimal parsing of the string and leaves most of it up to printf. It should also work with any number of arguments. Of course, since arguments are passed as char *s through the command line, this will only work with %s and its variants (and %%, but not sure if that counts as a format specifier).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stderr, "Usage: %s <format string>[ <args>]\n", argv[0]);
return 1;
}
// These pointers will constantly jump from format spec. to format spec.
char *last_fmt = argv[1], *next_fmt, *next_next_fmt;
char *buf = NULL; // a buffer to hold a substring of argv[1]
unsigned i = 2; // Used to iterate over argv[2+]
while (1)
{
next_fmt = last_fmt - 2;
do
{
if ((next_fmt = strchr(next_fmt + 2, '%')) == NULL)
{
/* Your compiler may warn about this line specifically (it did for me),
but rest assured that there are indeed no format specifiers
here really, printf is just needed for printing "%%"s as "%"s */
printf(last_fmt);
return 0;
}
} while (next_fmt[1] == '%');
next_next_fmt = next_fmt - 1;
do
{
if ((next_next_fmt = strchr(next_next_fmt + 2, '%')) == NULL)
{
printf(last_fmt == argv[1] ? last_fmt : next_fmt,
argv[i]);
return 0;
}
} while (next_next_fmt[1] == '%');
buf = malloc(next_next_fmt - last_fmt + 1);
memcpy(buf, last_fmt, next_next_fmt - last_fmt);
buf[next_next_fmt - last_fmt] = '\0';
printf(buf, argv[i]);
free(buf);
++i;
last_fmt = next_next_fmt;
}
}
An example of running:
./a.out "Hello %.2s World! %s" "foo" "bar"
Hello fo World! bar
./a.out "Hello %10s World!" "foo" "bar"
Hello foo World!
./a.out "Hello %5.2s World!" "random"
Hello ra World!
./a.out
Usage: ./a.out <format string>[ <args>]
./a.out "Hello %%s World %s" "a"
Hello %s World a
./a.out "%s %s %s" "a" "b" "c"
a b c
You could build upon this yourself, but if you want to handle other format specifiers, you'll have to do actual parsing of the string. At that point, you would basically be creating another printf.
You also might be a bit worried about the use of a not-string-literal passed to printf, but this is safe. There is guaranteed to be exactly 1 format specifier in each place I use printf (except in the first do loop, but there it is guaranteed to not have any arguments).
how to achieve this in C?
C language does not have reflection. You can't "dynamically create function calls" or inspect and then change your own source code. You have to know at compilation time how many arguments you are passing to a function. While it is simple to do printf("%s %s", "a", "b) inside C language, if you pass the same data to a program that was written in C language you have parse the data and write the logic yourself.
Such parser would take the string "%s %s" find the %s sequences and replace them for the string "a" and "b" and also print the space in between, etc. That parser has to be written in C and is basically a duplication of what printf program (not printf() C function) does. You may want to read some implementations of printf program: ex. coreutils printf.c or freebsd printf.c.
This isn't a great idea to begin with, it will be super-vulnerable to all manner of exploits, typos and bugs. But if you insist, you could do a dirty hack as follows:
Assuming the format string in argv[1] is %s %s %s, then each we can divide this string length by 3 to get the number of strings. Save for the final one, which isn't followed by a trailing space. So strlen(argv[1]) + 1 then divide by 3:
#define STR_N ((strlen(argv[1])+1)/3)
Next up we can take advantage of printf ignoring trailing arguments not corresponding to the format string. So we could do printf(argv[1], argv[2], argv[3]); just fine without actually passing that many arguments, long as the format string contains the correct amount of conversion specifiers. For example:
#define ARGV_LIST \
argv[2],\
argv[3],\
argv[4],\
argv[5],\
argv[6],\
argv[7],\
argv[8],\
argv[9]\
printf(argv[1], ARGV_LIST);
Then cook up something to convert the indices and make sure that array out of bounds never occurs:
#include <stdio.h>
#include <string.h>
#define STR_N ((strlen(argv[1])+1)/3)
#define INDEX(n) (STR_N>n? (n+2) : 0)
#define ARGV_LIST \
argv[INDEX(0)],\
argv[INDEX(1)],\
argv[INDEX(2)],\
argv[INDEX(3)],\
argv[INDEX(4)],\
argv[INDEX(5)],\
argv[INDEX(6)],\
argv[INDEX(7)],\
argv[INDEX(8)],\
argv[INDEX(9)]\
int main(int argc, char *argv[])
{
printf(argv[1], ARGV_LIST);
return 0;
}
Tested in Windows with prog.exe "%s %s %s %s %s" hello this is a test gives output:
hello this is a test
Related
I have this program that is supposed to read a line e.g post "nice job" john and i want to get every token in that line but for some reason i only get some of them.
Expected output:
post
nice job
john
My output:
post
nice
im sure im putting the correct format on sscanf so whats the problem i dont get why it doenst consider "nice job" as one word.
Program:
#include <stdio.h>
int main()
{
char token1[128];
char token2[128];
char token3[128];
char str[] = "post \"nice job\" john";
sscanf(str,"%s \"%s\" %s",token1,token2,token3);
puts(token1);
puts(token2);
puts(token3);
return(0);
}
The second %s reads "nice" because %s stops at the first whitespace. The format string then demands a match for a " quote, which isn't next (a space is next). The scanf functions don't skip input until a match is found, they stall. Always check the return value which should have been 3.
This code
#include <stdio.h>
int main()
{
char token1[128] = "";
char token2[128] = "";
char token3[128] = "";
char str[] = "post \"nice job\" john";
int res = sscanf(str, "%s \"%[^\"]\"%s", token1, token2, token3);
printf("%d\n", res);
puts(token1);
puts(token2);
puts(token3);
return(0);
}
outputs
3
post
nice job
john
I am currently reading "Hacking The Art of Exploitation" where it talks about format string vulnerabilities. The book's exercise tries to read the data from arbitrary part of memory by writing an address to stack and read it using format parameters. The problem is the exercise is written for 32 bit systems, whereas I am working on a 64 bit. My attempt to make it work for a 64 bit system is below:
./fmt_vuln $(printf "\xaa\xee\xff\xff\xff\x7f")%016x.%016x.%016x.%016x.%016x.%016x.%016x.%016x
and the response I get from the shell is:
The right way to print user-controlled input:
?????%016x.%016x.%016x.%016x.%016x.%016x.%016x.%016x
The wrong way to
print user-controlled input:
0000000055755010.00000000f7dd18c0.00000000f7af4154.000000000000000.000000000000035.0 ffffe088.00000000555543c0.00000000ffffeeaa
[*] test val # 0x55755010 =
-72 0xffffffb8
As you can see I am only able to read the lower 4 bytes (0xFFFFEEAA) and the upper 2 bytes are gone(0x7FFF). Any thought on how I can fix this?
Btw, here is the code for fmt_vuln from the book:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char text[1024];
static int test_val = -72;
if(argc < 2) {
printf("Usage: %s <text to print>\n", argv[0]);
exit(0);
}
strcpy(text, argv[1]);
printf("The right way to print user-controlled input:\n");
printf("%s", text);
printf("\nThe wrong way to print user-controlled input:\n");
printf(text);
printf("\n");
// Debug output
printf("[*] test_val # 0x%08x = %d 0x%08x\n", &test_val, test_val, test_val);
exit(0);
}
Here is a screen shot of my shell:
Try reading with %016llx (long long x) instead of %016x, since you are reading a 64 bit hex, not a 32.
I'm trying to create a simple script on my server, basically I would like to sent a string and display it via system function...
#include <stdio.h>
int main()
{
char txt[100];
printf("Insert a text: ");
fgets(txt, 100, stdin);
system("echo %s"), txt;
return 0;
}
Rght now I'm not getting any string just "%s"
any idea why?
system("echo %s"), txt;
This isn't doing what you think; it's an expression which evaluates to txt. Since evaluating txt has no side effects, and since you're not capturing the result of the expression anywhere, adding , txt after the system call essentially does nothing. See this question for some information on the "comma"-operator in C.
Moreover, system doesn't support the use of printf-style format specifiers, so the %s in your string literal doesn't have any special meaning; it's just going to be echoed exactly as written, as you've seen. If you want to construct a command at runtime for use with system, you will have to do so with sprintf or similar.
The prototype to system() is:
int system(const char * command);
From man 3 system:
executes the shell command specified in command
From this we can safely assume s refers to a C-"string".
So prepare the string using for example snprintf():
char s[1024];
snprintf(s, 1024 -1, "echo %s", txt); /* -1 for the C-"string"'s 0-terminator */
Then pass it:
system(s);
Instead of system("echo %s"), txt; try this:
printf("%s", txt);
the system statement will not format the output, like printf.
suggest using:
#include <stdio.h>
#include <stdlib.h> // system()
#include <string.h> // strcpy(), strcat()
#define BUF_LEN (100)
int main()
{
char output[10+BUF_LEN] = "echo ";
char txt[BUF_LEN] = {'\0'};
printf("Insert a text: ");
fgets(txt, BUF_LEN, stdin);
strcat( output, txt );
system( output );
return 0;
}
The above code works very nicely, however;
do not include any command separators, semicolons, or other characters that would be interpreted by the shell in the input string.
I am looking for an example of a simple app that will use printf to express two different strings based on a positional parameter.
In bash I would use:
case $1 in
-h | --help ) showHelp
exit
;;
* ) manPipe
exit 1
esac
And prior to this I would list that a function called showHelp would be called if the operater types either $ foo -h or $ foo -help into the Terminal. Anything else like $ foo -bar would request that the function manPipe would get called.
I have this code so far:
#include <stdio.h>
#include <cstring>
int secretFunction() {
printf("Success! You found the secret message!");
}
int main() {
str posParam;
posParam = X;
printf("Enter a number:");
scanf("%s",&posParam);
if ( posParam == "X" ){
printf("Welcome to app!\nType: " + $0 + " t\nto show a message");
}else{
if (posParam == "t" ){
secretFunction();
}
return 0;
}
return 0;
I know this code is really crappy, I was trying to make an example of the above code in bash. I am not trying to convert a bash script into a C app, I'm trying to play around with it. I drew the idea of something I want to work on from the Wikipedia article on the MD5 checksum C app that takes a string and calculates the MD5 checksum for it. I cannot seem to work out what part they get the positional parameter to pass to the application.
This is a little different, I do understand, because it has prompted the user to provide an answer and then assign it to a value. I would rather use it as a positional parameter in the first instance.
What is $1 in Bash (et al) is argv[1] in a C program:
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc > 1)
{
printf("You provided at least one argument (or parameter)\n");
printf("The first argument is \"%s\"\n", argv[1]);
}
return 0;
}
The argument argc is the number of valid entries in the argv array. argv[0] is the executable name, and you can access up to argv[argc - 1]. (Actually you can access argv[argv] as well, it is always a NULL pointer).
As Joachim says, replace $0 with argv[0], also (assuming that str is a char*):
scanf("%s",&posParam);
^ there is no need to use &, posParam is already a pointer.
if ( posParam == "X" ){
strings can not be compared with ==, instead use:
if (strcmp(posParam, "X") == 0){
I'm new to C and I'd like to ask about running a C program and supplying input at the same time.
What I would like to do is run a program (ex. fileOpener) and also state which file to open
./fileOpener < filename1
I've tried it already and it works fine, but what do I use to know what filename1 is? That way I can open the file with
fp = fopen(filename1, "r")
Thanks.
Edit: OK, I'll try to explain a bit more. If there wasn't a "<" then I could just use command line arguments as I have done before, but when I tried it with the <, it didn't work
Specifically: fileOpener code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
printf("%s", argv[1]);
}
when I use ./fileOpener < filename1 the output is ./fileOpener
I used gcc -o fileOpener fileOpener.c as the compiler
int main(int argc, char *argv[])
You can name them whatever you want, but these are the normal names.
argc is non-negative. It gives the number of useful elements in argv.
If argc is positive, argv[0] contains the program name. Then argv[1] through argv[argc - 1] point to character arrays that contain the program's command line arguments.
For example, if I run a program at the command line, such as
unzip filename.zip
argc will equal 2; and argv[0] will compare equal to "unzip"; and argv[1] will compare equal to "filename.zip".
Source
You can't do that, if you use redirection (i.e. "< filename") the file is opened by the system. You could discover the name, but it's non-portable, and anyway useless since the file is already open. Just use stdin instead of fp, and you need not use fopen() (nor fclose()):
int main()
{
char buffer[1024];
// fgets() reads at most 1024 characters unless it hits a newline first
// STDIN has been already opened by the system, and assigned to data flowing
// in from our file ( < inputFile ).
fgets(buffer, 1024, stdin);
printf("The first line of input was: %s", buffer);
}
A different approach is to use arguments:
int main(int argc, char **argv)
{
FILE *fp = NULL;
char buffer[1024];
if (argc != 2)
{
fprintf(stderr, "You need to specify one argument, and only one\n");
fprintf(stderr, "Example: %s filename\n", argv[0]);
// Except that argv[0], this program's name, counts.
// So 1 argument in command line means argc = 2.
return -1;
}
printf("I am %s. You wanted to open %s\n", argv[0], argv[1]);
fp = fopen(argv[1], "r");
fgets(buffer, 1024, stdin);
printf("The first line of input was: %s", buffer);
fclose(fp); fp = NULL; // paranoid check
return 0;
}
You need setup your program to take a command line argument. Here's a good tutorial that solves your exact question:
http://www.cprogramming.com/tutorial/c/lesson14.html
A program's main function in C has two arguments:
int main(int nArgs, char *pszArgs[]) {}
That first argument tells the program how many parameters were passed onto the program when you ran it. Usually, this will just be 1, because it includes the program's name.
The second argument is a table of strings, which can be accessed thus (the program below prints the parameters given to it):
int main(int nArgs, char *pszArgs[])
{
int i = 0;
while (i < nArgs)
{
printf("param %d: %s\n", i, pszArgs[i]);
i++;
}
return 0;
}