How can I get the local shell variables in C? - c

I'm currently working on my own replica of the history builtin.
I realize I need the HISTSIZE, HISTFILE and HISTFILESIZE variables to achieve the command options but I don't know how to get them. Is there a function similar to getenv or a variable like environ but with the local shell variables ?
Thanks in advance !

Well a builtin is executed directly by the shell for 2 possible reasons:
you avoid spawning a new processus (performance reason)
it is the only way to have access to internal shell variables (your use case)
A shell could only provide access to its internal variables by two ways:
either copy them to the environment because by definition the environment is the list of variables that are passed to child processes
either provided an inter process communication mechanism (named pipe, private sockect, etc.) to allow its childs to ask them
AFAIK, no common shell implement either, but you can export the required shell variables to the environment:
export HIST
export HISTSIZE
export HISTFILESIZE
should be enough to later get them through getenv

The main declaration can have an extra argument, char **envp, which is an 2D array of char terminated by a NULL pointer. Here is an example :
#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
int index = 0;
while (envp[index])
printf("%s\n", envp[index++];
return 0;
}
EDIT
Using envp will provide you to get the environnement. To find shell variables, I found this. I think that could help you.

#include <stdio.h>
#include <stdlib.h>
int main() {
printf("SET = %s\n",getenv("SET"));
return 0;
}
To test Program, set the variable first and then execute :-
export SET=1

As Steffan Hegny pointed out, there is no way to acces these variables if they are no environment variables. So popen(), what I thought could help, isn't a solution to your problem.
However if you need acces to those variables you can export their values to a real environment variable which can be accessed via getenv(char*).
E.g.
export _HISTFILE=$HISTFILE && ./myProgram
or
_HISTFILE=$HISTFILE ./myProgram
with myProgram accessing the value like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("History file: %s", getenv("_HISTFILE"));
}

Related

Using 'execlp' System Call to run current program recursively

I am trying to use execlp to call my program inside of my program (for a project) and am having trouble. I have created a sample project which should count down from n to 0 (essentially run n times). Each time I run it, I get the first decrement and then I get a seg fault. Please let me know what I am doing wrong here.
P.S Fairly new to System calls in C, so explain thoroughly if possible. Thanks in advance!
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <time.h>
int main(int argc, char **argv)
{
int n = atoi(argv[1]);
char newParameters[2];
sprintf(newParameters, "%d", n - 1);
if (n != 0)
{
execlp("./tmp", newParameters, (char *)NULL);
}
printf("The program has finished.\n");
return 0;
}
The C program is called tmp.
From the execlp manual:
The initial argument for these functions is the name of a file that is to be executed.
The const char *arg and subsequent ellipses in the execl(), execlp(), and execle() functions can be thought of as arg0, arg1, ..., argn. Together they describe a list of one or more pointers to null-terminated strings that represent the argument list available to the executed program. The first argument, by convention, should point to the filename associated with the file being executed.
That is, the first argument to execlp is the executable file to run. The second parameter corresponds to argv[0] passed to main. The third parameter is argv[1] and so on. So the execlp in this case needs to be:
execlp("./tmp", "./tmp", newParameters, NULL);
Or better still use argv[0] rather than a hard coded executable name so that it can work no matter how the program is linked:
execlp(argv[0], argv[0], newParameters, NULL);
Other things to note:
newParameters can only hold a single character string (including NUL terminator). So any command line with a number greater than 9 will result in undefined behaviour.
Other good practices: Always check argc before using argv values and always check the return value of all function calls, specifically execlp in this case.
execlp(2) cannot be used to run a program recursively, because no new process is created. The current context (process address space, data, etc.) is loaded (overwritten) with the new mapping to execute the same program again, and the data segment, the stack and memory segments are detached and trashed to create the new ones. When this instance finally exit(2)s, there's no process backed up to return to. To create a new process you need to use fork(2), not execlp(2).

How to set an environment variable when using system() to execute a command?

