Turn from: http://blog.csdn.net/ljx0305/article/details/9152523
Yesterday, someone in the belly group asked Linux under C How to get the program absolute path. First look at this problem, belly feel very simple ah, with GETCWD or argv[0] on it. Write a program to try, #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 getpath.c found, getcwd not, this function returns the execution path at that time, if the program is executed in another directory, such as ~/. This call is not.
Argv[0] Also no, the first parameter of the program may not be an absolute path, such as using/home/. /.. /root/getpath This call, the first argument becomes such a relative path. Belly improved this program, using Realpath to convert the relative path to absolute path: #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. This time argv[0] solves the problem with a relative path call.BUGSBut then the belly also found that there is another problem, such as putting the program into the/usr/bin of the environment variables in the path of the directory, and then in the/home directory through the program name directly to execute the program, the output of the program absolute path becomes/home/getpath, in fact, should be Usr/bin/getpath.is there any information in the elf file ?There is no other way, the belly first tried under this elf file is there some absolute path information. Executive: Strings getpath| The grep GetPath is naturally not found. In the other direction, if the absolute path information is kept in the elf file, change the path of the program, and the contents of the program will be modified. So it is impossible to drop.attempt to fetch from process memoryThen this absolute path of information, only when the program is running, add to the process space. Let's see if we can get the process memory.
Write a code look at the system's memory address distribution: #include <stdio.h> #include <string.h> #include <stdlib.h> int a = 0; Global initialization region char *P1; Global uninitialized zone main (int argc,char **argv) {int b;//stack char s[] = "abc";//Stack char *p2;//stack char *p3 = "123456";//123456 The P3 is in the constant area and 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); Areas that are allocated 10 and 20 bytes are in the heap area. strcpy (P1, "123456");//123456\0 is placed in the constant area, the compiler may optimize it and P3 point to "123456" into a place. printf ("Heap P1 \t\t\t%p\n", p1); printf ("Heap P2 \t\t\t%p\n", p2); printf ("Stack &p3 \t\t\t%p\n", &P3); printf ("Stack &p2 \t\t\t%p\n", &P2); printf ("Stack s \t\t\t%p\n", s); printf ("Stack &s[1] \t\t%p\n", &s[1]); printf ("Stack &b \t\t\t%p\n", &b); printf ("Main address \t\t%p\n", main); printf ("Text constant area \t\t%p\n", p3); printf ("Global initialization area \t\t%p\n", &a); printf ("(Static) initialization area \t%p\n", &c); printf ("Global uninitialized Zone \t\t%p\n", &P1); printf ("(Static) uninitialized zone \t%p\n", &UC); printf ("(Static) uninitialized zone \t%p\n", &UC1); printf ("(Static) uninitialized zone \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 to point out, because the belly of the system is x86-64.64 for the system, here with GCC print address is to pay attention to the use of%p, do not use%x. You can view the system version with Uname-a. Compile: gcc-wall-pipe-g-static-o memoryshow memoryshow.c execution, the result is: [Root@localhost ~]# the ./memoryshow heap P1 0xa3e8b0 heap p2 &NBS P &NBSP;0XA3E8D0 stack &p3 0X7FFF94FEC4A0 Stack &p2 0X7FFF94FEC4A8 Stack s &NB Sp 0X7FFF94FEC4B0 Stack &s[1] 0X7FF F94FEC4B1 Stack &b &NBSP;0X7FFF94FEC4B4 main address &nbsP 0x400494 text constant area &NBSP;0X47F3B0 Global Initialization area &NBSP;0X6A6E50 (Static) initialization area &NBSP;0X6A6E54 global uninitialized zone &NBSP;0X6A9BA8 (static) uninitialized zone 0x6a6e58 (static) uninitialized zone &NBSP;0X6A6E5C (static) uninitialized zone   ; 0x6a6e60 user=0x7fff94fece29 ARGC 0x7fff94fec49c ARGV 0x7fff94fec598 ARGV & nbsp;0x7fff94fec82b View the map for this process: [Root@localhost ~]# Ps-ef | grep showmemory root 2715 2150 0 21:58 pts/1 00:00:00 grep showmemory [root@l Ocalhost ~]# Ps-ef | grep memory root 2713 2087 0 21:58 pts/0 00:00:00./memoryshow Root &N Bsp 2717 2150 0 21:58 pts/1 00:00:00 grep memory [root@localhost ~]# cat/proc/2713/maps 00400000-004a6000 R-xp 00000000 fd:00 524196 /root/memoryshow 006a60 00-006a7000 rw-p 000a6000 fd:00 524196 /root/memoryshow 006a7000-006aa000 Rw-p 00000000 00:00 0 00a3d000-00a60000 rw-p 00000000 00:00 0 [he AP] 7f050a5c2000-7f050a5c3000 rw-p 00000000 00:00 0 7fff94fd8000-7fff94fed000 rw-p 00000000 00:00 0 & nbsp [stack] 7fff94fff000-7fff95000000 R-xp 00000000 00:00 0 &NBSP;[VDSO] FFF Fffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 &NBSP;[V Syscall] Repeat it again.To do, the belly needs to look at the process which addresses will change, those will not change. The online general 32 is linear distribution, and the belly of the system is not the number. So write a program on your own to see it clearly. [Root@localhost ~]# ./memoryshow heap p1 0x76b8b0 Heap P2 &NBSP;0X76B8D0 stack &p3 &NBS P 0X7FFF9987A9F0 stack &p2 0X7FFF9 987a9f8 Stack s 0X7FFF9987AA00 Stack &s[1] & nbsp 0X7FFF9987AA01 stack &b & NBSP;0X7FFF9987AA04 main address 0x400494 text constant area &NBS P &NBSP;0X47F3B0 Global initialization area &NBSP;0X6A6E50 (Static) initialization area 0X6A6E54 Global uninitialized zone &NBSP;0X6A9BA8 (static) not initializedZone &NBSP;0X6A6E58 (static) uninitialized zone &NBSP;0X6A6E5C (static) uninitialized zone 0x6a6e60 USER=0X7FFF9 987ce29 ARGC &NBSP;0X7FFF9987A9EC ARGV 0x7fff9987aae8 ARGV 0x7fff9987c82b its corresponding map situation: [RO Ot@localhost ~]# cat/proc/2713/maps Cat:/proc/2713/maps:no such file or directory [root@localhost ~]# ps-ef | grep memory root 2719 2087 0 21:59 pts/0 00:00:00./memoryshow Root &N Bsp 2722 2150 0 21:59 pts/1 00:00:00 grep memory [root@localhost ~]# cat/proc/2719/maps 00400000-004a6000 R-xp 00000000 fd:00 524196 /root/memoryshow 006a6000-006a7000 rw-p 000a6000 fd:00 524196 &NBS P /root/memoryshow 006a7000-006aa000 Rw-p 00000000 00:00 0 007 6a000-0078d000 Rw-p 00000000 00:00 0 & nbsp [heap] 7f9987494000-7f9987495000 rw-p 00000000 00:00 0 7fff99868000-7fff9987d000 rw-p 00000000 00:00 0 [stack] 7fff999 Ff000-7fff99a00000 r-xp 00000000 00:00 0 &NBSP;[VDSO] Ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 &NBSP ; [vsyscall] Here you can see that the addresses of the previous three segments are unchanged, but the heap starts, and the high address segments that follow will change each time. If the data containing the absolute path of the file is dropped in the first three segments, it can be obtained directly from the address, if it is in the back, it may be obtained by calculation. Debug with GDB to see what happens: [root@localhost ~]# gdb memoryshow Reading symbols from/root/memoryshow...done. (GDB) B main breakpoint 1 at 0x4004a3:file memoryshow.c, line 11. (GDB) R starting program:/root/memoryshow Breakpoint 1, Main (argc=1, ARGV=0X7FFFFFFFE5C8) at Memoryshow.c:11 char s[] = "ABC"; Stack (GDB) B-Breakpoint 2 at 0x4006db:file Memoryshow.c, line 44. (GDB) C continuing. Heap P1 0x6ab8b0 heap p2 & nbsp &NBSP;0X6AB8D0 stack &p3 0X7FFFFFFFE4D0 Stack &p2 0X7FFFFFFFE4D8 Stack s &NB Sp 0X7FFFFFFFE4E0 Stack &s[1] 0X7FF FFFFFE4E1 Stack &b &NBSP;0X7FFFFFFFE4E4 main address 0x400494 text constant area &NBSP;0X47F3B0 Global Initialization Zone & nbsp &NBSP;0X6A6E50 (Static) initialization area &NBSP;0X6A6E54 Global uninitialized Zone   &NBSP;0X6A9BA8 (static) uninitialized zone 0x6a6e58 (static) uninitialized zone &NBSP;0X6A6E5C (static) not initialized District 0x6a6e60 user=0x7fffffffedff ARGC 0x7fffffffe4cc ARGV &NBSP;0X7FFFFFFFE5C8 ARGV 0x7fffffffe81b Breakpoint 2, Main (argc=1, ARGV=0X7FFFFFFFE5C8) at memoryshow.c:45 & Nbsp;sleep (300); (gdb) x/30s 0x7fffffffedff 0x7fffffffedff: "/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" 0x7fffffffeed5: "Pwd=/root" 0X7FFFFFFFEEDF: "Java_home=/usr/local/jrockit" 0X7FFFFFFFEEFC: "LANG= en_US. UTF-8 "0x7fffffffef0d: " Configdir=/data/config "0x7fffffffef24: " lines=43 "0x7fffffffef2d: " Histcontrol=ignoredups "0X7FFFFFFFEF44: &nbsP; " Home=/root "0X7FFFFFFFEF4F: " shlvl=1 "0x7fffffffef57: " M2_home=/usr/local/maven "0x7fffffffef70: " Logname=root "0x7fffffffef7d: " ssh_connection=192.168.0.158 62555 192.168.0.98 "0x7fffffffefb0: " Lessopen=|/usr/bin/lesspipe.sh%s "0X7FFFFFFFEFD2: " G_broken_filenames=1 "0x7fffffffefe7: "/root/ Memoryshow " <– note here 0x7fffffffeff8: " "0X7FFFFFFFEFF9: " "0x7fffffffeffa: " " 0X7FFFFFFFEFFB: "" 0X7FFFFFFFEFFC: "" 0X7FFFFFFFEFFD: "" 0x7fffffffeffe: "" 0X7FFFFFFFEFFF: & nbsp; "" 0x7ffffffff000: <address 0x7ffffffff000 out of the bounds> 0x7ffffffff000: <address 0x7ffffffff000 out Bounds> 0x7ffffffff000: <address 0x7ffffffff000 out of bounds> 0x7ffffffff000: <Address 0x7ffffffff000 out of bounds> Here you can see that the absolute path to running the program is saved in Envstring, while Envstring is in the stack, and the stack address changes every time it runs. And if you continue to test, you can also find that the way the call is different, this absolute path corresponds to the location of the stack start address is also different. And the machine is different, the algorithm is also different. So getting the absolute path directly from the process memory is not very reliable. get from/proc/self/exeBelly check on the internet, the most common method is to use the process mapping file, with Readlink read/proc/self/ EXE this symbolic link to the file. Insert a paragraph, how to determine the link is a symbolic link or a hard link, mainly to see the file inode, the same is hard link, is not the same as symbolic links. View with Ls-li. A piece of code found on the Internet: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define maxbufsize 1024 int mai n (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] = ' I '; printf ("/proc/self/exe-> [%s]\n", buf); return (exit_success); }/* End of main * *EXE file permissions issueSome people may worry about/proc/self/exe This file permissions problem, belly feel no need to worry, the directory of file permissions are confirmed by the system, users can not be modified. So read the map of their process in the proc directory, user rights must be there. If you read the mapping directory of programs that other users are running under/proc, you may not have permission.
Remark: The content of the article is from the belly lighting month personal real understanding and some knowledge of the online summary, rather than deliberately to speculate on the intentional fools eyes and ears. Due to the limited personal level, although the content is correct, but still inevitable mistakes, please do not mind, if you can leave a message to tell.