前言

本文需要基础的ELF格式文件知识。

我们知道printf代码的实现位于libc.so中,而我们知道我们的so是在运行通过加载器进行加载的.

如下代码所示:

//编译指令 gcc -o main2.out main2.c -zlazy
//zlazy是启用延迟绑定。部分发行版本连接器直接程序加载的时候会进行绑定so函数
#include <stdio.h>
void main(){printf("hello %d",23);
}

ldd命令可以查看程序所需的动态库

so编译的时候printf是不知道函数地址的,因为你不知道so中被加载到内存哪个地址。

如下图所示:

图[1]

我们看到so被加载不同的地址对于调用函数指令也有所不同。

解决方案1

我们直接在程序被加载时重写改写所有so的函数调用地址。

比如如下汇编在编译时的指令

call xxx1
cal xxx2
call xxx3

加载后修改所有地址

call yyy1
cal yyy2
call yyy3

但是弊端异常明显,假设一个程序需要重定位100万个地址的话,那么程序启动会异常的慢,而且你程序不可能所有指令都会被调用(也许用户刚打开就关闭,你的代码基本没怎么执行却浪费大量的时间在加载时)。

解决方案2

延迟绑定重定位的地址,也就是我们在调用某条指令的时候再去修改他的调用地址。为了实现延迟绑定ELF推出了两个节 .GOTPLT.

首先我們要明白其中的一些格式

.got其实本质是一张表,每一项都是一个地址,也许是变量的地址或者函数的。某个需要重定位的函数被调用后.got表里的与之关联的地址会被改成真正函数地址(未被调用之前got的地址指向plt某个函数)。

.plt存储的是桩代码,负责解析与调用真正的重定位地址函数。

我们用一个例子举例说明:

我们原始调用某个函数的汇编指令:

call   xxxx #调用<printf>实际所在地址

启用延迟绑定后这个指令会改为调用plt某处代码

call   1050 #改为调用plt的某处代码

跳转处plt代码如下所示

 jmp QWORD PTR [rip+0x2fbd]        # rip+0x2fbd这个地址会指向.got某个存储地址

以下为.got表存储的地址信息为1034

;.got或者.got.plt表存储的地址
1034

1034这个地址指的又是.plt某个函数地址

1034         push   0x0
1039        jmp 1020 <.plt>

push 用于传递参数 标识是哪个函数
jmp 跳转另一段plt代码

 1020    push   QWORD PTR [rip+0x2fe2]   # rip+0x2fe2计算为 4008 指向`.got.plt`表中的第二个地址1026  jmp QWORD PTR [rip+0x2fe3]        # [rip+0x2fe3 4010  指向`.got.plt`表中的第三个地址

其中 QWORD PTR [rip+0x2fe2] 传入的是link_map结构,内包含动态必要的信息,可以让我们查找函数


/* Structure describing a loaded shared object.  The `l_next' and `l_prev'members form a chain of all the shared objects loaded at startup.These data structures exist in space used by the run-time dynamic linker;modifying them may have disastrous results.  */struct link_map{/* These first few members are part of the protocol with the debugger.This is the same format used in SVR4.  */ElfW(Addr) l_addr;        /* Difference between the address in the ELFfile and the addresses in memory.  */char *l_name;      /* Absolute file name object was found in.  */ElfW(Dyn) *l_ld;      /* Dynamic section of the shared object.  */struct link_map *l_next, *l_prev; /* Chain of loaded objects.  */};

QWORD PTR [rip+0x2fe3] 其实是一个名叫_dl_runtime_resolve函数,他的作用有两个

  1. 根据传入的函数id和link_map修改got表地址为函数地址
  2. 跳转查找的函数地址

为方便理解我们使用gdb调试进行演示:
如下代码:

//编译指令 gcc -o main2.out main2.c -zlazy
//zlazy是启用延迟绑定。部分发行版本连接器直接程序加载的时候会进行绑定so函数
#include <stdio.h>
void main(){printf("hello %d",23);
}

首先gbd main2.out进入gdb调试界面

layout asm打开汇编面板

断点 函数入口b main

执行 r命令运行程序,然后单步到call 0x401040 <printf@plt>

输入si步入这条指令

QWORD PTR [rip+0x2fcd] 是got表中某一项的地址,也就是printf的地址,但是由于他没有重定向此时会指向另一个ptl函数地址

以下为此地址存储的数据:

对其反编译这个地址:

这个地址的代码其实是ptl.sec中的代码,这段代码最后又跳转0x401020

接着我们步入这个_dl_runtime_resolve函数
你最后会发现最步入到print函数的实现

我们最后在查看下我们前面的got表地址是否变化了

参考

1. GDB shows incorrect jump address at PLT section

通过 GDB 调试理解 GOT/PLT

got/plt之_dl_runtime_resolve

_dl_runtime_resolve

