class Metasm::InstructionBlock

holds a list of contiguous decoded instructions, forming an uninterrupted block (except for eg CPU exceptions) most attributes are either a value or an array of values, use the associated iterator.

Attributes

address[RW]

address of the first instruction

backtracked_for[RW]

array of BacktraceTrace when a new code path comes to us, it should be backtracked for the values of :r/:w/:x using btt with no address for internal use only (block splitting): btt with an address

edata[RW]

pointer to raw data

edata_ptr[RW]

pointer to raw data

from_indirect[RW]

address of instructions executed indirectly through us (callback in a subfunction, SEH…) XXX #from_indirect is not populated for now

from_normal[RW]

address of instructions giving control directly to us includes addr of normal instruction when call flow continues to us past the end of the preceding block does not include addresses of subfunction return instructions may be nil or an array

from_subfuncret[RW]

address of an instruction that calls a subfunction which returns to us

list[RW]

list of DecodedInstructions

to_indirect[RW]

address of instructions executed indirectly through us (callback in a subfunction, SEH…) XXX #from_indirect is not populated for now

to_normal[RW]

address of instructions called/jumped to

to_subfuncret[RW]

address of instruction executed after a called subfunction returns

Public Class Methods

new(arg0, edata=nil, edata_ptr=nil) click to toggle source

create a new InstructionBlock based at address also accepts a DecodedInstruction or an Array of them to initialize from

# File metasm/disassemble.rb, line 171
def initialize(arg0, edata=nil, edata_ptr=nil)
        @list = []
        case arg0
        when DecodedInstruction
                @address = arg0.address
                add_di(arg0)
        when Array
                @address = arg0.first.address if not arg0.empty?
                arg0.each { |di| add_di(di) }
        else
                @address = arg0
        end
        edata_ptr ||= edata ? edata.ptr : 0
        @edata, @edata_ptr = edata, edata_ptr
        @backtracked_for = []
end

Public Instance Methods

add_di(di) click to toggle source

adds a decodedinstruction to the block list, updates di.block and di.block_offset

# File metasm/disassemble.rb, line 213
def add_di(di)
        di.block = self
        di.block_offset = bin_length
        di.address ||= @address + di.block_offset
        @list << di
end
add_from(addr, type=:normal) click to toggle source

adds an address to the from_normal/from_subfuncret list

# File metasm/disassemble_api.rb, line 11
def add_from(addr, type=:normal)
        send "add_from_#{type}", addr
end
add_from_indirect(addr) click to toggle source
# File metasm/disassemble_api.rb, line 22
def add_from_indirect(addr)
        @from_indirect ||= []
        @from_indirect |= [addr]
end
add_from_normal(addr) click to toggle source
# File metasm/disassemble_api.rb, line 14
def add_from_normal(addr)
        @from_normal ||= []
        @from_normal |= [addr]
end
add_from_subfuncret(addr) click to toggle source
# File metasm/disassemble_api.rb, line 18
def add_from_subfuncret(addr)
        @from_subfuncret ||= []
        @from_subfuncret |= [addr]
end
add_to(addr, type=:normal) click to toggle source
# File metasm/disassemble_api.rb, line 42
def add_to(addr, type=:normal)
        send "add_to_#{type}", addr
end
add_to_indirect(addr) click to toggle source
# File metasm/disassemble_api.rb, line 53
def add_to_indirect(addr)
        @to_indirect ||= []
        @to_indirect |= [addr]
end
add_to_normal(addr) click to toggle source
# File metasm/disassemble_api.rb, line 45
def add_to_normal(addr)
        @to_normal ||= []
        @to_normal |= [addr]
end
add_to_subfuncret(addr) click to toggle source
# File metasm/disassemble_api.rb, line 49
def add_to_subfuncret(addr)
        @to_subfuncret ||= []
        @to_subfuncret |= [addr]
end
bin_length() click to toggle source
# File metasm/disassemble.rb, line 188
def bin_length
        (di = @list.last) ? di.block_offset + di.bin_length : 0
end
each_from() { |a, :normal| ... } click to toggle source

iterates over every from address, yields [address, type in [:normal, :subfuncret, :indirect]]

# File metasm/disassemble_api.rb, line 27
def each_from
        each_from_normal { |a| yield a, :normal }
        each_from_subfuncret { |a| yield a, :subfuncret }
        each_from_indirect { |a| yield a, :indirect }
end
each_from_indirect(&b) click to toggle source
# File metasm/disassemble_api.rb, line 38
def each_from_indirect(&b)
        @from_indirect.each(&b) if from_indirect
