node/lib/metasm/metasm/disassemble.rb
def backtrace_check_found(expr, di, origin, type, len, maxdepth, detached, snapshot_addr=nil)
		# only entrypoints or block starts called by a :saveip are checked for being a function
		# want to execute [esp] from a block start
		if type == :x and di and di == di.block.list.first and @cpu.backtrace_is_function_return(expr, @decoded[origin]) and (
			# which is an entrypoint..
			(not di.block.from_normal and not di.block.from_subfuncret) or
			# ..or called from a saveip
			(bool = false ; di.block.each_from_normal { |fn| bool = true if @decoded[fn] and @decoded[fn].opcode.props[:saveip] } ; bool))

			# now we can mark the current address a function start
			# the actual return address will be found later (we tell the caller to continue the backtrace)
			addr = di.address
			l = auto_label_at(addr, 'sub', 'loc', 'xref')
			if not f = @function[addr]
				f = @function[addr] = DecodedFunction.new
				puts "found new function #{l} at #{Expression[addr]}" if $VERBOSE
			end
			f.finalized = false

			if @decoded[origin]
				f.return_address ||= []
				f.return_address |= [origin]
				@decoded[origin].add_comment "endsub #{l}"
				# TODO add_xref (to update the comment on rename_label)
			end

			f.backtracked_for |= @decoded[addr].block.backtracked_for.find_all { |btt| not btt.address }
		end

		return if need_backtrace(expr)
		if snapshot_addr
			return if expr.expr_externals(true).find { |ee| ee.kind_of?(Indirection) }
		end

puts "backtrace #{type} found #{expr} from #{di} orig #{@decoded[origin] || Expression[origin] if origin}" if debug_backtrace
		result = backtrace_value(expr, maxdepth)
		# keep the ori pointer in the results to emulate volatile memory (eg decompiler prefers this)
		#result << expr if not type	# XXX returning multiple values for nothing is too confusing, TODO fix decompiler
		result.uniq!

		# create xrefs/labels
		result.each { |e|
			backtrace_found_result(e, di, type, origin, len, detached)
		} if type and origin

		result
	end
# returns an array of expressions, or nil if expr needs more backtrace
# it needs more backtrace if expr.externals include a Symbol != :unknown (symbol == register value)
# if it need no more backtrace, expr's indirections are recursively resolved
# xrefs are created, and di args are updated (immediate => label)
# if type is :x, addrs_todo is updated, and if di starts a block, expr is checked to see if it may be a subfunction return value
#
# expr indirection are solved by first finding the value of the pointer, and then rebacktracking for write-type access
# detached is true if type is :x and from should not be set in addrs_todo (indirect call flow, eg external function callback)
# if the backtrace ends pre entrypoint, returns the value encoded in the raw binary
# XXX global variable (modified by another function), exported data, multithreaded app..
# TODO handle memory aliasing (mov ebx, eax ; write [ebx] ; read [eax])
# TODO trace expr evolution through backtrace, to modify immediates to an expr involving label names
# TODO mov [ptr], imm ; <...> ; jmp [ptr] => rename imm as loc_XX
#  eg. mov eax, 42 ; add eax, 4 ; jmp eax  =>  mov eax, some_label-4
returns an array of expressions, or nil if expr needs more backtrace
it needs more backtrace if expr.externals include a Symbol != :unknown (symbol == register value)
if it need no more backtrace, expr's indirections are recursively resolved
xrefs are created, and di args are updated (immediate => label)
if type is :x, addrs_todo is updated, and if di starts a block, expr is checked to see if it may be a subfunction return value

