Call function from exec()-initialized process - c

Let's say I have the following programs:
//gcc a_program.c -o a_program
void foo() {
printf("foo called\n");
}
int main(int argc, char** argv) {
execvp("some_other_program", argv);
}
//gcc some_other_program.c -o some_other_program
int main(int argc, char** argv) {
foo();
}
Is there a way to call foo from the new process image that execvp() creates? dlsym() only works on binaries loaded as dynamic libraries - according to the man page, at least - so I can't just search for the symbol in the new process, even if it exists.

No. When you exec a program the current process is completely replaced by the new one. Environmental factors like open file descriptors are retained, but code isn't. You can't call functions from the old process in the new one.

Related

dynamic file compilation with gcc in c

I'm trying to find a method to, from a program, check the presence of one or more ".c" files and load one or more functions of it.
Basically, I would have a "main" program which will check if the "script.c" file exists, and will launch (if it exists) the main() function of this one.
Here is the content of my "main" program before compilation:
int main(int argc, char *argv[]){
...
if(argc == 1){
FILE *file;
if((file = fopen("script.c", "r"))){
printf("file script.c loaded.");
// to compile the script.c file and modify on it the "main()" function to "_main()" (in order to be able to recompile it with the main library) before restarting the program
int ret = system("gcc -c script.c && objcopy --redefine-sym main=_main script.o && gcc main script.o -o main && ./main -l script.o");
printf("ret(0)=%d\n", ret);
}
else{
int ret = system("./main -l");
printf("ret(1)=%d\n", ret);
}
}
else{
if(argc == 3 && strcmp(argv[2], "script.o") == 0){
_main(argc, argv);
}
else{
printf("no file found.\n");
}
}
...
}
He is the content of my "script.c" file:
int main(int argc, char *argv[]){
...
printf("main() function in script.c loaded.\n");
...
}
If the script.c file exists, running main should give:
file script.c loaded.
ret(0)=0
main() function in script.c loaded.
If the script.c file does not exist, running main should give:
file script.c loaded.
ret(1)=0
no file found.
Obviously, this does not work for several reasons.
It is impossible to use the "main" program to recompile the script.o file (especially since this is supposed to be in use)
It is impossible to compile my "main" program with a _main() function that does not exist (on the 1st launch, and potentially on the second too if script.c dont found)
Do you have an idea for me to achieve my goal ?
So from a single executable program (here "main") to be able to check the presence of an external file (here "script.c") and launch one or more functions from it...
PS: Having already seen it in other projects, I know it's possible, but I can't find the solution.
PS2: Only the executable file (main) and potentially the script.c file must be present (therefore no main.c...which therefore perhaps suggests that a "main" file should be merged with the "main.o" associated which would be unpacked and executed)
So from a single executable program (here "main") to be able to check the presence of an external file (here "script.c") and launch one or more functions from it...
I'm going to make an assumption that the main function you mentioned is not the most important and show how you can, from within your program, compile collections of functions into shared libraries that you load and then execute functions (other than main) in.
A simple driver could look like this:
// driver.c
#include <dlfcn.h> // to be able to dynamically load shared libraries
#include <stdio.h>
#include <stdlib.h>
// the signature of the `start` function you decide to have in all the files:
typedef void(*start_func_t)(void);
int main(int argc, char *argv[]){
char sys[1024];
for(int i = 1; i < argc; ++i) { // loop through all the arguments
// try to compile the argument into an object file
// (use a safer version than sprintf in real code)
sprintf(sys, "gcc -fPIC -c -o %s.o %s", argv[i], argv[i]);
if(system(sys)) {
printf("%d failed\n", sys);
exit(1);
}
// try to create a shared library from the object file
sprintf(sys, "gcc -shared -o libcurrent.so %s.o", argv[i]);
if(system(sys)) {
printf("%d failed\n", sys);
exit(1);
}
// load the shared library you just created
(void)dlerror();
void *handle = dlopen("./libcurrent.so", RTLD_NOW | RTLD_LOCAL);
if(!handle) {
puts(dlerror());
exit(1);
}
// lookup the "start" symbol in the shared library:
start_func_t start = dlsym(handle, "start");
if(!start) {
puts(dlerror());
exit(1);
}
// call the loaded function:
start();
dlclose(handle); // close the library
}
}
You need to link the above program with the dl library, so something like this should work:
gcc -o driver driver.c -ldl
Now, if you create some example files:
// t1.c
#include <stdio.h>
void start(void) { puts("Hello world"); }
// t2.c
#include <stdio.h>
void start(void) { puts("another file"); }
and then run:
./driver t1.c t2.c
It should produce this output if everything works out:
Hello world
another file
I also made a test to see how this works out if I put main in the library. That is, change the start_func_t signature to:
typedef int(*start_func_t)(int argc, char *argv[]);
and load and call main instead:
start_func_t start = dlsym(handle, "main");
if(!start) {
puts(dlerror());
exit(1);
}
// call the loaded function with some example arguments:
char *cargv[] = {
"foo", "hello", "world", NULL
};
start(3, cargv);
and change the test programs slightly:
// t1.c
#include <stdio.h>
int main(int argc, char *argv[]) {
for(int i = 0; i < argc; ++i) {
printf("t1: %s\n", argv[i]);
}
}
// t2.c
#include <stdio.h>
int main(int argc, char *argv[]) {
for(int i = 0; i < argc; ++i) {
printf("t2: %s\n", argv[i]);
}
}
and this worked fine too. However, main is a bit special and I'm not sure if this violates any rules.

multiple definition of main() function with gcc compilation in c