end
each_from_normal(&b) click to toggle source
# File metasm/disassemble_api.rb, line 32
def each_from_normal(&b)
        @from_normal.each(&b) if from_normal
end
each_from_otherfunc(dasm, &b) click to toggle source

yields all from that are not in the same subfunction as this block

# File metasm/disassemble_api.rb, line 80
def each_from_otherfunc(dasm, &b)
        @from_normal.each(&b) if from_normal and dasm.function[address]
        @from_subfuncret.each(&b) if from_subfuncret and dasm.function[address]
        @from_indirect.each(&b) if from_indirect
end
each_from_samefunc(dasm, &b) click to toggle source

yields all from that are from the same function

# File metasm/disassemble_api.rb, line 73
def each_from_samefunc(dasm, &b)
        return if dasm.function[address]
        @from_subfuncret.each(&b) if from_subfuncret
        @from_normal.each(&b) if from_normal
end
each_from_subfuncret(&b) click to toggle source
# File metasm/disassemble_api.rb, line 35
def each_from_subfuncret(&b)
        @from_subfuncret.each(&b) if from_subfuncret
end
each_to() { |a, :normal| ... } click to toggle source
# File metasm/disassemble_api.rb, line 57
def each_to
        each_to_normal     { |a| yield a, :normal }
        each_to_subfuncret { |a| yield a, :subfuncret }
        each_to_indirect   { |a| yield a, :indirect }
end
each_to_indirect(&b) click to toggle source
# File metasm/disassemble_api.rb, line 68
def each_to_indirect(&b)
        @to_indirect.each(&b) if to_indirect
end
each_to_normal(&b) click to toggle source
# File metasm/disassemble_api.rb, line 62
def each_to_normal(&b)
        @to_normal.each(&b) if to_normal
end
each_to_otherfunc(dasm) { |to| ... } click to toggle source

yields all to that are not in the same subfunction as this block

# File metasm/disassemble_api.rb, line 96
def each_to_otherfunc(dasm)
        each_to { |to, type|
                to = dasm.normalize(to)
                yield to if type == :indirect or dasm.function[to] or not dasm.decoded[to]
        }
end
each_to_samefunc(dasm) { |to| ... } click to toggle source

yields all to that are in the same subfunction as this block

# File metasm/disassemble_api.rb, line 87
def each_to_samefunc(dasm)
        each_to { |to, type|
                next if type != :normal and type != :subfuncret
                to = dasm.normalize(to)
                yield to if not dasm.function[to]
        }
end
each_to_subfuncret(&b) click to toggle source
# File metasm/disassemble_api.rb, line 65
def each_to_subfuncret(&b)
        @to_subfuncret.each(&b) if to_subfuncret
end
from_otherfunc(dasm) click to toggle source
# File metasm/disassemble_api.rb, line 109
def from_otherfunc(dasm)
        ary = []
        each_from_otherfunc(dasm) { |a| ary << a }
        ary
end
from_samefunc(dasm) click to toggle source

returns the array used in #each_from_samefunc

# File metasm/disassemble_api.rb, line 104
def from_samefunc(dasm)
        ary = []
        each_from_samefunc(dasm) { |a| ary << a }
        ary
end
split(addr) click to toggle source

splits the current block into a new one with all di from address addr to end caller is responsible for rebacktracing new.bt_for to regenerate correct old.btt/new.btt

# File metasm/disassemble.rb, line 194
def split(addr)
        raise "invalid split @#{Expression[addr]}" if not idx = @list.index(@list.find { |di| di.address == addr }) or idx == 0
        off = @list[idx].block_offset
        new_b = self.class.new(addr, @edata, @edata_ptr + off)
        new_b.add_di @list.delete_at(idx) while @list[idx]
        new_b.to_normal, @to_normal = to_normal, new_b.to_normal
        new_b.to_subfuncret, @to_subfuncret = to_subfuncret, new_b.to_subfuncret
        new_b.add_from @list.last.address
        add_to new_b.address
        @backtracked_for.delete_if { |btt|
                if btt.address and new_b.list.find { |di| di.address == btt.address }
                        new_b.backtracked_for << btt
                        true
                end
        }
        new_b
end
to_otherfunc(dasm) click to toggle source
# File metasm/disassemble_api.rb, line 119
def to_otherfunc(dasm)
        ary = []
        each_to_otherfunc(dasm) { |a| ary << a }
        ary
end
to_samefunc(dasm) click to toggle source
# File metasm/disassemble_api.rb, line 114
def to_samefunc(dasm)
        ary = []
        each_to_samefunc(dasm) { |a| ary << a }
        ary
end