Methods for obtaining absolute paths in C Programs in Linux

Source: Internet
Author: User
Someone in the group yesterday asked Linux C how to obtain the absolute path of the program. When I first read this question, I thought it was very simple. Just use getcwd or argv [0. I wrote a program and tried it,
# Include <unistd. h> int main (INT argc, char * argv []) {char buffer [100]; getcwd (buffer, sizeof (buffer); printf ("the current directory is: % s \ n ", buffer); printf (" prog name: % s \ n ", argv [0]); Return 0 ;}
Compile:
Gcc-wall-pipe-g-static-O getpath. c
It is found that getcwd does not work. This function returns the current execution path. If you execute this program in another directory, such ~ /. The call will not work.
Argv [0] does not work either. The first parameter of the program may not be an absolute path, for example,/home /.. /.. /root/getpath is called in this way, and the first parameter becomes the relative path. This program is improved by using realpath to convert relative paths to absolute paths:
# Include <unistd. h> main (INT argc, char * argv []) {char resolved_path [80]; realpath (argv [0], resolved_path); printf ("resolved_path: % s \ n ", resolved_path); sleep (300 );}
OK. At this time, argv [0] is resolved by calling the relative path. Bugs, but later I found another problem. For example, put the program in the directory of the/usr/bin environment variable path, then execute the program directly in the/Home Directory through the program name. The absolute path of the output program is/home/getpath, which should be/usr/bin/getpath. There is no other way to check whether there is any relevant information in the ELF File. First, I tried whether there is any absolute path information in this ELF File.
Execute: strings getpath | grep getpath
Naturally, it cannot be found. In another direction, if the absolute path information is stored in the ELF file, the path of a program is changed and the content of the program must be modified? So it is impossible to drop. Try to get the absolute path information from the process memory. It can only be added to the process space when the program is running. Let's see if the process memory can be obtained?
Write a code to check the memory address distribution of the system:
# Include <stdio. h> # include <string. h> # include <stdlib. h> int A = 0; // global initialization zone char * P1; // global uninitialized Zone Main (INT argc, char ** argv) {int B; // stack char s [] = "ABC"; // stack char * P2; // stack char * P3 = "123456"; // 123456 \ 0 in the constant area, p3 is on the stack. Static int C = 0; // global (static) initialization zone static int UC, uc1, UC2; // global (static) uninitialized zone p1 = (char *) malloc (10); P2 = (char *) malloc (20); // The allocated 10 and 20 bytes are in the heap zone. Strcpy (P1, "123456"); // 123456 \ 0 is placed in the constant area, and the compiler may optimize it into a place with the "123456" pointed to by P3. Printf ("heap P1 \ t % P \ n", P1); printf ("heap P2 \ t % P \ n", P2 ); printf ("Stack & P3 \ t % P \ n", & P3); printf ("Stack & p2 \ t % P \ n ", & p2); printf ("Stack s \ t % P \ n", S ); printf ("Stack & S [1] \ t % P \ n", & S [1]); printf ("Stack & B \ t % P \ n", & B); printf ("main address \ t % P \ n", main ); printf ("text constant Zone \ t % P \ n", P3); printf ("global initialization Zone \ t % P \ n", & ); printf ("(static) initialization Zone \ t % P \ n", & C); printf ("Global uninitialized Zone \ t % P \ n ", & P1); printf ("(static) uninitialized Zone \ t % P \ n", & UC); printf ("(static) uninitialized partition \ t % P \ n ", & uc1); printf (" (static) uninitialized partition \ t % P \ n ", & UC2); char * P; if (P = getenv ("path") {printf ("user = % P \ n", P);} printf ("argc \ t % P \ n ", & argc); printf ("argv \ t % P \ n", argv); printf ("argv \ t % P \ n", * argv ); sleep (300 );}
Here I want to point out, because the belly system is x86-64.64 for the system, here with GCC print address is to note that the use of % P, do not use % x. you can use uname-a to view the system version.
Compile: gcc-wall-pipe-g-static-O memoryshow. c
Run the command. The result is:
[Root @ localhost ~] #. /Memoryshow heap P1 0xa3e8b0 heap P2 0xa3e8d0 stack & P3 0x7fff94fec4a0 stack & p2 0x7fff94fec4a8 stack S release stack & S [1] Release stack & B release address 0x400494 text constant zone 0x47f3b0 zone 0x6a6e50 (static) initialization zone 0x6a6e54 global uninitialized zone 0x6a9ba8 (static) uninitialized zone 0x6a6e58 (static) uninitialized zone 0x6a6e5c (static) uninitialized zone 0x6a6e60user = 0000000000000x7fff94fec82b
View the map of the process:
[Root @ localhost ~] # Ps-Ef | grep showmemoryroot 2715 2150 0 00:00:00 pts/1 grep showmemory [root @ localhost ~] # Ps-Ef | grep memoryroot 2713 2087 0 00:00:00 pts/0 00:00:00./memoryshowroot 2717 2150 0 pts/1 grep memory [root @ localhost ~] # Cat/proc/2713/maps 00400000-004a6000 R-XP 00000000 FD: 00 524196/root/memoryshow006a6000-006a7000 RW-P 000a6000 FD: 00 524196/root/memoryshow006a7000-006aa000 RW-P 00000000 0 00a3d000-00a60000 RW-P 00000000 0 [heap] 1_rw-P 00000000 0 7fff94fd8000-7fff94fed000 RW-P 00000000 0 [Stack] Running r-XP 00000000 0 [vdso] ffffffffff600000-ffffffffff601000 R-XP 00000000 0 [vsyscall]
Repeat the operation again to check which process addresses will change and those will not change. Generally, 32 is a linear distribution on the Internet, which is not the same as that of the belly system. Therefore, you can write a program clearly.
[Root @ localhost ~] #. /Memoryshow heap P1 0x76b8b0 heap P2 0x76b8d0 stack & P3 comment stack & p2 comment stack s 0x7fff9987aa00 stack & S [1] 0x7fff9987aa01 stack & B comment address 0 × 400494 text constant zone 0x47f3b0 zone 0x6a6e50 (static) initialization zone 0x6a6e54 global uninitialized zone 0x6a9ba8 (static) uninitialized zone 0x6a6e58 (static) uninitialized zone 0x6a6e5c (static) uninitialized zone 0x6a6e60user = 0000000000000x7fff9987c82b
The corresponding map:
[Root @ localhost ~] # Cat/proc/2713/maps Cat:/proc/2713/maps: no such file or directory [root @ localhost ~] # Ps-Ef | grep memoryroot 2719 2087 0 00:00:00 pts/0 00:00:00./memoryshowroot 2722 2150 0 pts/1 grep memory [root @ localhost ~] # Cat/proc/2719/maps 00400000-004a6000 R-XP 00000000 FD: 00 524196/root/memoryshow006a6000-006a7000 RW-P 000a6000 FD: 00 524196/root/memoryshow006a7000-006aa000 RW-P 00000000 0 0076a000-0078d000 RW-P 00000000 0 [heap] 7f9987494000-7f9987495000 RW-P 00000000 0 1_rw-P 00000000 0 [Stack] Warning r-XP 00000000 0 [vdso] ffffffffff600000-ffffffffff601000 R-XP 00000000 0 [vsyscall]
Here we can see that the addresses of the first three segments remain unchanged, but at the beginning of the heap, the next high segment will change every operation. If the data that contains the absolute path of the file falls in the first three segments, you can directly obtain the data through the address. If the data is in the back, it may be obtained through calculation. Debug with GDB to see what the situation is:
[Root @ localhost ~] # GDB memoryshowreading symbols from/root/memoryshow... Done. (GDB) B mainbreakpoint 1 at 0x4004a3: file memoryshow. c, line 11. (GDB) rstarting program:/root/memoryshow breakpoint 1, main (argc = 1, argv = 0x7fffffffe5c8) at memoryshow. c: 1111 char s [] = "ABC"; // stack (GDB) B 44 breakpoint 2 at 0x4006db: file memoryshow. c, line 44. (GDB) ccontinuing. heap P1 0x6ab8b0 heap P2 0x6ab8d0 stack & P3 Primary stack & P2 Primary stack s primary stack & S [1] 0x7fffffffe4e1 stack & B primary address 0 × 400494 text constant zone 0x47f3b0 global initialization zone 0x6a6e50 (static) initialization zone 0x6a6e54 global uninitialized zone 0x6a9ba8 (static) uninitialized zone 0x6a6e58 (static) uninitialized zone 0x6a6e5c (static) uninitialized zone 0x6a6e60user = 255.255.255.255.255.255.breakpoint 2, main (argc = 1, argv = 0x7fffffffe5c8) at memoryshow. c: 4545 sleep (300); (GDB) x/30 s 0x7fffffffedff0x7fffffedff: "/usr/local/Maven/bin:/usr/local/sbin: /usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/jrockit/bin: /usr/local/redis/bin:/usr/local/MySQL/bin:/root/bin "0x7fffffffee9c:" mail =/var/spool/mail/root "0x7fffffffeeb6: "nodename = _ 0_218" 0x7fffffffeec6: "_ =/usr/bin/GDB" restart: "Pwd =/root" 0x7fffffffeedf: "java_home =/usr/local/jrockit" restart: "lang = en_US.UTF-8" 0x7fffffffef0d: "configdir =/data/config" 0x7fffffffef24: "lines = 43" Leading: "histcontrol = ignoredups" 0x7fffffffef44: "home =/root" Leading: "shlvl = 1" 0x7fffffffef57: "m2_home =/usr/local/Maven" restart: "LOGNAME = root" 0x7fffffffef7d: "ssh_connection = 192.168.0.158 62555 192.168.0.98 22" restart: "lessopen = |/usr/bin/lesspipe. sh % s "Usage:" g_broken_filenames = 1 "0x7fffffffe7:"/root/memoryshow "<-note:" "0x7fffffffeff9:" "0x7fffffffeffa:" "Usage: "" comment: "" comment: "" 0x7fffffffeffe: "" comment: "" comment: <address 0x7ffffffff000 out of bounds> 0x7ffffffff000: <address 0x7ffffff000 out of bounds> comment: <address 0x7ffffff000 out of bounds> 0x7ffffffff000: <address 0x7ffffffff000 out of bounds>
Here we can see that the absolute path of the program running is saved in the envstring, while the envstring is in the stack, and the stack address changes every time it runs. In addition, if you continue the test, you can also find that the call method is different, and the location of the absolute path corresponding to the stack start address is also different. In addition, algorithms vary with machines. Therefore, it is not reliable to obtain the absolute path directly from the process memory. You have obtained a belly map from/proc/self/EXE and checked it online. The most common method is to use the process ing file, use readlink to read the file pointed to by the/proc/self/EXE symbolic link. insert a section, how to determine whether the link is a symbolic link or a hard link, mainly depends on the inode of the file, the same is a hard link, the difference is a symbolic link. Use LS-Li to view the logs. A piece of code found on the Internet:
# Include <stdio. h> # include <stdlib. h> # include <unistd. h> # define maxbufsize 1024 int main (INT argc, char * argv []) {char Buf [maxbufsize]; int count; count = readlink ("/proc/self/EXE", Buf, maxbufsize); If (count <0 | count> = maxbufsize) {printf ("failed \ n "); return (exit_failure);} Buf [count] = '\ 0'; printf ("/proc/self/Exe-> [% s] \ n", Buf ); return (exit_success);}/* end of main */
Some people may worry about the permission of the file/proc/self/EXE. The system determines the file permission in the directory, users cannot be modified. Therefore, the system reads the ing directory of its own process under the proc directory, and the user permission is certainly there. If you want to read the ing directories of programs run by other users under/proc, you may not have the permission.

Note:The content of this article is based on my personal understanding and summary of some online knowledge, rather than thinking about what you mean. Due to the limited personal level, although the content is correct, it is still inevitable to make mistakes, please do not blame, if you can leave a message.

 

Http://www.wjthink.org /? P = 522

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.