问题分析
在动态调试程序的时候,用gdb调试到libc的时候能正确加载符号信息,但同样的程序用IDA调试到libc的时候却缺失了libc中的许多符号,
这其实是IDA没有正确加载DWARF调试信息(debuginfo)所导致的
根本原因是系统中没有对应的调试信息(可以装libc6-dbg),或是调试信息所在的位置不正确
到网上找了一圈,发现IDA不能像gdb一样指定调试信息所在的目录,所以即便下载了调试信息也没办法直接加载,于是事情就变得有点复杂了
IDA官网上给出的解释是当前仅支持加载PDB,而不支持加载DWARF
Currently, only PDB files are supported.
不过去逆一下linux_server就会发现,其实IDA是支持加载DWARF的,只不过调试信息的路径默认为空,而且IDA没有提供方法对其进行修改
解决方法有四种
第零种方法:使用Load DWARF file插件,不过这个好像只能加载主程序的调试信息
第一种方法:把调试信息拷贝到优先级高的/usr/lib/debug/.build-id下,再通过patch修改linux_server的调试信息加载目录
第二种方法:给调试信息换个名字,比如libc-2.23.so.debug,避免和原来的libc-2.23.so重名
第三种方法:用IDC脚本加载调试信息
第四种方法:把调试信息附加到动态库上
这里推荐使用第一种方法,不用每次都修改二进制文件,比较方便
如图,虽然用的是带调试信息的libc,但是Load debug symbols的时候Output window会输出如下错误信息,这是因为加载了错误的libc-2.23.so
解决方案
准备工作
首先要下载libc对应的调试信息,对应的方法比较多
1、sudo apt-get install libc6-dbg
2、https://github.com/matrix1001/glibc-all-in-one
3、https://mirror.tuna.tsinghua.edu.cn/ubuntu/pool/main/g/glibc/下载对应版本的libc6-dbg_*.deb包,再用dpkg -i安装
解决方法一
下面主要用libc6-dbg演示,另外两种方法同理
切换工作目录到/usr/lib/debug/lib/x86_64-linux-gnu
执行以下命令,复制调试信息到/usr/lib/debug/.build-id下
for file in `ls` do buildid=`readelf -n $file|grep 'Build ID'|awk '{print $3}'` dir=`echo $buildid | cut -c1-2` fn=`echo $buildid | cut -c3-` sudo mkdir -p /usr/lib/debug/.build-id/$dir sudo cp $file /usr/lib/debug/.build-id/$dir/$fn sudo cp $file /usr/lib/debug/.build-id/$dir/${fn}.debug done
再对linux_server进行修改
1、在.rodata段中找地方写入字符串/usr/lib/debug/
2、对0x4163A3处的指令进行修改,将操作数改成字符串/usr/lib/debug/的所在位置
这样在调试的时候,IDA就会到/usr/lib/debug/.build-id下加载调试信息了
当需要加载libc信息的时候进行以下操作
1、Start/Attach debugged process
2、Pause debugged process
3、Modules->libc-2.23.so->Load debug info
4、Modules->libc-2.23.so->Analyze module
解决方法二
下面主要用glibc-all-in-one演示,另外两种方法同理
切换工作目录到glibc-all-in-one/libs/2.23-0ubuntu10_amd64
然后执行以下命令,对libc进行修改
objcopy -R .gnu_debuglink ./libc-2.23.so objcopy --add-gnu-debuglink=libc-2.23.so.debug ./libc-2.23.so mv .debug/libc-2.23.so .debug/libc-2.23.so.debug
再执行以下命令修改要调试的文件,使其加载修改后的libc
patchelf --set-interpreter `pwd`/ld-2.23.so 你的程序 patchelf --replace-needed libc.so.6 `pwd`/libc-2.23.so 你的程序
当需要加载libc信息的时候进行以下操作
1、Start/Attach debugged process
2、Pause debugged process
3、Modules->libc-2.23.so->Load debug info
4、Modules->libc-2.23.so->Analyze module
解决方法三
先用IDA打开对应的调试信息
选择File->Produce file->Dump database to IDC file...
打开导出的IDC脚本进行修改
1、写一个函数,将base设置为调用脚本时IDA的EA所选中的地址
static ask_libcbase(void) { auto ea=get_screen_ea(); base=ask_addr(ea,"input libc base"); }
2、将原来地址的0X7EFE替换为base-0X7EFE21CF9000+0X7EFE,这里的0X7EFE21CF9000是libc加载的基地址,要根据实际导出的IDC脚本进行修改
3、注释掉delete_*函数调用
4、注释掉create_*函数调用
5、注释掉make_*函数调用
当需要加载libc信息的时候进行以下操作
1、Start/Attach debugged process
2、Pause debugged process
3、Modules->libc-2.23.so->Jump to moudle base
4、File->Script File
5、Modules->libc-2.23.so->Analyze module
解决方法四
运行结果
用IDA来Start或者Attach你的程序
点击右侧的Modules->libc-2.23.so->Load debug symbols
等待左下角显示AU:idle加载完成,此时仍有Name信息加载不全的问题
再点击Modules->libc-2.23.so->Analyze module
然后耐心等待调试信息加载完成
最后的效果如下,_IO_FILE_plus_1等结构体都能被很好地识别,在右侧注释中有对应的成员信息,而且伪代码也能正常生成了
注意事项
apt里的patchelf是0.9版本的,有Bug
要自己到Github上编译0.10版本的才能正常使用
参考文献
1、https://blog.csdn.net/chinainvent/article/details/24129311?reload
2、https://www.douban.com/note/350501219/
3、https://stackoverflow.com/questions/34293646/how-to-add-debug-symbols-to-stripped-elf-binaries
5、https://www.hex-rays.com/products/ida/support/idadoc/1457.shtml