How does strace read the file name of system call sys_open? - c

I am writing a program which uses Ptrace and does the following:
It reads the current eax and checks if the system call is sys_open.
If it is then i need to know what are the arguments that are passed.
int sys_open(const char * filename, const int mode, const int mask)
So eax = 5 implies it is a open system call
I came to know ebx has the address of the file location from this Question
But how do I knows the length of the file name so I can read the contents in that location?
I came across the following questions which address the same
Question 1
Question 2 (This one is mine only!)
But I still didn't get a solution to my problem. :( as both the answers were not clear.
I am still getting a segmentation fault when I try the approach in the Question-1
You can check my code here
So Now I really was wondering how does strace extract these values so beautifully :(

As you know, sys_open() doesn't receive the size of the filename as parameter. However, the standard says that a literal string must end with a \0 character. This is good news, because now we can do a simple loop iterating over the characters of the string, and when we find a \0 (NULL) character we know we've reached the end of it.
That's the standard procedure, that's how strlen() does it, and also how strace does it!
C example:
#include <stdio.h>
int main()
{
const char* filename = "/etc/somefile";
int fname_length = 0;
for (int i = 0; filename[i] != '\0'; i++)
{
fname_length++;
}
printf("Found %d chars in: %s\n", fname_length, filename);
return 0;
}
Back to your task at hand, you must access the address of filename and perform the procedure I just described. This is something you will have to do, and there's no other way.

Related

How to use sscanf to parse an program argument in C

I've been looking every sscanf post here and I can't find an exact solution suitable for my problem. I was implementing my own Shell and one of the characteristics is that if I find the dollar sign $, I got to replace what is exactly behind with the environmental variable:
cd $HOME should actually be replaced by cd /home/user before I even execute the cd.
My question is what is the code to use sscanf to take out the dollar sign and simply get HOME on the same string? I've been struggling with some null pointers trying this:
char * change;
if (strcmp(argv[1][0],'$')==0){
change = malloc(strlen(argv[y]));
sscanf(argv2[y]+1,"%[_a-zA-Z0-9]",change);
argv2[y]=getenv(change);
}
But this seems to be failing, I'm having a segmentation fault core. (If needed i put more code, my question is specially focused on the sscanf).
Quick explanation argv is an array of pointers to the lines entered and parsed, so actually the content of argv[0] = "cd" and argv[1]="$HOME". I also know that the variable I'm going to receive after the $ has the format %[_a-zA-Z0-9].
Please ignore the non failure treatment.
You asked "is malloc() necessary" in your code snipped and the answer was "no", you could use a simple array. In reality, if you are simply making use of the return of getenv() without modification in the same scope without any other calls to getenv(), all you need is a pointer. getenv() will return a pointer to the value part of the name=value pair within the program environment. However the pointer may be a pointer to a statically allocated array, so any other calls to getenv() before you make use of the pointer can cause the text to change. Also, do not modify the string returned by getenv() or you will be modifying the environment of the process.
That said, for your simple case, you could do something similar to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
char *envp = NULL, /* pointer for return of getenv() */
buf[MAXC]; /* buffer to parse argv[2] w/sscanf */
if (argc < 3) { /* validate at least 2 program arguments given */
printf ("usage: %s cmd path\n", strrchr (argv[0], '/') + 1);
return 1;
}
if (*argv[2] == '$') /* chest 1st char of argv[2] == '$' */
if (sscanf (argv[2] + 1, "%1023[_a-zA-Z0-9]", buf) != 1) {
fputs ("error: invalid format following '$'.\n", stderr);
return 1;
}
if (!(envp = getenv (buf))) { /* get environment var from name in buf */
fprintf (stderr, "'%s' not found in environment.\n", buf);
return 1;
}
printf ("%s %s\n", argv[1], envp); /* output resulting command line */
}
Right now the program just outputs what the resulting command line would be after retrieving the environment variable. You can adjust and build the array of pointers for execv as needed.
Example Use/Output
$ ./bin/getenvhome "cd" '$HOME'
cd /home/david
Look things over and let me know if you have any further questions.
You don't need sscanf here, you can just slide the pointer.
If argv[1] points to the string "$HOME", then argv[1] + 1 points to "HOME", so your example code would just become:
char * change;
if (argv[y][0] == '$')
{
change = argv[y] + 1;
}
(But in this case your variable should not be named change. Call your variables what they represent, for example in this case variable_name, because it contains the name of the shell variable you will be expanding - remember your code is for communicating to other humans your intent and other helpful information about the code.)
To be clear, whether you do sscanf or this trick, you still have to do error checking to make sure the variable name is actually the right characters.
Remember that sscanf won't tell you if there are wrong characters, it'll just stop - if the user writes a variable like $FO)O (because they made a typo while trying to type $FOO) sscanf will just scan out the first valid characters and ignore the invalid ones, and return FO instead.
In this case ignoring bad data at the end would be bad because user interfaces (that includes shells) should minimize the chances that a user mistake silently does an unintended wrong thing.