I'm writing a C program on Linux and need to execute a command with system(), and need to set an environment variable when executing that command, but I don't know how to set the env var when using system().
If you want to pass an environment variable to your child process that is different from the parent, you can use a combination of getenv and setenv. Say, you want to pass a different PATH to your child:
#include <stdlib.h>
#include <string.h>
int main() {
char *oldenv = strdup(getenv("PATH")); // Make a copy of your PATH
setenv("PATH", "hello", 1); // Overwrite it
system("echo $PATH"); // Outputs "hello"
setenv("PATH", oldenv, 1); // Restore old PATH
free(oldenv); // Don't forget to free!
system("echo $PATH"); // Outputs your actual PATH
}
Otherwise, if you're just creating a new environment variable, you can use a combination of setenv and unsetenv, like this:
int main() {
setenv("SOMEVAR", "hello", 1); // Create environment variable
system("echo $SOMEVAR"); // Outputs "hello"
unsetenv("SOMEVAR"); // Clear that variable (optional)
}
And don't forget to check for error codes, of course.
This should work:
#include "stdio.h"
int main()
{
system("EXAMPLE=test env|grep EXAMPLE");
}
outputs
EXAMPLE=test
Use setenv() api for setting environment variables in Linux
#include <stdlib.h>
int setenv(const char *envname, const char *envval, int overwrite);
Refer to http://www.manpagez.com/man/3/setenv/ for more information.
After setting environment variables using setenv() use system() to execute any command.

How do I change EIP in a different process?

I'm trying to hack another program by changing the EIP of it. There are two programs running, one is the target, that tells where the function that is the "core-function"(e.g. a function that receive a password string as a parameter and returns true or false) is in memory.
Then now that I know where the core-function is I wanna modify the EIP with the other program so the target program can call my function and simply get a true out of it and print out a beautiful "access granted".
My code is now like this:
Target Program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int checkPwd(char *pwd)
{
printf("\nstill in the function\n");
if(strcmp(pwd, "patrick") == 0) return true;
else return false;
}
int main()
{
char pwd[16];
printf("%d", checkPwd);
scanf("%s", &pwd);
system("pause");
if(checkPwd(pwd)) printf("Granted!\n");
else printf("Not granted\n");
system("pause");
}
Attacker Program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
int returnTrue()
{
return true;
}
int main()
{
int hex;
scanf("%d", &hex);
memcpy((void*)hex, (void*)returnTrue, sizeof(char)*8);
system("pause");
}
I wanna add that I tried to put the hex code directly(without the scanf part) in the attacker program and did not work, it crashed.
So I think I'm missing some part of the theory in here. I'd be glad to know what is it.
Thanks in advance.
This won't work—the processes occupy different memory spaces!
Modern operating systems are designed to protect user programs from exactly this kind of attack. One process doesn't have access to the memory of another—and indeed, the addresses of data are only valid inside that process.
When a program is running, it has its own view of memory, and only can "see" memory that the kernel has instructed the memory management unit (MMU) to map for it.
Some references:
Mapping of Virtual Address to Physical Address
Printing same physical address in a c program
Why are these two addresses not the same?
It is possible to inject a function into another process but it is a little more involved than you think. The first thing is you need the proper length of the function you can do this by creating two functions.
static int realFunction() { ... }
static void realFunctionEnd() {}
Now when you copy the function over you do the length of:
realFunctionEnd - realFunction
This will give you the size. Now you cannot just call the other functions because as stated they are not guranteed to be at the same address in the other process, but you can assume that , I will assume windows, that kernal32.dll is at the same address so you can actually pass that to the realFunction when you create a remote thread.
Now, as to your real issue. What you need to do is to either inject a dll or copy a function over into the other process and then hook the function that you need to change. You can do this by copying another function over and making that code executable and then overwriting the first five bytes of the target function with a jump to your injected code, or you can do a proper detour type hook. In either case it should work. Or, you can find the offset into the function and patch it yourself by writing the proper op codes in place of the real code, such as a return of true.
Some kind of injection or patching is required to complete this, you have the basic idea, but there is a little more to it than you think at the moment. I have working code for windows to copy a function into another process, but I believe it is a good learning experience.

Transfer files in C

