关于C++文件换libc版本的问题

今天解决了一件困扰了我很久的事情,那就是对于elf文件的patch。以前我在做pwn题的时候,遇到C++文件总是束手无策。

在换过对应的版本之后,libc总是报错。就如下面这张图片

1

在此问了肥猫师傅给我的解决办法,解决办法很早就给了我的,但是我到现在才搞明白,弄懂,下面是肥猫师傅的原话。

2

在此之前我一直都是用patchelf封装的脚本加上glibc all in one配合完美换libc版本,对于C程序是没有任何问题的。但是C++出现了问题,那么我们就先看看C和C++编译链接之后出来的文件的依赖库的结构。

那么为了测试就先写出两个版本的hello world程序。

1
2
3
4
5
6
7
//C
#include<stdio.h>

int main(){
printf("Hello world\n");
return 0;
}
1
2
3
4
5
6
7
8
//C++
#include<iostream>
using namespace std;

int main(){
cout<<"Hello world"<<endl;
return 0;
}

分别用gcc和g++命令编译得到1和2可执行文件。

查看动态链接的关系。

3

可以看到C++程序多了三项依赖,查一下自己glibc all in one libs中找得到一下依赖项

1
2
3
libc.so.6
libm.so.6
ld.so.6

我们换库的原因是因为malloc的分配以及各个函数在libc中的偏移在不同版本中都有着很大的区别,偏移问题不大,只需要在本地打出之后连接远程靶机的时候替换一下自己的libc即可。但是在打堆题的时候,不同libc分配有本质区别,比如,2.27的tcache允许直接double free,但是2.23和2.29之后都不允许直接的double free。以及2.34 的libc 中很多hook已经被删除,并不能利用。总之,在打堆题的时候版本是一个很重要的东西,不同版本利用手段都会有本质区别的。

我们patchelf的时候一般是指定链接器,然后再指定runpath到我们自己下载的库文件。那我们把这两个项换上2.23的libc之后ldd看看他们的依赖关系。

2

可以看到两个文件都已经换上了2.23版本的libc,但是C++编译出来的文件出现了报错,报错是在我们换上的libc.so.6中报出的,然后报错的提醒是因为这个libstdc++.so.6。那么就可以确定一点了,c++自己额外提供了库,而这个库是libstdc++.so.6,而这一项指定到了我们系统的/lib/x86_64-linux-gnu/libstdc++.so.6这个库文件中,而这个库文件是对应了我们安装的版本的,因此我们需要去找一找2.23版本的这个C++的库,并且patch之后指向那个库应该就可以解决。这里可以学肥猫师傅的做法,先用docker装一个16版本的ubuntu,因为16版本刚好对应了libc的版本2.23。

这里先去用docker拉一个ubuntu16.04的镜像然后用如下命令进入这个镜像。

1
#docker run -it ubuntu:16.04 /bin/bash

进入之后装上g++和vim,用vim写一个hello world 并且编译之后ldd查看文件依赖关系,找到libstdc++.so.6指向的具体路径然后用docker cp命令拷贝到自己目录下,然后建议丢进libs目录,此时为C++文件再加一个patchelf命令,我这里用了如下命令,自己看情况改改路径即可。

1
$patchelf --replace-needed libstdc++.so.6 '/home/xiaoji233/pwn-tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libstdc++.so.6.0.21'  filename

那么,改完了之后我们ldd看看情况。

5

可以看到libstdc++.so.6已经指向了我们所给的库,并且也没有上面两行的报错了,因此这样就完成了一个C++程序的版本更换。

最后我们运行看看。

6

完美成功运行。

总结

小总结一波:在更换C程序的时候需要用patchelf更改链接器的版本和runpath,C++程序换libc版本的时候需要额外指定一个libstdc++.so.6这个库才能正常运行。

总而言之,解决这个问题心情十分爽快,也希望本篇博客能帮到很多人。

文章目录
  1. 1. 总结
|