node/lib/metasm/metasm/disassemble.rb
# returns the array of values pointed by the indirection at its invocation (ind.origin)
# first resolves the pointer using backtrace_value, if it does not point in edata keep the original pointer
# then backtraces from ind.origin until it finds an :w xref origin
# if no :w access is found, returns the value encoded in the raw section data
# TODO handle unaligned (partial?) writes
returns the array of values pointed by the indirection at its invocation (ind.origin)
first resolves the pointer using backtrace_value, if it does not point in edata keep the original pointer
then backtraces from ind.origin until it finds an :w xref origin
if no :w access is found, returns the value encoded in the raw section data
TODO handle unaligned (partial?) writes
returns the array of values pointed by the indirection at its invocation ( ind . origin ) first resolves the pointer using backtrace_value if it does not point in edata keep the original pointer then backtraces from ind . origin until it finds an : w xref origin if no : w access is found returns the value encoded in the raw section data TODO handle unaligned ( partial? ) writes
def backtrace_indirection(ind, maxdepth)
		if not ind.origin
			puts "backtrace_ind: no origin for #{ind}" if $VERBOSE
			return [ind]
		end
		ret = []
		decode_imm = lambda { |addr, len|
			edata = get_edata_at(addr)
			if edata
				Expression[ edata.decode_imm("u#{8*len}".to_sym, @cpu.endianness) ]
			else
				Expression::Unknown
			end
		}
		backtrace_value(ind.target, maxdepth).each { |ptr|
			refs = []
			each_xref(ptr, :w) { |x|
				next if not @decoded[x.origin]
				refs |= [x.origin]
			} if ptr != Expression::Unknown
			if refs.empty?
				if get_section_at(ptr)
					ret |= [decode_imm[ptr, ind.len]]
					next
				else
					initval = ind
				end
			else
				initval = true
			end
			backtrace_walk(initval, ind.origin, true, false, nil, maxdepth-1) { |ev, expr, h|
				case ev
				when :unknown_addr, :maxdepth, :stopaddr
puts "   backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtrace
					ret |= [Expression::Unknown]
				when :end
					if not refs.empty? and (expr == true or not need_backtrace(expr))
						if expr == true
							ret |= [decode_imm[ptr, ind.len]]
						else
							bd = expr.expr_indirections.inject({}) { |h_, i| h_.update i => decode_imm[i.target, i.len] }
							ret |= [Expression[expr.bind(bd).reduce]]
						end
					else
						ret |= [Expression::Unknown]
					end
				when :di
					di = h[:di]
					if expr == true
						next true if not refs.include? di.address
						writes = get_xrefs_rw(di)
						writes = writes.find_all { |x_type, x_ptr, x_len| x_type == :w and x_len == ind.len }
						if writes.length != 1
							puts "backtrace_ind: incompatible xrefs to #{ptr} from #{di}" if $DEBUG
							ret |= [Expression::Unknown]
							next false
						end
						expr = Indirection.new(writes[0][1], ind.len, di.address)
					end
					expr = backtrace_emu_instr(di, expr)
					if expr.expr_externals.all? { |e| @prog_binding[e] or @function[normalize(e)] } and expr.expr_indirections.empty?
						ret |= backtrace_value(expr, maxdepth-1-h[:loopdetect].length)
						false
					else
						expr
					end
				when :func
					next true if expr == true	
					expr = backtrace_emu_subfunc(h[:func], h[:funcaddr], h[:addr], expr, ind.origin, maxdepth-h[:loopdetect].length)
					if expr.expr_externals.all? { |e| @prog_binding[e] or @function[normalize(e)] } and expr.expr_indirections.empty?
						ret |= backtrace_value(expr, maxdepth-1-h[:loopdetect].length)
						false
					else
						expr
					end
				end
			}
		}
		ret
	end