Why does this loop not print the same value continuously?

I am trying to understand some C code I've stumbled across. For the record, the code does exactly what it's supposed to except for the print line I added. It takes all of the contents from the inputFile.txt, and replaces the J's with X's, and writes it to the outputFile.txt.
int main(void) {
int fd_to_read = open("inputFile.txt", O_RDONLY);
int fd_to_write = open("outputFile.txt", O_WRONLY | O_CREAT);
char c;
int bytes;
while ((bytes = read(fd_to_read, &c, sizeof(c))) > 0) {
if (c == 'J') {
c = 'X';
}
write(fd_to_write, &c, sizeof(c));
//I added this and it doesn't work.
printf(&c);
}
close(fd_to_read);
}
When I first saw this, I expected the while loop to print the first character from the file over and over again. I understand that the read() function will be executed until it is >0, but I assumed that in order for it to change position in the file the memory address pointed to by c would have to increment by something, possibly the sizeof(c), but nothing appears to increment and it just moves on to the next letter in the file. My next assumption is that read() handles that on it's own, but when I went to print the contents of &c I got close to what I expected, which was a ton of garbage, since it was just printing random things from memory essentially.
So, two questions really.
How is the &c that is written to the outputFile.txt write to that correctly without incrementing the address of c?
How would I just print the individual characters from the file without all the garbage since print(&c) added all the garbage after each char?
Ok two things.
(1) char c does not need to be incremented because it is serving like the output to the read fn.
(2) the read and write fn's automatically increment their respective file descriptors.
The file descriptors (fd_to_read, fd_to_write) represent a location in the file, not char c.
Read about it in the man pages:
https://linux.die.net/man/3/read
https://linux.die.net/man/3/write
char c; ... printf(&c); is UB, yet I suspect OP knows that.
The first arg to printf() must be a pointer to a string. &c is not a pointer to a string.
OP is hoping for favorable UB. Good luck.

read() function error in C

