分享
 
 
 

Linux 编程之获取应用程序的绝对路径

王朝system·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

经常看到有人提问在linux中如何获取当前应用程序的绝对路径, 却很少有人能比较好的解答. 现转贴www.linuxforum.net上的一篇文章, 希望能对受这个问题困扰的人有帮助.

13.12 如何获取当前进程对应之静态映像文件的绝对路径

A: hushui110@水木清华

这是一个x86/Linux Kernel 2.4.7-10系统中利用proc获取绝对路径的例子

--------------------------------------------------------------------------

/*

* gcc -Wall -pipe -g -static -o myprog_2 myprog_2.c

*/

#include

#include

#include

#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 */

--------------------------------------------------------------------------

[scz@ /home/scz/src]> echo $PATH

/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:.

[scz@ /home/scz/src]> ./myprog_2

/proc/self/exe -> [/home/scz/src/myprog_2]

[scz@ /home/scz/src]> ../src/myprog_2

/proc/self/exe -> [/home/scz/src/myprog_2]

[scz@ /home/scz/src]> myprog_2

/proc/self/exe -> [/home/scz/src/myprog_2]

[scz@ /home/scz/src]>

显然这里直接给出了最期待的结果,没有冗余信息。

A: scz & microcat

2000-03-18

下面在x86/Linux Kernel 2.4.7-10上演示、讨论

--------------------------------------------------------------------------

*

* gcc -Wall -pipe -g -static -o myprog myprog.c

*/

#include

#include

int main ( int argc, char * argv[] )

{

return( EXIT_SUCCESS );

} /* end of main */

--------------------------------------------------------------------------

[scz@ /home/scz/src]> gcc -Wall -pipe -g -static -o myprog myprog.c

[scz@ /home/scz/src]> echo $PATH

/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:.

[scz@ /home/scz/src]> gdb ./myprog

(gdb) b main

(gdb) r

(gdb) x/17s 0xbfffff00

0xbfffff00: "SHLVL=1"

0xbfffff08: "_=/bin/bash"

0xbfffff14: "SHELL=/bin/bash"

0xbfffff24: "HOSTTYPE=i386"

0xbfffff32: "OSTYPE=linux-gnu"

0xbfffff43: "HISTSIZE=1000"

0xbfffff51: "TERM=vt100"

0xbfffff5c: "HOME=/home/scz"

0xbfffff6b: "SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass"

0xbfffff9e: "PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:."

0xbfffffd2: "LESSCHARSET=latin1"

0xbfffffe5: "/home/scz/src/./myprog" <-- 注意这个输出

0xbffffffc: ""

0xbffffffd: ""

0xbffffffe: ""

0xbfffffff: ""

0xc0000000:

[scz@ /home/scz/src]> gdb myprog

(gdb) b main

(gdb) r

(gdb) x/17s 0xbfffff00

0xbfffff00: "z"

0xbfffff02: "SHLVL=1"

0xbfffff0a: "_=/bin/bash"

0xbfffff16: "SHELL=/bin/bash"

0xbfffff26: "HOSTTYPE=i386"

0xbfffff34: "OSTYPE=linux-gnu"

0xbfffff45: "HISTSIZE=1000"

0xbfffff53: "TERM=vt100"

0xbfffff5e: "HOME=/home/scz"

0xbfffff6d: "SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass"

0xbfffffa0: "PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:."

0xbfffffd4: "LESSCHARSET=latin1"

0xbfffffe7: "/home/scz/src/myprog" <-- 注意这个输出

0xbffffffc: ""

0xbffffffd: ""

0xbffffffe: ""

0xbfffffff: ""

[scz@ /home/scz/src]> gdb ../src/myprog

(gdb) b main

(gdb) r

(gdb) x/17s 0xbfffff00

0xbfffff00: "=1"

0xbfffff03: "_=/bin/bash"

0xbfffff0f: "SHELL=/bin/bash"

0xbfffff1f: "HOSTTYPE=i386"

0xbfffff2d: "OSTYPE=linux-gnu"

0xbfffff3e: "HISTSIZE=1000"

0xbfffff4c: "TERM=vt100"

0xbfffff57: "HOME=/home/scz"

0xbfffff66: "SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass"

0xbfffff99: "PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:."

0xbfffffcd: "LESSCHARSET=latin1"

0xbfffffe0: "/home/scz/src/../src/myprog" <-- 注意这个输出

0xbffffffc: ""

0xbffffffd: ""

0xbffffffe: ""

0xbfffffff: ""

0xc0000000:

[scz@ /home/scz/src]>

这是ELF文件在Linux系统中加载进内存之后的布局简图

--------------------------------------------------------------------------

0x08048000 code .text,代码,只读

data .data,包含已经初始化的数据,只读

bss .bss,未初始化数据,初始化成0,读/写

... 堆区,动态分配获取的内存从.bss往内存高端增长

... (heap),读/写

...

stack 栈区,起始地址大于0xBFFF0000

arguments main()的形参

environment 环境变量区域

program name execve()第一形参,不是argv[0]

0xBFFFFFFC null(dword) 最后四个字节固定为零

0xC0000000

--------------------------------------------------------------------------

通常动态链接库被映射到0x40000000往高端的地址。对于Linux,如果打了不可执行

堆栈内核补丁,动态链接库被映射到0x40000000往低端的地址。tt说就是以前的映射

地址减去0x40000000。打了补丁后使得通过字符串拷贝(strcpy)传递shellcode相对

复杂化,需要更多技巧。

