1、概述
有这样的一个场景,我有一个动态库myso.so里面有函数start_crash(),用到静态库的内存分配函数,其实静态库里面的static.a 里面就封装了一个函数叫system_malloc(),函数返回的是分配的内存地址,然后发现,我在测试demo里面创建了个子线程,然后在子线程里面调用start_crash(),会发现system_malloc函数返回的地址不对,内存不可访问,使用时直接会发生崩溃
图1.1 exmaple为测试的例子,src为my.so动态库,util为负责调用malloc并返回分配的地址
图1.2 util system_malloc函数
图1.3 为myso.so中的start_crash()函数
图1.4为main函数调用myso.so中的start_crash函数
2、分析过程
我采用的是visual stdio 2022进行调试Linux的程序,具体怎么配置,请看在 Visual Studio 中连接到你的目标 Linux 系统 | Microsoft Learn,这个教程进行配置调试
2.1 主线程的调用
2.1.1 myso.so中start_crash反汇编代码
2.1.2 my.so中的start_crash的寄存器值
2.1.3 返回的地址指针
我们可以看到rax 跟eax的地址值就是最终给payload变量的值,这个是没有问题的
2.2 子线程的调用
2.2.1 my.so 中start_crash的反汇编
调用流程跟主线程中的一样,但是为啥多了个cltp汇编指令呢,我们看cltp的解释
这样我们继续看调用system_malloc函数后返回的地址
payload的地址变成了0xffffffff000b60,不可访问,其实根据汇编指令,是把rax的地址给了payload变量,所以看到payload的地址跟rax是一样的,为啥好好的在system_malloc明明得到正确的地址,为啥函数调用回来之后就变了,很奇怪,我们根据汇编代码其实是多了调cltp指令导致的。
2.2.2 在utils.a中分配的地址值
rax 跟eax寄存器存的内容
3、原因分析
根据2.1跟2.2的比较我们可以得出,在主线程中调用test_mem得到的地址是没有问题的,但是在子线程中的就有问题,我们找了网上的资料发现也有这个cltp指令导致的错误GCC cutting of higher 32 bits of qword in dlmalloc port - OSDev.org
所以我们在编译时候加add_compile_options(-Werror)编译选项,发现编译不过,发现我没有把system_interface.h头文件给包含过来导致的,然后加上之后竟然不会发生崩溃了。怀疑这是编译器进行优化导致的一个问题。
但是我没有在myso.c中包含system_interface.h头文件我竟然都能编译过去,这也很奇怪,通过对比内存和反汇编,我们可以得出结论应该是
4、结论
system_malloc函数没有被正确声明,编译把返回当成32位了?,还是没怎么搞懂,为啥在主线程调用就不会发生这事,在子线程就会,从地址来看,子线程分配的地址控件大于32,这才导致这样的问题,而且发生了cltp扩展