前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >通过修改第三方so的elf符号表兼容redhat6.2下低版本glibc

通过修改第三方so的elf符号表兼容redhat6.2下低版本glibc

作者头像
lovelife110
发布2021-01-14 14:38:32
1.3K0
发布2021-01-14 14:38:32
举报
文章被收录于专栏:爱生活爱编程爱生活爱编程

背景:第三方so依赖glibc2.14版本,如何在不升级redhat 6.2自带的gblic2.12情况下,运行so?

结论:通过16进制编辑器修改so的elf符号表来解决这个问题,即强制让so里依赖高版本gblic的函数指向低版本的glibc。风险:有些函数在老版本下可能会出问题,具体需要多测试

首先评估so文件修改风险

通过ldd命令打印库文件所依赖的共享库列表,发现so依赖glibc2.14版本

代码语言:javascript
复制
[root@bogon lee]# ldd libTaSESDK.so 
ldd: warning: you do not have execution permission for `./libTaSESDK.so'
./libTaSESDK.so: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./libTaSESDK.so)
        linux-vdso.so.1 =>  (0x00007fff530a5000)
        libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fe729ebf000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fe729c3b000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fe729a24000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fe729683000)
        /lib64/ld-linux-x86-64.so.2 (0x0000003810600000)

而通过rpm命令发现当前系统对应的是glibc2.12版本

代码语言:javascript
复制
[root@bogon lee]# rpm -qa | grep glibc
glibc-2.12-1.47.el6.x86_64
glibc-devel-2.12-1.47.el6.x86_64
glibc-common-2.12-1.47.el6.x86_64
glibc-headers-2.12-1.47.el6.x86_64

通过objdump -T 查看so 动态符号,发现so使用glibc 2.14 版本的 memcpy 函数

代码语言:javascript
复制
[root@bogon lee]# objdump -T libTaSESDK.so | grep GLIBC_2.1.*
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.14  memcpy

通过objdump -T /lib64/libc.so.6发现当前系统 glibc 库提供的 memcpy 实现是 2.2.5 版本

代码语言:javascript
复制
[root@bogon lib64]#  objdump -T /lib64/libc.so.6 | grep memcpy
0000003810e8fa80  w   DF .text  0000000000000009  GLIBC_2.2.5 wmemcpy
0000003810efdc70 g    DF .text  000000000000001b  GLIBC_2.4   __wmemcpy_chk
0000003810e87dd0 g   iD  .text  000000000000003c  GLIBC_2.2.5 memcpy
0000003810efbd50 g   iD  .text  000000000000003c  GLIBC_2.3.4 __memcpy_chk

接下来,要做的就是让so指向2.2.5版本

修改elf

readelf -sV libTaSESDK.so >1.txt

通过readelf 命令查看so的ELF 的符号表

定位到 .gnu.version_r ,其表示二进制程序实际依赖的库文件版本

上图发现,该so比较简单,目前就2处,可想而知,我们只要修改 0x0010: Name: GLIBC_2.14 Flags: none Version: 3这行。

如果行数比较多,可以通过Version版本与 .gnu.version的信息对应,再与.dynsym对应来找到对应的函数。关系是 .gnu.version通过偏移量+.dynsym里面函数对应的num*2找到对应的版本,然后.gnu.version通过version关联.gnu.version_r。具体可以自行百度,本次so比较简单,所以没有查这个。

.gnu.version_r 表是按照不同的库文件进行分段显示的,每个条目占用 0x10 也就是 16 个字节,上图偏移量为0x0054d0,加上 0x0010=0x0054E0找到如下

现在只要参考 0x0020: Name: GLIBC_2.2.5 Flags: none Version: 2 修改就行,把 0x0010: Name: GLIBC_2.14 Flags: none Version: 3(0x0054E0开始)改为 0x0020: Name: GLIBC_2.2.5 Flags: none Version: 2(0x0054d0+0x0020=0x0054F0)类似就行,相当与把gblic2.14降为2.2.5

.gnu.version_r 表中每个条目是 16 个字节的 Elfxx_Vernaux 结构体,其声明如下(Elfxx_Half 占用 2 个字节,Elfxx_Word 占用 4 个字节):

代码语言:javascript
复制
typedef struct {
    Elfxx_Word    vna_hash;
    Elfxx_Half    vna_flags;
    Elfxx_Half    vna_other;
    Elfxx_Word    vna_name;
    Elfxx_Word    vna_next;
} Elfxx_Vernaux;

vna_hash 为 4 个字节的库名称的 hash 值,vna_other 为对应的 .gnu.version 表中符号的版本值,vna_name 指向库名称字符串的偏移量(也可以在 ELF 头中找到),vna_next 为下一个条目的位置(一般固定为 0x00000010)。

终于修改为如下

只有vna_other和vna_next有差异

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-07-30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 首先评估so文件修改风险
  • 修改elf
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档