I'm looking for an efficient (fast and secure) method to communicate multiple scripts (and their associated main function ()) to each other. A bit like the principle of the G-WAN project which uses a launcher (./gwan) to read / load / compile different .c files which each contain (or not) a main() function.
Ideally, my launcher should be able to execute the main () functions of other scripts while sharing information through their argv variables.
But as you know, gcc -Wall script1.c script2.c script3.c -o test return me an error of multiple definition of function main(), and gcc -Wl,--allow-multiple-definition -Wall script1.c script2.c script3.c -o test interprets only the first script1.c main() function.
Maybe the solution would be to have a first script (script1.c) which compiles the other scripts (script2.c and script3.c) via a shared variable?
Thanks for your help and sorry for my limited english.
script1.c:
int main(int argc, char *argv[]){
...
int i = main(argc, argv); // main for script2.c
if(i == 0)
main(argc, argv); // main for script3.c
...
return(0);
}
script2.c:
int main(int argc, char *argv[]){
...
return(0);
}
script3.c:
int main(int argc, char *argv[]){
...
return(0);
}
You can't have multiple main function in c, it's simply not allowed, what you can do is have your main function in your first .c file, and whatever you want in your others .c files.
Then you can write :
#include "script2.c"
#include "script3.c"
on top of your script1.c file.
If you want to compute values inside a file and "send" it to main file, you can do it through functions, defined in your other files, since you include it !
Notice that there is no scripts in C !

How to execute a code whose main function looks like this?

The code is like (real noob question) :
int main(int argc, char **argv){
//some code
}
I know, it means I have to give some arguments while executing in the terminal, but the code does not require any arguments or information from the user. I don't know what to give as the argument?
For example:
#include <stdio.h>
int main(int argc, char **argv)
{
printf("Hello World\n");
}
Compile with GCC,
$gcc prog.c -o prog
$./prog
Hello World
So, If you do not use agave in your code, then, there is no need to provide an argument.
I have to give some arguments while executing in the terminal,
No, you don't have to. You may give some arguments. There are conventions regarding program arguments (but these are just conventions, not requirements).
It is perfectly possible to write some C code with a main without argument, or with ignored arguments. Then you'll compile your program into some executable myprog and you just type ./myprog (or even just myprog if your PATH variable mentions at the right place the directory containing your myprog) in your terminal.
The C11 standard n1570 specifies in ยง5.1.2.2.1 [Program startup] that
The function called at program startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and with no
parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be
used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent) or in some other implementation-defined manner.
The POSIX standard specifies further the relation between the command line, the execve function, and the main of your program. See also this.
In practice I strongly recommend, in any serious program running on a POSIX system, to give two argc & argv arguments to main and to parse them following established conventions (In particular, I hate serious programs not understanding --help and --version).
You can always pass some number of arguments or pass nothing unless you are checking for the number of arguments and arguments passed (or forcing compiler to do so). Your command interpreter has no idea what your program is going to do with the passed argument or whether the program need any argument. It's your program which takes care of all these things.
For example,
int main(void){
return 0;
}
you can pass any number of arguments to the above program
$ gcc hello.c -o hello
$ ./hello blah blah blah
In case of
int main(int argc, char **argv){
return 0;
}
you can pass no arguments.
$ gcc hello.c -o hello
$ ./hello
For
int main(int argc, char **argv){
if(argc < 3){
printf("You need to pass two arguments to print those on the terminal\n");
exit(0);
}
else{
printf("%s %s\n", argv[1], arv[2]);
}
return 0;
}
You have to pass two arguments because the program checking the number of arguments passed and using them
$ gcc hello.c -o hello
$ ./hello Hello world

Extern undefined symbol

I am building a user defined shell where the shell dynamically links libraries
I have the following snippet from the main file that contains the global variable declarations...
char *prompt = "upsh";
int main()
{ ...
then I have a shared library as follows...
extern char *prompt;
int setprompt(char *argv[]) {
prompt = argv[1];
return 0;
}
my problem is that when I link the library from the main program I get the error
./setprompt.so: undefined symbol: prompt
...maybe this is a compilation issue?
As Naveem Kumar commented, you should provide compilation steps. Does the following reproduce what you meant? This worked in my laptop.
Makefile
all: main
libsetprompt.so: setprompt.c
gcc -fPIC -DPIC -shared setprompt.c -o libsetprompt.so
main: main.c libsetprompt.so
gcc main.c -o main -L. -lsetprompt
clean:
rm main libsetprompt.so
main.c
char *prompt = "upsh";
int main(int argc, char *argv[])
{ return 0; }
setprompt.c
extern char *prompt;
int setprompt(char *argv[])
{
prompt = argv[1];
return 0;
}
I do not think it is a comilation issue. If i get it right, you have a console application, which means that argc and argv must be passed to the main function in order to use them, but they are not passed. I guess your problem is that you call int setprompt(char *argv[]) without actually passing argv[]. But i may be wrong, more code would help to tell for sure.
But probably instead of int main() there should be int main(int argc, char **argv)

Return-To-Libc Function Address Probing

I'm trying to implement a return-to-libc buffer overflow attack by finding the address of system() with gdb and returning to said address with /bin/sh passed as an argument to system() on the stack. The only problem is, I can't find the address in memory where system() lives, as running print system in gdb returns "No symbol table is loaded. Use the "file" command.", which isn't especially helpful, as loading libc.so into gdb doesn't do me any good. Is there a way I can find the addresses of functions in libc which I have not included via headers?
For reference, the code I'm testing this with is below, DEP is enabled, and ASLR is disabled.
#include <stdio.h>
#include <string.h>
void foo(char *arg) {
char buf[100];
strcpy(buf, arg);
}
int main(int argc, char **argv) {
foo(argv[1]);
return 0;
}

Resources