program name处不一定是绝对路径,实际对应了execve()第一形参。一般从shell上

启动进程,shell根据PATH环境变量自动搜索匹配出一个路径,未必是绝对路径。假

设PATH环境变量中有当前目录(.),所执行的程序也只在当前目录下有,直接指定程

序名(myprog)执行时,shell会向execve()第一形参传递"./myprog"。注意,execve

第一形参未必是绝对路径。用gdb加载后再执行,情况有所不同。如果gdb命令行上指

定的程序名非绝对路径,gdb在调用execve()之前会调用getcwd()拼接在程序名之前,

此时不依赖PATH环境变量。所以用gdb调试溢出程序时应该在命令行上指定绝对路径,

避免不必要的偏移调整。

现在来看这样一个演示程序

--------------------------------------------------------------------------

/*

* gcc -Wall -pipe -g -static -o myprog_1 myprog_1.c

*/

#include

#include

extern char **environ;

int main ( int argc, char * argv[] )

{

char *path = ( char * )( 0xc0000000 - 5 );

while ( *--path );

++path;

printf( "path --> %08x [%s]\n", ( unsigned int )path, path );

printf( "argv --> %08x\n", ( unsigned int )argv );

printf( "argv[0] --> %08x [%s]\n", ( unsigned int )argv[0],

argv[0] );

printf( "environ --> %08x\n", ( unsigned int )environ );

printf( "environ[0] --> %08x [%s]\n", ( unsigned int )environ[0],

environ[0] );

return( EXIT_SUCCESS );

} /* end of main */

--------------------------------------------------------------------------

直接执行,然后用gdb加载后执行,对比输出上的不同。

[scz@ /home/scz/src]> myprog_1

path --> bffffff1 [./myprog_1] <-- 注意这里前面多了一个"./"

argv --> bffffb24

argv[0] --> bffffc29 [myprog_1]

environ --> bffffb2c

environ[0] --> bffffc32 [PWD=/home/scz/src]

[scz@ /home/scz/src]> ./myprog_1

path --> bffffff1 [./myprog_1]

argv --> bffffb24

argv[0] --> bffffc27 [./myprog_1]

environ --> bffffb2c

environ[0] --> bffffc32 [PWD=/home/scz/src]

[scz@ /home/scz/src]> ../src/myprog_1

path --> bfffffec [../src/myprog_1]

argv --> bffffb14

argv[0] --> bffffc18 [../src/myprog_1]

environ --> bffffb1c

environ[0] --> bffffc28 [PWD=/home/scz/src]

[scz@ /home/scz/src]>

Linux系统中main()函数里自修改argv[0]欺骗ps有效,而FreeBSD、Solaris则无效。

execve()第二形参可以指定不同于第一形参的argv[0]。argv[0]不可信,但execve()

第一形参相对就可信得多。如果是自己写程序,可以考虑在main()中第一时刻判断

execve()第一形参是否为相对路径,进而决定是否调用getcwd(),最后拼接出一个绝

对路径。就像gdb所做的那样。

需要考虑"/home/scz/src/./myprog"、"/home/scz/src/../src/myprog"这些情况,

消掉"./"、"../"等冗余信息。

A: scz & microcat

2002-09-13 18:00

下面在SARPC/Solaris 8 64-bit kernel mode上演示、讨论

--------------------------------------------------------------------------

/*

* gcc -Wall -pipe -g -static -o myprog_3 myprog_3.c

*/

#include

#include

extern char **environ;

static void outputBinary ( const unsigned char *byteArray, const size_t

byteArrayLen )

{

size_t offset, k, j, i;

fprintf( stderr, "byteArray [ %u bytes ] ----> \n", byteArrayLen );

if ( byteArrayLen <= 0 )

{

return;

}

i = 0;

offset = 0;

for ( k = byteArrayLen / 16; k > 0; k--, offset += 16 )

{

fprintf( stderr, "%08X ", offset );

for ( j = 0; j < 16; j++, i++ )

{

if ( j == 8 )

{

fprintf( stderr, "-%02X", byteArray[ i ] );

}

else

{

fprintf( stderr, " %02X", byteArray[ i ] );

}

}

fprintf( stderr, " " );

i -= 16;

for ( j = 0; j < 16; j++, i++ )

{

/*

* if ( isprint( (int)byteArray[ i ] ) )

*/

if ( ( byteArray[ i ] >= ' ' ) && ( byteArray[ i ]

<= 255 )

&& ( byteArray[ i ] != 0x7f ) )

{

fprintf( stderr, "%c", byteArray[ i ] );

}

else

{

fprintf( stderr, "." );

}

}

fprintf( stderr, "\n" );

} /* end of for */

k = byteArrayLen - i;

if ( k <= 0 )

{

return;

}

fprintf( stderr, "%08X ", offset );

for ( j = 0 ; j < k; j++, i++ )

{

if ( j == 8 )

{

fprintf( stderr, "-%02X", byteArray[ i ] );

}

else

{

fprintf( stderr, " %02X", byteArray[ i ] );

}

}

i -= k;

for ( j = 16 - k; j > 0; j-- )

{

fprintf( stderr, " " );

}

fprintf( stderr, " " );

for ( j = 0; j < k; j++, i++ )

{

if ( ( byteArray[ i ] >= ' ' ) && ( byteArray[ i ] <=

255 )

&& ( byteArray[ i ] != 0x7f ) )

{

fprintf( stderr, "%c", byteArray[ i ] );

[1] [2] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有