• IDA 正确加载 libc.so 等动态库的调试信息


    问题分析

    在动态调试程序的时候,用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

    解决方法四

    参考:https://stackoverflow.com/questions/15977961/how-to-undo-strip-i-e-add-symbols-back-to-stripped-binary

    运行结果

    用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

    4、https://stackoverflow.com/questions/15977961/how-to-undo-strip-i-e-add-symbols-back-to-stripped-binary

    5、https://www.hex-rays.com/products/ida/support/idadoc/1457.shtml

  • 相关阅读:
    MySQL数据库导入方法(最佳方案--cmd命令行方式导入,不会导致数据结构或表丢失)
    MySQL:互联网公司常用分库分表方案汇总!
    主流的消息中间件有哪些?
    Java实现进制之间转换的工具类
    python查找文件夹下所有指定后缀名的文件
    Visual Studio检查内存泄露方法
    Linux重要文件被删恢复问题
    docker 安装与相关操作
    C++ 替换路径中斜杠 并获取完整路径的文件名
    catch2:一个好用的C++单元测试框架
  • 原文地址:https://www.cnblogs.com/algonote/p/12729657.html
Copyright © 2020-2023  润新知