lib/pwnlib/memleak.rb
# encoding: ASCII-8BIT
# frozen_string_literal: true
require 'pwnlib/util/packing'
module Pwnlib
# A class caching and heuristic tool for exploiting memory leaks.
class MemLeak
# Instantiate a {Pwnlib::MemLeak} object.
#
# @yieldparam [Integer] leak_addr
# The start address that the leaker should leak from.
#
# @yieldreturn [String]
# A leaked non-empty byte string, starting from +leak_addr+.
def initialize(&block)
@leak = block
@cache = {}
end
# Leak +numb+ bytes at +addr+.
# Returns a string with the leaked bytes.
#
# @param [Integer] addr
# The starting address of the leak.
# @param [Integer] numb
# Number of bytes to be leaked.
#
# @return [String]
# The leaked byte string.
def n(addr, numb)
(0...numb).map { |i| do_leak(addr + i) }.pack('C*')
end
# Leak a byte at +*((uint8_t*) addr)+.
#
# @param [Integer] addr
# The address of the leak.
#
# @return [Integer]
# The leaked byte.
def b(addr)
Util::Packing.u8(n(addr, 1))
end
# Leak a word at +*((uint16_t*) addr)+.
#
# @param [Integer] addr
# The address of the leak.
#
# @return [Integer]
# The leaked word.
def w(addr)
Util::Packing.u16(n(addr, 2))
end
# Leak a dword at +*((uint32_t*) addr)+.
#
# @param [Integer] addr
# The address of the leak.
#
# @return [Integer]
# The leaked dword.
def d(addr)
Util::Packing.u32(n(addr, 4))
end
# Leak a qword at +*((uint64_t*) addr)+.
#
# @param [Integer] addr
# The address of the leak.
#
# @return [Integer]
# The leaked qword.
def q(addr)
Util::Packing.u64(n(addr, 8))
end
private
# Call the leaker function on address +addr+.
# The result would be cached.
def do_leak(addr)
unless @cache.key?(addr)
data = @leak.call(addr)
data.bytes.each.with_index(addr) { |b, i| @cache[i] = b }
end
@cache[addr]
end
end
end