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.

Parameters:

  • addr (Integer)

    An address known to be inside the ELF.

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)

Returns Base of lib.

Returns:

  • (Integer)

    Base of lib.



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.

Returns:

  • (String?)

    Return BuildID in hex format or nil.



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.

Parameters:

  • symbol (String)

    The symbol name.

Returns:

  • (Integer, nil)

    The address of the symbol, or nil if not found.



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