Class: Pwnlib::DynELF

Inherits:
Object
  • Object
show all
Includes:
Context
Defined in:
lib/pwnlib/dynelf.rb

Overview

DynELF class, resolve symbols in loaded, dynamically-linked ELF binaries. Given a function which can leak data at an arbitrary address, any symbol in any loaded library can be resolved.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(addr) {|leak_addr| ... } ⇒ DynELF

Instantiate a Pwnlib::DynELF object.

Yield Parameters:

  • leak_addr (Integer)

    The start address that the leaker should leak from.

Yield Returns:

  • (String)

    A leaked non-empty byte string, starting from leak_addr.



26
27
28
29
30
31
32
33
# File 'lib/pwnlib/dynelf.rb', line 26

def initialize(addr, &block)
  @leak = ::Pwnlib::MemLeak.new(&block)
  @libbase = find_base(addr)
  @elfclass = { 0x1 => 32, 0x2 => 64 }[@leak.b(@libbase + 4)]
  @elfword = @elfclass / 8
  @dynamic = find_dynamic
  @hshtab = @strtab = @symtab = nil
end

Instance Attribute Details

#libbaseInteger (readonly)



14
15
16
# File 'lib/pwnlib/dynelf.rb', line 14

def libbase
  @libbase
end

Instance Method Details

#build_idString?

Leak the BuildID of the remote libc.so.



81
82
83
84
85
86
87
88
# File 'lib/pwnlib/dynelf.rb', line 81

def build_id
  build_id_offsets.each do |offset|
    next unless @leak.n(@libbase + offset + 12, 4) == "GNU\x00"

    return @leak.n(@libbase + offset + 16, 20).unpack1('H*')
  end
  nil
end

#lookup(symbol) ⇒ Integer?

Lookup a symbol from the ELF.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/pwnlib/dynelf.rb', line 42

def lookup(symbol)
  symbol = symbol.to_s
  sym_size = { 32 => 16, 64 => 24 }[@elfclass]
  # Leak GNU_HASH section header.
  nbuckets = @leak.d(hshtab)
  symndx = @leak.d(hshtab + 4)
  maskwords = @leak.d(hshtab + 8)

  l_gnu_buckets = hshtab + 16 + (@elfword * maskwords)
  l_gnu_chain_zero = l_gnu_buckets + (4 * nbuckets) - (4 * symndx)

  hsh = gnu_hash(symbol)
  bucket = hsh % nbuckets

  i = @leak.d(l_gnu_buckets + bucket * 4)
  return nil if i.zero?

  hsh2 = 0
  while (hsh2 & 1).zero?
    hsh2 = @leak.d(l_gnu_chain_zero + i * 4)
    if ((hsh ^ hsh2) >> 1).zero?
      sym = symtab + sym_size * i
      st_name = @leak.d(sym)
      name = @leak.n(strtab + st_name, symbol.length + 1)
      if name == ("#{symbol}\x00")
        offset = { 32 => 4, 64 => 8 }[@elfclass]
        st_value = unpack(@leak.n(sym + offset, @elfword))
        return @libbase + st_value
      end
    end
    i += 1
  end
  nil
end