How do I transfer files from one folder to another, where both folders are present in oracle home directory?
int main(int argc, char *argv[]){
char *home, *tmp2;
home = getenv("ORACLE_HOME");
temp2 = getenv("ORACLE_HOME");
strcat (home,"A");
strcat (tmp2,"B");
//transfer files from home to tmp2
}
strcat doesn't seem to work. Here, I see tmp2 pointer doesn't get updated correctly.
Edit: OS is a UNIX based machine. Code edited.
I require a binary file which does this copying, with the intention that the real code cannot be viewed. Hence I didn't consider using shell script as an option. The files in A are encrypted and then copied to B, decrypted in B and run. As the files are in perl, I intend to use system command to run them in the same C code.
Using the system(3) command is probably a good idea since you get the convenience of a shell interpreter to expand filenames (via *) but avoids the hassle of computing the exact length of buffer needed to print the command by using a fixed length buffer and ensuring it cannot overflow:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFSZ 0xFFF
int main(void)
{
char * ohome = getenv("ORACLE_HOME"), cmd[BUFSZ];
char * fmt="/bin/mv %s/%s/* %s/%s";
int written = snprintf(cmd, BUFSZ, fmt, ohome, "A", ohome, "B"), ret;
if ((written < 0) || (written >= (BUFSZ-1))) {
/* ERROR: print error or ORACLE_HOME env var too long for BUFSZ. */
}
if ((ret = system(cmd)) == 0) {
/* OK, move succeeded. */
}
return 0;
}
As commenter Paul Kuliniewicz points out, unexpected results may ensue if your ORACLE_HOME contains spaces or other special characters which may be interpreted by the subshell in the "system" command. Using one of the execl or execv family will let you build the arguments without worrying about the shell interpreter doing it's own interpretation but at the expense of using wildcards.
First of all as pointed out before, this "security" of yours is completely useless. It is trivial to intercept the files being copied (there are plenty of tools to monitor file system changes and such), but that is another story.
This is how you could do it, for the first part. To do the actual copying, you'd have to either use system() or read the whole file and then write it again, which is kind of long for this kind of quick copy.
int main(int argc, char *argv[]){
char *home, *tmp2;
home = strdup(getenv("ORACLE_HOME"));
tmp2 = strdup(getenv("ORACLE_HOME"));
home = realloc(home, strlen(home)+strlen("A")+1);
tmp2 = realloc(tmp2, strlen(tmp2)+strlen("B")+1);
strcat (home,"A");
strcat (tmp2,"B");
}
By the way, if you could stand just moving the file, it would be much easier, you could just do:
rename(home,tmp2);
Not realted to what you are asking, but a comment on your code:
You probably won't be able to strcat to the results of a getenv, because getenv might (in some environments) return a pointer to read-only memory. Instead, make a new buffer and strcpy the results of the getenv into it, and then strcat the rest of the file name.
The quick-n-dirty way to do the transferring is to use the cp shell command to do the copying, but invoke it using the system command instead of using a shell script.
Or, have your C program create a shell script to do the copying, run the shell script, and then delete it.

Executing "echo $PATH" from a c program?

I am trying to display, set & modify PATH environment variable from a C program. I am doing something like this:-
char *cmd[] = { "echo", "$PATH", (char *)0 };
if (execlp("echo", *cmd) == -1)
But I am not getting the results.
You should use getenv(), there's no need to go through a shell:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("PATH='%s'\n", getenv("PATH"));
return EXIT_SUCCESS;
}
But you won't be able to change the value. Environment variables are inherited into child processes, but the child has its own copy. You can't change the shell's environment from a different program, regardless in which language it's written. You can of course change your own process' value, but that's not what you asked to do.
In the shell itself, you can change its current environment settings, but only there. This is why you need to use "source" to run shells scripts that change the environment.
If you want to display $PATH, try this:
#include <stdlib.h>
printf("PATH: %s\n",getenv("PATH"));
if you want to modify it, use setenv() or putenv().
try this:
char *cmd[] = { "$PATH", (char *)0 };
if (execlp("echo", cmd) == -1)
#include <stdio.h>
#include <stdlib.h>
...
char *pPath;
pPath = getenv("PATH");
if (pPath!=NULL)
printf ("The current path is: %s",pPath);
putenv("PATH=somepath");
...
Better solutions already given, but by way of explanation; the $PATH variable is parsed and translated by the command shell, not the echo command itself. The solutions already suggested use getenv() to obtain the environment variable's value instead.
To invoke the command shell to perform this:
system( "echo $PATH" ) ;
but that solution is somewhat heavyweight since it invokes a new process and the entire command processor just to do that.

Resources