I'm trying to read from .txt file until I hit the character "=". Text file is always the same,contains only these strings:
TaskLimit=3
cc pr.c && ./a.out
Sometimes the code works fine and quits the while loop and sometimes it prints "TaskLimit" but then throws "Segmentation fault (core dumped)" error. Any ideas what am I doing wrong? Should I clear the buf[] or something?
char buf[1];
file = open(argv[1], O_RDONLY);
if (file == -1){
perror("Error opening file");
exit(1);
}
while(1){
read(file, buf, 1);
if(buf[0]=='=') {printf("I'm out");break;}
printf("%c",buf[0]);
//further actions
edit:
in the "further actions" I'm trying to convert a char to int and this seems to be the problem:
char limit_char[0];
int limit;
read(file,limit_char,1);
limit=atoi(limit_char[0]);
edit2:
changing this line
limit=atoi(limit_char[0]);
to
limit=atoi(&limit_char);
helped.
The most important part of C programming is checking return values.
In your sample code sample you do it for open(2), but not for read(2) and you should, because not only does it tell if there was an error, it also tells how many bytes have been read. Excerpt from the man page:
On success, the number of bytes read is returned (*zero indicates end of file*),
and the file position is advanced by this number.
That is, knowing that there is nothing more to read - return value of zero - can let you break from the loop in case the user gave you an invalid file.
When you learn C, I suggest (and pretty much every person on this site) to always compile with -Wall -Wextra -Werror. C is a spartan language and mastering it requires discipline. GCC (or whatever your compiler is) would never have let you execute:
limit=atoi(&limit_char);
As the type of &limit_char is effectively char ** and atoi expects a const char *.
atoi requires a NULL-terminated array of char so your array needs 1 more element than you're reading in.
char limit_char[2];
int limit;
read(file,limit_char,1);
limit_char[1]='\0';
limit=atoi(limit_char);
beyond that, you should probably be checking the return value from read to make sure you've actually read something in.
In your code, your refer to argv[1] for the filename, but on the example usage (cc pr.c && ./a.out) you don't specify any filename.
In you read() statement you use a variable plik which is not defined anywhere, use file here, i.e. the variable you used to store the result of `open().
Fix this and it will work.
This declaras an array of length zero which doesn't make much sense. BTW: normally the compiler should emit at least a warning.
char limit_char[0];
this wont work, you need an array of length 1 because you read 1 byte with read:
char limit_char[1];
or rather this:
char limit_char;
...
read(file, &limit_char, 1);

How to crash this C program? [duplicate]

I have a small C program to be exploited. And I also understood the logic behind the attack to be performed. However, as much as I try, it is just not working for me.
#include <stdio.h>
#include <stdlib.h>
#define SECRET1 0x44
#define SECRET2 0x55
int main(int argc, char *argv[]) {
char user_input[100];
int *secret;
int int_input;
int a, b, c, d; /* other variables, not used here.*/
/* The secret value is stored on the heap */
secret = (int *) malloc(2*sizeof(int));
/* getting the secret */
secret[0] = SECRET1; secret[1] = SECRET2;
printf("Please enter a decimal integer\n");
scanf("%d", &int_input); /* getting an input from user */
printf("Please enter a string\n");
scanf("%s", user_input); /* getting a string from user */
printf(user_input);
printf("\n");
/* Verify whether your attack is successful */
printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2);
printf("The new secrets: 0x%x -- 0x%x\n", secret[0], secret[1]);
return 0;
}
I just need to print the address and value of secret[0] using the format string "printf(user_input);"
I have tried giving something like "\x6e\xaf\xff\xff%x%x%x%x%s". but it is not working. Any suggestions will be appreciated. Thanks a lot.
This looks like an exercise for a class, so I'll provide some pointers, but no the actual solution.
You are attempting to exploit this program, by providing untrusted input. There are two fairly obvious bugs here; one is the scanf() using %s, as you can overflow the buffer and overwrite the stack. The other is a format-string vulnerability. Overwriting the stack probably wouldn't let you do anything interesting until the function returned. Based on the "verify whether your attack is successful" section, you probably want to exploit the vulnerability before then, so I'm guessing it's supposed to be a format string vulnerability.
Based on the verification section, you are expected to overwrite the memory pointed to by secret. The only way of causing printf to write to a controlled location in memory is to use the %n format specifier, which writes the given pointer.
Now the trick is to figure out how to walk up the stack until we find the appropriate pointer. Conveniently, there's a user-controlled integer right before the pointer on the stack. So, we enter a number with an easy to spot pattern (maybe 65535, which is ffff in hex), and use a format string with a lot of %xs to see what's on the stack. Once we find that, the next thing on the stack should be the pointer.
Hmm. I just tried this, and it turns out that it's not quite so simple. The exact layout of the stack frame isn't actually related to the order of declarations; and it differs between different systems for me. Instead, I had to use a lot of %lxs, along with a well-known string at the beginning, and add a line to print out the actual pointer, so I would know when I found it. Then replace the corresponding %lx with the %n to write through that pointer. It may be easiest to just try 20 or so %lxs, and substitute each one by one with %n, until you have managed to overwrite that pointer.
Anyhow, hope that's enough to get you started. Let me know if you have any questions.

Why is this C code giving me a bus error?

I have, as usual, been reading quite a few posts on here. I found a particular useful posts on bus errors in general, see here. My problem is that I cannot understand why my particular code is giving me an error.
My code is an attempt to teach myself C. It's a modification of a game I made when I learned Java. The goal in my game is to take a huge 5049 x 1 text file of words. Randomly pick a word, jumble it and try to guess it. I know how to do all of that. So anyway, each line of the text file contains a word like:
5049
must
lean
better
program
now
...
So, I created an string array in C, tried to read this string array and put it into C. I didn't do anything else. Once I get the file into C, the rest should be easy. Weirder yet is that it complies. My problem comes when I run it with ./blah command.
The error I get is simple. It says:
zsh: bus error ./blah
My code is below. I suspect it might have to do with memory or overflowing the buffer, but that's completely unscientific and a gut feeling. So my question is simple, why is this C code giving me this bus error msg?
#include<stdio.h>
#include<stdlib.h>
//Preprocessed Functions
void jumblegame();
void readFile(char* [], int);
int main(int argc, char* argv[])
{
jumblegame();
}
void jumblegame()
{
//Load File
int x = 5049; //Rows
int y = 256; //Colums
char* words[x];
readFile(words,x);
//Define score variables
int totalScore = 0;
int currentScore = 0;
//Repeatedly pick a random work, randomly jumble it, and let the user guess what it is
}
void readFile(char* array[5049], int x)
{
char line[256]; //This is to to grab each string in the file and put it in a line.
FILE *file;
file = fopen("words.txt","r");
//Check to make sure file can open
if(file == NULL)
{
printf("Error: File does not open.");
exit(1);
}
//Otherwise, read file into array
else
{
while(!feof(file))//The file will loop until end of file
{
if((fgets(line,256,file))!= NULL)//If the line isn't empty
{
array[x] = fgets(line,256,file);//store string in line x of array
x++; //Increment to the next line
}
}
}
}
This line has a few problems:
array[x] = fgets(line,256,file);//store string in line x of array
You've already read the line in the condition of the immediately preceding if statement: the current line that you want to operate on is already in the buffer and now you use fgets to get the next line.
You're trying to assign to the same array slot each time: instead you'll want to keep a separate variable for the array index that increments each time through the loop.
Finally, you're trying to copy the strings using =. This will only copy references, it won't make a new copy of the string. So each element of the array will point to the same buffer: line, which will go out of scope and become invalid when your function exits. To populate your array with the strings, you need to make a copy of each one for the array: allocate space for each new string using malloc, then use strncpy to copy each line into your new string. Alternately, if you can use strdup, it will take care of allocating the space for you.
But I suspect that this is the cause of your bus error: you're passing in the array size as x, and in your loop, you're assigning to array[x]. The problem with this is that array[x] doesn't belong to the array, the array only has useable indices of 0 to (x - 1).
You are passing the value 5049 for x. The first time that the line
array[x] = ...
executes, it's accessing an array location that does not exist.
It looks like you are learning C. Great! A skill you need to master early is basic debugger use. In this case, if you compile your program with
gcc -g myprogram.c -o myprogram
and then run it with
gdb ./myprogram
(I am assuming Linux), you will get a stack dump that shows the line where bus error occurred. This should be enough to help you figure out the error yourself, which in the long run is much better than asking others.
There are many other ways a debugger is useful, but this is high on the list. It gives you a window into your running program.
You are storing the lines in the line buffer, which is defined inside the readFile function, and storing pointers to it in the arary. There are two problems with that: you are overwriting the value everytime a new string is read and the buffer is in the stack, and is invalid once the function returns.
You have at least a few problems:
array[x] = fgets(line,256,file)
This stores the address of line into each array element. line in no longer valid when readFile() returns, so you'll have an array of of useless pointers. Even if line had a longer lifetime, it wouldn't be useful to have all your array elements having the same pointer (they'd each just point to whatever happened to be written in the buffer last)
while(!feof(file))
This is an antipattern for reading a file. See http://c-faq.com/stdio/feof.html and "Using feof() incorrectly". This antipattern is likely responsible for your program looping more than you might expect when reading the file.
you allocate the array to hold 5049 pointers, but you simply read however much is in the file - there's no checking for whether or not you read the expected number or to prevent reading too many. You should think about allocating the array dynamically as you read the file or have a mechanism to ensure you read the right amount of data (not too little and not too much) and handle the error when it's not right.
I suspect the problem is with (fgets(line,256,file))!=NULL). A better way to read a file is with fread() (see http://www.cplusplus.com/reference/clibrary/cstdio/fread/). Specify the FILE* (a file stream in C), the size of the buffer, and the buffer. The routine returns the number of bytes read. If the return value is zero, then the EOF has been reached.
char buff [256];
fread (file, sizeof(char), 256, buff);

Resources