哈哈哈,看到标题是不是以为strace是编程语言呢?不是啦,小镇为了学习strace足足准备了一个多星期,而这次终于是吧strace的文章放了出来,哎,怎么说呢,strace出来的还是有相当多的函数看不太懂,不过这次咱这次就来个strace的入门,简称strace之helloworld。
strace是一个有用的小工具 – 大多数Linux系统默认已经安装 – 可以通过跟踪系统调用来让你知道一个程序在后台所做的事情。Strace是一个基础的调试工具;但是即便你不是在跟踪一个问题的时候它也是一个极好的软件。它能告诉你很多关于一个Linux程序怎样工作的信息。
我们这次用c语言写了一个helloworld的程序,然后编译完之后去strace,让我们看看一个基本的helloworld经过了哪些系统调用。首先编译:gcc -o helloworld helloworld.c 然后执行命令strace ./helloworld。最后弹出strace出来的内容。好了,在这里给大家截张图吧。如下图所示:
下面我们来一行一行的去解释:
第一行:execve("./helloworld", ["./helloworld"], [/* 28 vars */]) = 0
我们前面有一篇博文是关于linux的execve函数的,大家可以调出来看看,方便学习。execve是linux执行命令的函数,第一个参数./helloworld是命令的所在路径,很明显路径就是本目录下的helloworld,然后第二个是命令的集合,命令本身也是./helloworld并且不带参数,第三个参数是环境变量集,这个大家不用管。
第二行:brk(0)
brk是c库函数而不是系统调用,一般来说系统调用通常是提供了最小最基本的功能,而库函数通常提供比较复杂的功能,brk是从堆中分配空间,本质是移动一个位置,向后移就是分配空间,向前移就是释放空间,而brk(0)是用来返回比较精确的虚拟内存的使用情况,在这里可以理解为内核需要详细了解虚拟空间的使用情况。
第三行&第四行:mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b0ebc632000
这边的mmap大家可以看到参数是flag参数是MAP_ANONYMOUS,然后fd文件描述符是-1,证明这个mmap是一个匿名映射,也就是说建立一个没有与文件映射的映射区,这边与第四行的作用咱们不得而知。因为具体的代码的运作我们是看不出来的。strace只是看到了系统调用而已,不过这对我们理解这次的strace一点关系都没有。
第五行:access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
还记得我以前写的一个关于教你做黑客的文章么,这里的ld.so.preload就是用来预加载共享库的环境变量的文件。不过这里我们没有用来预加载的共享库,所以自然返回的是No suck file or directory了。
第六行:open("/etc/ld.so.cache", O_RDONLY) = 3
然后我们需要打开动态链接库的加载缓存文件,打开后返回值为3的文件描述符。
第七行:fstat(3, {st_mode=S_IFREG|0644, st_size=94316, ...}) = 0
获取该文件描述符所指向文件的状态和属性,就是刚刚的动态链接库的加载缓存文件的文件状态。
第八行:mmap(NULL, 94316, PROT_READ, MAP_PRIVATE, 3, 0) = 0x2b0ebc634000
将这个缓存文件映射到虚拟内存中,恩,这个94316的大小就是用过fstat获取到的。
第九行:close(3)
将该文件描述符关闭。
第十行到第十七行:同样是一系列的操作,知不过就是操作的从ld.so.cache中读到的libc.so.6文件,并且读入ld.so.cache中的内容:
十八行到二十二行:对内存的一系列的操作,这边的操作只能看看表面的意思,具体在干嘛谁知道呢?
第二十三行:fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
获取标准输出文件描述符的状态
第二十五行:write(1, "Helloworld\n", 11) = 11
将Helloworld写入到标准输出的文件中去。最后通过exit_group终止线程组,大家可以看到,知识量是很大的,如果想完全的看懂strace的过程,基本上要对linux的内核函数有非常深入的理解才行,所以向我们这种运维才需要用到strace的网络安全工程师来说,大概适度的了解是最好的。