expr indirection are solved by first finding the value of the pointer, and then rebacktracking for write-type access
detached is true if type is :x and from should not be set in addrs_todo (indirect call flow, eg external function callback)
if the backtrace ends pre entrypoint, returns the value encoded in the raw binary
XXX global variable (modified by another function), exported data, multithreaded app
TODO handle memory aliasing (mov ebx, eax ; write [ebx] ; read [eax])
TODO trace expr evolution through backtrace, to modify immediates to an expr involving label names
TODO mov [ptr], imm ; <...> ; jmp [ptr] => rename imm as loc_XX
eg.
returns an array of expressions or nil if expr needs more backtrace it needs more backtrace if expr . externals include a Symbol ! = : unknown ( symbol == register value ) if it need no more backtrace expr ' s indirections are recursively resolved xrefs are created and di args are updated ( immediate = > label ) if type is : x addrs_todo is updated and if di starts a block expr is checked to see if it may be a subfunction return value expr indirection are solved by first finding the value of the pointer and then rebacktracking for write - type access detached is true if type is : x and from should not be set in addrs_todo ( indirect call flow eg external function callback ) if the backtrace ends pre entrypoint returns the value encoded in the raw binary XXX global variable ( modified by another function ) exported data multithreaded app TODO handle memory aliasing ( mov ebx eax ; write [ ebx ] ; read [ eax ] ) TODO trace expr evolution through backtrace to modify immediates to an expr involving label names TODO mov [ ptr ] imm ; < ... > ; jmp [ ptr ] = > rename imm as loc_XX eg .
def backtrace_check_found(expr, di, origin, type, len, maxdepth, detached, snapshot_addr=nil)
		if type == :x and di and di == di.block.list.first and @cpu.backtrace_is_function_return(expr, @decoded[origin]) and (
			(not di.block.from_normal and not di.block.from_subfuncret) or
			(bool = false ; di.block.each_from_normal { |fn| bool = true if @decoded[fn] and @decoded[fn].opcode.props[:saveip] } ; bool))
			addr = di.address
			l = auto_label_at(addr, 'sub', 'loc', 'xref')
			if not f = @function[addr]
				f = @function[addr] = DecodedFunction.new
				puts "found new function #{l} at #{Expression[addr]}" if $VERBOSE
			end
			f.finalized = false
			if @decoded[origin]
				f.return_address ||= []
				f.return_address |= [origin]
				@decoded[origin].add_comment "endsub #{l}"
			end
			f.backtracked_for |= @decoded[addr].block.backtracked_for.find_all { |btt| not btt.address }
		end
		return if need_backtrace(expr)
		if snapshot_addr
			return if expr.expr_externals(true).find { |ee| ee.kind_of?(Indirection) }
		end
puts "backtrace #{type} found #{expr} from #{di} orig #{@decoded[origin] || Expression[origin] if origin}" if debug_backtrace
		result = backtrace_value(expr, maxdepth)
		result.uniq!
		result.each { |e|
			backtrace_found_result(e, di, type, origin, len, detached)
		} if type and origin
		result
	end
def backtrace_check_found ( expr , di , origin , type , len , maxdepth , detached , snapshot_addr = nil ) if type == :x and di and di == di . block . list . first and @cpu . backtrace_is_function_return ( expr , @decoded [ origin ] ) and ( ( not di . block . from_normal and not di . block . from_subfuncret ) or ( bool = false ; di . block . each_from_normal { | fn | bool = true if @decoded [ fn ] and @decoded [ fn ] . opcode . props [ :saveip ] } ; bool ) ) addr = di . address l = auto_label_at ( addr , 'sub' , 'loc' , 'xref' ) if not f = @function [ addr ] f = @function [ addr ] = DecodedFunction . new puts "found new function #{l} at #{Expression[addr]}" if $VERBOSE end f . finalized = false if @decoded [ origin ] f . return_address ||= [ ] f . return_address |= [ origin ] @decoded [ origin ] . add_comment "endsub #{l}" end f . backtracked_for |= @decoded [ addr ] . block . backtracked_for . find_all { | btt | not btt . address } end return if need_backtrace ( expr ) if snapshot_addr return if expr . expr_externals ( true ) . find { | ee | ee . kind_of? ( Indirection ) } end puts "backtrace #{type} found #{expr} from #{di} orig #{@decoded[origin] || Expression[origin] if origin}" if debug_backtrace result = backtrace_value ( expr , maxdepth ) result . uniq! result . each { | e | backtrace_found_result ( e , di , type , origin , len , detached ) } if type and origin result end
returns an array of expressions, or nil if expr needs more backtrace
it needs more backtrace if expr.externals include a Symbol != :unknown (symbol == register value)
if it need no more backtrace, expr's indirections are recursively resolved
xrefs are created, and di args are updated (immediate => label)
if type is :x, addrs_todo is updated, and if di starts a block, expr is checked to see if it may be a subfunction return value
returns an array of expressions or nil if expr needs more backtrace it needs more backtrace if expr . externals include a Symbol ! = : unknown ( symbol == register value ) if it need no more backtrace expr ' s indirections are recursively resolved xrefs are created and di args are updated ( immediate = > label ) if type is : x addrs_todo is updated and if di starts a block expr is checked to see if it may be a subfunction return value
# only entrypoints or block starts called by a :saveip are checked for being a function # want to execute [esp] from a block start # which is an entrypoint.. # ..or called from a saveip # now we can mark the current address a function start # the actual return address will be found later (we tell the caller to continue the backtrace) # TODO add_xref (to update the comment on rename_label) # keep the ori pointer in the results to emulate volatile memory (eg decompiler prefers this) #result << expr if not type	# XXX returning multiple values for nothing is too confusing, TODO fix decompiler # create xrefs/labels
expr
di
origin
type
len
maxdepth
detached
snapshot_addr