Home avatar

Wings

Pwn ret2libc in x86

共享目标文件是 PIC (地址无关代码) 的, 对其中的符号进行寻址是 相对寻址, 这也说明了整个 .so 装载后是一个不可分割的整体, 各个符号之间的相对距离 (或者各个指令的相对距离) 并不会变. 这样, 即使程序开启了 ASLR (地址随机化, 动态链接 .so 的时候会装载到随机的地址上), 我们只要知道程序用的是哪一个版本的 libc.so (进而知道各个符号之间的相对距离), 且知道某一个符号当前装载在内存中的地址, 那么理论上来说, 我们就可以计算出任意符号 (或者直接就是 .so 的某个地址)当前装载在内存中的地址. libc.so 中有 system 函数, “/bin/sh” 字符串等可供我们利用的符号或数据.

那么现在的问题在于:

  1. 怎么知道程序使用的是什么版本的 libc.so
  2. 怎么知道某一个符号当前装载在内存中的地址

先来看第一个问题.

虽然 .so 在装载后的地址是随机化的, 但是地址的低 12 位是固定的 (随机了, 但没完全随机). 因为程序装载的时候, 会涉及到虚拟内存向物理内存的映射, 而这种映射是以页为单位的, 页需要对齐, 而一个页的大小为 0x1000 (4096) 字节. 程序装载的时候, 每个节的对齐粒度都是 0x1000, 这也就说明了为什么 .so 中指令, 符号或者数据的低 12 位是固定的. 关于页映射, 目前没有搞得很明白, 详细请参考 «程序员的自我修养».

如果知道某一个符号的低 12 位是什么, 那么直接拿它和现有的所有版本的 libc.so 去对比, 就可以找到程序用的是什么版本的 libc.so 了. 对没错就是暴力枚举. 当然可能匹配到多个版本的 libc.so, 这时就得提供更多的信息了, 比如拿两个甚至多个符号的低 12 位去爆搜, 直到确定某一个版本的 libc.so. 或者暴力把所有符合条件的 libc.so 都跑一遍, 总有一个是对的.

奇偶校验与海明码

数据是由一堆 01 串组成的. 要看这些 01 串在传输过程中有没有出现错误, 最简单的方法就是比较一下接收到的数据和发送的数据是否相同. 但是, 接收数据的人怎么知道发送的 “正确数据” 是多少呢? 所以这就很有意思了.

整数运算

注意
好像 CSAPP 没涉及到运算在逻辑电路上的实现 (暂时没看到后面), 但是计组课本上居然有… 日后看情况补充吧, 可能得等计组考试前两天才会学这玩意.

无符号整数比较简单, 因为其加法, 乘法, 减法 (这里不讨论整数的除法) 运算都是在模域 $2^w$ 下的, 可以直接将结果用人理解的方法算出来. (如果有需要的话把算出的这个结果转换成二进制表示.)

IEEE 754 浮点数表示

浮点数Floating Point是表示实数的一种方法. 它的思想类似于科学计数法, 即将数字写成 $x = (-1)^S M \cdot 2^E$ 的形式. 那么需要记录 符号Sign $S$, 尾数Mantissa $M$ 和指数或阶(码)Exponent $E$.