pwn入门-46-glibc源码调试
有时候需要看库函数哪里出问题了,有源码调试的话,看起来会更直观和方便
glibc源代码调试
开启gdb后 dir xxxx目录 即可
但dir命令加载源码只能指定单个目录或文件,在gdb启动的时候用这个命令来加载glibc源码进去就好了
1 | gdb `find ~/path/to/glibc/source -type d -printf '-d %p '` ./a.out |
当前机器版本libc
安装带调试版本libc
1 | apt install libc6-dbg |
下载对应的源代码
1 | 1. 修改/etc/apt/sources.list 开启deb-src (不知道是不是都要开) |
注意第三步会在当前目录进行下载
调试的时候进行指定即可: gdb -q ./pwn -d /xxx/xxx/glibc-2.31/
不同版本glibc下载与编译
官方下载与编译
https://ftp.gnu.org/gnu/glibc/
1 | git clone git://sourceware.org/git/glibc.git && cd glibc |
查看当前分支: git branch
查看有哪些分支: git branch -a
指定编译好的库进行文件编译
–rpath指定共享库路径 -I指定动态链接器
就可以用指定的libc来编译代码了, 这样的话, 也会很自然就有glibc的源代码可以调试了
1 | gcc -L/usr/local/glibc-2.31-debug/lib -Wl,--rpath=/usr/local/glibc-2.31-debug/lib -Wl,-I/usr/local/glibc-2.31-debug/lib/ld-2.31.so hello.c -o hello |
为什么不用加 -g了? (需要的,如果要看hello.c的源代码的话)
但是用glibcallinone下载的不行..有问题, 那是因为它只有编译好的库,没有头文件之类的吧?
glibc-all-in-one工具
这里是编译好的,一般都是带符号的,但是如果需要源代码调试还是需要下载源码并加载进gdb里面进行调试
https://blog.csdn.net/csdn546229768/article/details/122691241
如果网站里没有的话,就修改download源代码, 换个source看看,google精准搜索搜索一下
debug信息
符号文件在哪呢, 被编译进程序里了吧,我记得之前有单独的符号文件的
ls -al /usr/lib/debug/.build-id/这里有
1 | drwxr-xr-x 2 root root 4096 7月 27 10:48 . |
但是glibcallinone里没找到这个呀…
他们之间是什么关系呢?
libc编译案例
做一道题需要23版本的libc,用ubuntu20编译的有问题..换18试试 (也有很多报错, 难道得换debian?)
source是源码,右边是编译好的,但是没有符号信息
难道版本不对? 这个source看起来是没有什么问题的,下载后看了下源码文件
https://launchpad.net/ubuntu/xenial/amd64/libc6/2.23-0ubuntu11
http://launchpadlibrarian.net/409875491/libc6_2.23-0ubuntu11_amd64.deb
1 | mkdir build && cd build |
罢了……..还是报错….处理不了……..(回头试试16, 或者说 还是得换debian? 不纠结这个编译问题了…)
转机
https://launchpad.net/ubuntu/xenial/amd64/libc6-dbg/2.23-0ubuntu11
嘶,用了一下还是不太行
不过实际做题也未必要一模一样的环境,反正给了libc,可以从里面找偏移
报错处理
之前报错说要加–disable-werror, 但是好像也没啥用,
../configure –disable-werror –prefix=/usr/local/glibc-2.23 –enable-debug=yes
1 | error: argument 1 of type ‘struct __jmp_buf_tag *’ declared as a pointer [-Werror=array-parameter=] |
make[1]: *** [Makefile:214: stdio-common/subdir_lib] Error
https://www.cnblogs.com/zq10/p/14314952.html
https://gist.github.com/stefan1wan/5e4b3973aae578ac39f94d30a5555f19
make[2]: *** No rule to make target ‘../manual/errno.texi’, needed by ‘../sysdeps/gnu/errlist.c’. Stop
Inconsistency detected by ld.so: dl-call-libc-early-init.c: 37: _dl_call_libc_early_init: Assertion `sym != NULL’ failed!
问: 这里有现成的libc可以用,但是没有符号文件, 符号和源代码又是两回事吧
答: 是的,两回事
问: 没有符号咋办, 只能进行编译吗..
答: 我记得之前做海大ctf,ida可以导入符号文件,网上有编译好的符号文件,这个网站上也有symbol, 但是不全
问: gcc直接用这里的库编译会有问题,需要install?
问: 如何编译符号文件呢
调试案例
printf的调用路径
1 |
|
调试, bt追踪栈
1 | 0 0x00007ffff7e5ca69 in __printf (format=0x55555555600a "hello,%s\n") at printf.c:28 |
会发现进入的是__printf函数,为什么不是printf函数呢? 需要看libc源代码
进到这里是因为ldbl_strong_alias (__printf, printf); 将printf和 _ _ printf进入了的函数统一为 _ _printf
stdio-common/printf.c
1 |
|
__printf又主要调用了vfprintf函数,在stdio-common/vfprintf.c中, 这个函数有点长
函数完整加载过程
恩….比较复杂..有时间专门学习下..
原文地址: http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html
翻译: https://zhuanlan.zhihu.com/p/52054044
https://zhuanlan.zhihu.com/p/521205296
其他参考:
https://xuanxuanblingbling.github.io/ctf/pwn/2021/12/12/csu/
程序员的自我修养里面也有
_start
1 | 0000000000001060 <_start>: |
__libc_start_main
starti可以从最开始启动时下断点
可以慢慢地去一探究竟程序的过程了!
它会处理执行环境的初始化工作, 然后调用main函数, 并且处理main函数的返回,
它可能干的事如下
- performing any necessary security checks if the effective user ID is not the same as the real user ID.
- initialize the threading subsystem.
- registering the
*rtld_fini*
to release resources when this dynamic shared object exits (or is unloaded). - registering the
*fini*
handler to run at program exit. - calling the initializer function
(**init*)()
. - calling
main()
with appropriate arguments. - calling
exit()
with the return value frommain()
.
参考
https://xuanxuanblingbling.github.io/ctf/tools/2020/03/20/gdb/
[原创]关于不同版本 glibc 更换的一些问题: https://bbs.kanxue.com/thread-254868.htm
https://gist.github.com/stefan1wan/5e4b3973aae578ac39f94d30a5555f19
问答
有无符号的区别在哪呢….蒙圈了
函数、变量符号
有符号的话是可以看到定义的那些变量、函数等,但是不知道行数、具体的代码
符号文件在哪?
deb如何解包 dpkx -x xxxxx.deb ./
debug文件为什么会有单独的,为什么glibcallinone里的不用呢