pwnlib.dynelf
— 通过内存泄漏解析远程函数地址¶
解析加载到内存中的动态链接的 ELF 二进制文件中的符号 需要提供一个可以泄漏任意内存的函数 之后任何被动态加载的库的任何符号都可以被解析
例子¶
# 假设现在有一个进程或者远程连接
p = process('./pwnme')
# 声明一个函数, 这个函数只接收一个参数, 作为要被泄漏的内存地址
# 并且至少泄漏这个地址的一个字节的数据
def leak(address):
data = p.read(address, 4)
log.debug("%#x => %s" % (address, (data or '').encode('hex')))
return data
# 为了便于说明这个例子
# 假设我们有任意多的指针
# 一个指针指向二进制程序的某一个符号的指针
# 另两个指针指向 libc
main = 0xfeedf4ce
libc = 0xdeadb000
system = 0xdeadbeef
# 使用我们的泄漏器, 和一个指向二进制程序的某一个符号的指针
# 我们就能泄漏这个内存地址的任意数据
# 事实上为了解析符号, 我们都不需要对目标二进制进行拷贝
d = DynELF(leak, main)
assert d.lookup(None, 'libc') == libc
assert d.lookup('system', 'libc') == system
# However, if we *do* have a copy of the target binary,
# 然而, 如果我们拷贝了这个二进制程序
# 这一步的速度就会快一点
d = DynELF(leak, main, elf=ELF('./pwnme'))
assert d.lookup(None, 'libc') == libc
assert d.lookup('system', 'libc') == system
# 我们也可以解析别的 lib 中的符号
# 然后返回这个符号的指针
d = DynELF(leak, libc + 0x1234)
assert d.lookup('system') == system
DynELF
-
class
pwnlib.dynelf.
DynELF
(leak, pointer=None, elf=None, libcdb=True)[源代码]¶ DynELF 知道如何在一个远程程序中通过信息泄漏或者内存泄漏来解析符号, 得益于
pwnlib.memleak.MemLeak
实现细节:解析函数:
在所有那些导出自己的符号以便与被别的 lib 导入的二进制程序 (例如:
libc.so
)中, 有一系列用于保存符号名称的表, 并且会将这些符号进行哈希。 通过实现相同的哈希函数, 我们就可以知道符号名称 (例如:printf
) 哈希的结果 然后我们就可以从哈希表中找到他们, 它在哈希表中位置会提供一个字符串表的索引(strtab)以及符号的地址(symtab)Assuming we have the base address of
libc.so
, the way to resolve 假设我们已经得到了libc.so
在虚拟内存中的基地址 为了进一步得到printf
, 我们需要定位symtab
和strtab
以及哈希表"printf"
这个字符串已经被根据不同的方式(SYSV 或者 GNU)哈希过并且存储在哈希表中 然后只需要遍历哈希表直到我们找到匹配的入口 我们可以通过检查字符串表来验证这是绝对正确的, 检查字符串表, 然后就可以得到symtab
在libc.so
中的偏移解析 lib 地址:
如果我们有一个指向动态链接的可执行程序的指针, 我们就能得到一个叫做 ``link map``_ 的内部的链表结构 这个数据结构是一个链表, 并且它包含了所有被加载的 lib 的信息, 包括完整的路径以及内存地址
指向
lib map
的指针可以通过两种方法找到 两者都是从 DYNAMIC 数组中的条目引用的- 在没有开启 RELRO 的二进制程序中, 在 .got.plt 这个段会存在一个位置放置这个指针 那么问题就变成了在二进制程序中寻找 _DT_PLTGOT_ 了
- 在所有的二进制文件中, 这个指针会保存在 _DT_DEBUG_ 的地方, 就算是被去除符号的二进制程序中也是这样
为了保持最大的灵活性, 这两种方式都会被彻底地使用
Instantiates an object which can resolve symbols in a running binary given a
pwnlib.memleak.MemLeak
leaker and a pointer inside the binary.参数: -
bases
()[源代码]¶ Resolve base addresses of all loaded libraries.
Return a dictionary mapping library path to its base address.
-
static
find_base
(leak, ptr)[源代码]¶ Given a
pwnlib.memleak.MemLeak
object and a pointer into a library, find its base address.
-
heap
()[源代码]¶ Finds the beginning of the heap via __curbrk, which is an exported symbol in the linker, which points to the current brk.
-
lookup
(symb = None, lib = None) → int[源代码]¶ Find the address of
symbol
, which is found inlib
.参数: 返回: Address of the named symbol, or
None
.
-
stack
()[源代码]¶ Finds a pointer to the stack via __environ, which is an exported symbol in libc, which points to the environment block.
-
elftype
[源代码]¶ e_type from the elf header. In practice the value will almost always be ‘EXEC’ or ‘DYN’. If the value is architecture-specific (between ET_LOPROC and ET_HIPROC) or invalid, KeyError is raised.