C++空指针Coredump调试
发布时间:2023-03-29 11:10:18.562 文章来源:AiSoftCloud 浏览次数:694 下载次数:1 

指针是C/C++高性能的独门绝技,但是用不好也就成了稳定性的破坏之神,必须要养成良好的编码习惯。

分析工具

IDA Pro 7.7 SP1

下载地址(百度网盘):链接: https://pan.baidu.com/s/1_QPXda0zg0joxfxivFzUpw 提取码: 7np1

安装:

1、双击下载后的IDAPro170914.dmg,打开如下安装界面,然后将左侧的【IDA Pro 7.0】拉到右侧应用程序即可:

2、安装完成后,直接双击打开可能出现如下问题:

  • “xxx软件已损坏,无法打开,你应该将它移到废纸篓”
  • “打不开xxx软件,因为Apple无法检查其是否包含恶意软件”
  • “打不开…软件,因为它来自身份不明的开发者”

解决方案如下:

如果出现弹窗提示您没有权限来打开应用程序“ida64”。请联系您的电脑或网络管理员以获得帮助。这是因为Mac系统无法直接启动64位应用程序,可以直接到安装目录下双击启动:

  1. cd /Applications/IDA Pro 7.0
  2. open .

然后鼠标右键点击ida64,选择“显示包内容”,进入“Contents/MacOS”,右键点击ida64,选择“打开”。

打开后如果弹出“Oops, IDA has almost crashed!”,这是第三方输入法导致的,需要切换到英文输入法

测试程序

为方便说明,写一个测试程序,包含ida_crash.hida_crash.ccida_crash_test.ccCMakeLists.txt四个文件:

ida_crash.h:

  1. #include <string>
  2. class IdaCrash {
  3. public:
  4. std::string test();
  5. };

ida_crash.cc:

  1. #include "ida_crash.h"
  2. std::string IdaCrash::test() {
  3. const char* data = getenv("IDA_CRASH_TEST");
  4. std::string str = data;
  5. return str;
  6. }

ida_crash_test.cc:

  1. #include "ida_crash.h"
  2. #include <csignal>
  3. #include <execinfo.h>
  4. #include <iostream>
  5. std::string DumpBacktrace() {
  6. const int32_t MAX_STACK = 100;
  7. void *buffer[MAX_STACK] = {0};
  8. int32_t n = ::backtrace(buffer, MAX_STACK);
  9. if (n <= 0) {
  10. return std::string("backtrace fail: " + std::to_string(n));
  11. }
  12. char **symbols = ::backtrace_symbols(buffer, n);
  13. if (symbols == nullptr) {
  14. return std::string("backtrace fail: no symbols");
  15. }
  16. std::string bt_stack = "\n";
  17. for (int32_t i = 1; i < n; ++i) {
  18. bt_stack += (" " + std::string(symbols[i]) + "\n");
  19. }
  20. ::free(symbols);
  21. return bt_stack;
  22. }
  23. void SignalHandler(int sigval) {
  24. switch (sigval) {
  25. case SIGABRT:
  26. case SIGBUS:
  27. case SIGFPE:
  28. case SIGHUP:
  29. case SIGQUIT:
  30. case SIGSEGV:
  31. case SIGTERM:
  32. case SIGILL:
  33. std::cout << "backtrace:\n" << DumpBacktrace() << std::endl;
  34. std::signal(sigval, SIG_DFL);
  35. std::raise(sigval);
  36. break;
  37. case SIGINT:
  38. break;
  39. default:
  40. break;
  41. }
  42. }
  43. void RegSigCallBack() {
  44. std::signal(SIGABRT, SignalHandler);
  45. std::signal(SIGBUS, SignalHandler);
  46. std::signal(SIGFPE, SignalHandler);
  47. std::signal(SIGHUP, SignalHandler);
  48. std::signal(SIGINT, SignalHandler);
  49. std::signal(SIGQUIT, SignalHandler);
  50. std::signal(SIGSEGV, SignalHandler);
  51. std::signal(SIGTERM, SignalHandler);
  52. std::signal(SIGILL, SignalHandler);
  53. }
  54. int main(int argc, char** argv) {
  55. RegSigCallBack();
  56. IdaCrash test;
  57. test.test();
  58. return 0;
  59. }

CMakeLists.txt:

  1. cmake_minimum_required(VERSION 3.10)
  2. project(ida_crash_test)
  3. add_library(ida_crash ida_crash.cc)
  4. add_executable(ida_crash_test ida_crash_test.cc)
  5. target_link_libraries(ida_crash_test ida_crash)

编译后执行./ida_crash_test,打印出crash堆栈如下:

  1. backtrace:
  2. ./ida_crash_test(+0x1d26) [0x557b70a01d26]
  3. /lib/x86_64-linux-gnu/libc.so.6(+0x3ef10) [0x7f9e73932f10]
  4. /lib/x86_64-linux-gnu/libc.so.6(gsignal+0xc7) [0x7f9e73932e87]
  5. /lib/x86_64-linux-gnu/libc.so.6(abort+0x141) [0x7f9e739347f1]
  6. /usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0x8c957) [0x7f9e73f89957]
  7. /usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0x92ae6) [0x7f9e73f8fae6]
  8. /usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0x92b21) [0x7f9e73f8fb21]
  9. /usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0x92d54) [0x7f9e73f8fd54]
  10. /usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0x8e79f) [0x7f9e73f8b79f]
  11. /usr/lib/x86_64-linux-gnu/libstdc++.so.6(_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tag+0xcd) [0x7f9e740242dd]
  12. /home/work/ida_crash_test/build/libida_crash.so(_ZN8IdaCrash4testB5cxx11Ev+0x53) [0x7f9e7428695d]
  13. ./ida_crash_test(+0x1e80) [0x557b70a01e80]
  14. /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f9e73915c87]
  15. ./ida_crash_test(+0x186a) [0x557b70a0186a]

上述堆栈清楚显示crash位置为libida_crash.so(_ZN8IdaCrash4testB5cxx11Ev+0x53) [0x7f9e7428695d]

分析过程

1、确定崩溃位置

通过堆栈分析,crash位置为libida_crash.so(_ZN8IdaCrash4testB5cxx11Ev+0x53) [0x7f9e7428695d],其中小括号表示偏移地址(_ZN8IdaCrash4testB5cxx11Ev+0x53,有的堆栈没有+号前面的部分),中括号表示虚拟地址(0x7f9e7428695d)

2、打开IDA分析软件,并加载libida_crash.so:

3、等待加载完成(文件很大时可能加载时间很长),完成后显示如下界面:

4、在左侧窗口中找到_ZN8IdaCrash4testB5cxx11Ev这个符号,双击,然后按F5键进行反编译(Mac下为左下角Fn功能键同时按最上方的F5)

5、此时右侧窗口显示的就是反汇编代码,里面调用了getenv接口,返回一个指针v3,指针未做判空检查直接赋值给一个std::string变量导致crash。

6、如果堆栈中的便宜地址只有0x开头的数字,则直接可以在IDA软件中按g键输入地址跳转到该位置,然后按F5键反编译即可,如下图所示:

更多文章可关注公众号
aisoftcloud