学习ret2dlresolve

通过GDB学透PLT与GOT相关推荐

  1. a pycharm 标记多个_轻松学透Markdown的终极教程 #3:Markdown标准标记语法(全)

    轻松学透Markdown的终极教程 #3: Markdown标准标记语法(全) 掌握并熟记一些常用的Markdown的标记语法,简单.有趣.实用 其实如果大家选择了一款Markdown编辑器上手的话, ...

  2. 学透CSS-当CSS遇到古诗和月亮,月亮动起来!!!

    创作不易 拒绝白嫖 点个赞呗 关注专栏 学透CSS,带你走进CSS的深处!!! 前言 在具体开始之前,我们先来科普一下.月亮的各种圆缺形态,也称为月相. "新月",也叫" ...

  3. Android架构演进 · 设计模式· 为什么建议你一定要学透设计模式?

    一.引言 Hello,我是小木箱,欢迎来到小木箱成长营Android架构演进系列教程,今天将分享Android架构演进 · 设计模式· 为什么建议你一定要学透设计模式? 今天分享的内容主要分为四部分内 ...

  4. 二分查找 二分答案 万字详解,超多例题,带你学透二分。

    很多人对二分感到很苦恼,很困惑,可能是因为二分的边界很难掌握,也许是判断条件难写- 然而,很幸运,你找到了这篇文章,仔细看下去,这篇文章将带你学透二分!!! 二分可以简单分为二分查找与二分答案. 可能 ...

  5. Flash ActionScript (23)三天学透as3.0之第二天

    5. 多态(Polymorphism) 5.1 多态的概念 面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. 多态的定 ...

  6. 秀,用NBA球员数据学透K-Means聚类

    这次我们用 NBA 球员赛季表现聚类来探讨下 K-Means 算法,K-Means 是一个清晰明白的无监督学习方法,和 KNN 有很多相似点,例如都有超参数 K,前者是 K 个类别,后者是 K 个邻居 ...

  7. 一张学习规划图学透自动化测试

    有很多的朋友问我,自动化测试应该怎么学,在网上看看视频能学会吗?现在网络上的软件测试资料很多,但是很多人就是没有规划,不知道该怎么去学习,往往没有头绪的学习,到头来都是无法坚持的,这个时候学习规划的作 ...

  8. 震惊!阿里P8爆出学透这份算法面试文档后,任何大厂算法都是小意思

    为什么要学习数据结构和算法? 随着应用程序变得越来越复杂和数据越来越丰富,几百万.几十亿甚至几百亿的数据就会出现,而对这么大对数据进行搜索.插入或者排序等的操作就越来越慢,数据结构就是用来解决这些问题 ...

  9. 学透JSON.stringify

    场景介绍 项目中用到JSON.stringify的机会特别多,但是稍不注意就会出现问题 eg : public singInfo = [{fieldId: 539,value: undefined}, ...

最新文章

  1. 学习笔记:深度学习中的正则化
  2. swift开发记录 - MARK,TODO,FIXME
  3. 文档的管理计算机,如何使用FTP自动同步备份电脑文件数据?
  4. 前端技巧:遍历数组都有哪些方式呢?
  5. 【转】博客美化(1)基本后台设置与样式设置
  6. centos7安装kubernetes1.9集群
  7. mysql 多值属性_数据库 名词解释:单值属性和多值属性
  8. android csv显示乱码问题,Android CSV解析器问题
  9. Underscore.js-精巧而强大实用功能库
  10. Firefox关闭最后一个标签页时不关闭Firefox的设置
  11. Asp.net MVC 搭建属于自己的框架(一)
  12. Python之文章生成器(升级版,也就是更傻瓜式运行)
  13. fastboot工具的操作流程
  14. 2020字节跳动数据库面试题及答案
  15. 梁文道:盗版电影网站死去,我们仍然不见光明
  16. SAMBA配置 “你可能没有权限访问网络资源”的问题解决方法
  17. JRebel激活与配置
  18. CWnd::WindowProc的理解
  19. 一般将来时语法课教案_英语时态
  20. PyCharm如何自定义调整字体大小的快捷键

热门文章

  1. 企微管家如何自动给客户打标签?
  2. python 排课算法_基于遗传算法的排课系统
  3. pageadmin cms,pageadmin cms插件,pageadmin cms如何建站
  4. CVX用户指南之快速入门
  5. java知识竞赛活动方案_java知识竞赛s1
  6. 车内看车头正不正技巧_坡道定点停车和起步只要掌握技巧,一点都不难_搜狐汽车...
  7. 夏天到来了,可以去做这5个生意,投入成本不大,利润却非常不错
  8. 使用 arm-linux-androideabi-addr2line 工具定位 libunity.so 崩溃问题
  9. 151205苹果手机屏幕尺寸及分辨率
  10. 【原】阿里云RDS数据库超大表分区实现