def backtrace_indirection ( ind , maxdepth ) if not ind . origin puts "backtrace_ind: no origin for #{ind}" if $VERBOSE return [ ind ] end ret = [ ] decode_imm = lambda { | addr , len | edata = get_edata_at ( addr ) if edata Expression [ edata . decode_imm ( "u#{8*len}" . to_sym , @cpu . endianness ) ] else Expression :: Unknown end } backtrace_value ( ind . target , maxdepth ) . each { | ptr | refs = [ ] each_xref ( ptr , :w ) { | x | next if not @decoded [ x . origin ] refs |= [ x . origin ] } if ptr != Expression :: Unknown if refs . empty? if get_section_at ( ptr ) ret |= [ decode_imm [ ptr , ind . len ] ] next else initval = ind end else initval = true end backtrace_walk ( initval , ind . origin , true , false , nil , maxdepth - 1 ) { | ev , expr , h | case ev when :unknown_addr , :maxdepth , :stopaddr puts "   backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtrace ret |= [ Expression :: Unknown ] when :end if not refs . empty? and ( expr == true or not need_backtrace ( expr ) ) if expr == true ret |= [ decode_imm [ ptr , ind . len ] ] else bd = expr . expr_indirections . inject ( { } ) { | h_ , i | h_ . update i => decode_imm [ i . target , i . len ] } ret |= [ Expression [ expr . bind ( bd ) . reduce ] ] end else ret |= [ Expression :: Unknown ] end when :di di = h [ :di ] if expr == true next true if not refs . include? di . address writes = get_xrefs_rw ( di ) writes = writes . find_all { | x_type , x_ptr , x_len | x_type == :w and x_len == ind . len } if writes . length != 1 puts "backtrace_ind: incompatible xrefs to #{ptr} from #{di}" if $DEBUG ret |= [ Expression :: Unknown ] next false end expr = Indirection . new ( writes [ 0 ] [ 1 ] , ind . len , di . address ) end expr = backtrace_emu_instr ( di , expr ) if expr . expr_externals . all? { | e | @prog_binding [ e ] or @function [ normalize ( e ) ] } and expr . expr_indirections . empty? ret |= backtrace_value ( expr , maxdepth - 1 - h [ :loopdetect ] . length ) false else expr end when :func next true if expr == true expr = backtrace_emu_subfunc ( h [ :func ] , h [ :funcaddr ] , h [ :addr ] , expr , ind . origin , maxdepth - h [ :loopdetect ] . length ) if expr . expr_externals . all? { | e | @prog_binding [ e ] or @function [ normalize ( e ) ] } and expr . expr_indirections . empty? ret |= backtrace_value ( expr , maxdepth - 1 - h [ :loopdetect ] . length ) false else expr end end } } ret end
returns the array of values pointed by the indirection at its invocation (ind.origin)
first resolves the pointer using backtrace_value, if it does not point in edata keep the original pointer
then backtraces from ind.origin until it finds an :w xref origin
if no :w access is found, returns the value encoded in the raw section data
TODO handle unaligned (partial?)
returns the array of values pointed by the indirection at its invocation ( ind . origin ) first resolves the pointer using backtrace_value if it does not point in edata keep the original pointer then backtraces from ind . origin until it finds an : w xref origin if no : w access is found returns the value encoded in the raw section data TODO handle unaligned ( partial? )
# resolve pointers (they may include Indirections) # find write xrefs to the ptr # XXX should be rebacktracked on new xref # static data, newer written : return encoded value # unknown pointer : backtrace the indirection, hope it solves itself # wait until we find a write xref, then backtrace the written value # wait until we arrive at an xref'ing instruction, then backtrace the written value # found a path avoiding the :w xrefs, read the encoded initial value # unknown pointer, backtrace did not resolve... # find the expression to backtrace: assume this is the :w xref from this di # may have new indirections... recall bt_value ? #if not need_backtrace(expr) # XXX #if not need_backtrace(expr)
ind
maxdepth