node/lib/metasm/metasm/exe_format/pe.rb
def memdump_imports(memory, dump, unk_iat_p=nil)
		puts 'rebuilding imports...' if $VERBOSE
		if unk_iat_p
			# read iat data from unk_iat_p
			iat_p = unk_iat_p
		else
			return if not imports
			# read iat data from @imports
			imports = @imports.dup
			imports.each { |id| id.iat = id.iat.dup }
			iat_p = imports.first.iat_p	# used for iat_p
		end

		failcnt = 0		# bad pointers in iat table (unk_ only)
		dump.imports ||= []
		loaded_dll = nil	# the dll from who we're importing the current importdirectory
		ptrsz = (@optheader.signature == 'PE+' ? 8 : 4)
		cache = []	# optimize forwarder target search
		loop do
			if unk_iat_p
				# read imported pointer from the table
				ptr = decode_xword(EncodedData.new(memory[@load_address + iat_p, ptrsz]))
				iat_p += ptrsz
			else
				# read imported pointer from the import structure
				while not ptr = imports.first.iat.shift
					imports.shift
					break if imports.empty?
					iat_p = imports.first.iat_p
				end
				break if imports.empty?
				iat_p += ptrsz
			end

			if not loaded_dll or not e = loaded_dll.export.exports.find { |e_| loaded_dll.label_rva(e_.target) == ptr - loaded_dll.load_address }
				# points to unknown space
				# find pointed module start
				if not dll = cache.find { |dll_| ptr >= dll_.load_address and ptr < dll_.load_address + dll_.optheader.image_size }
					addr = ptr & ~0xffff
					256.times { break if memory[addr, 2] == MZ::MAGIC or addr < 0x10000 ; addr -= 0x10000 }
					if memory[addr, 2] == MZ::MAGIC
						dll = LoadedPE.load memory[addr, 0x1000_0000]
						dll.load_address = addr
						dll.decode_header
						dll.decode_exports
						cache << dll
					end
				end
				if dll and dll.export and e = dll.export.exports.find { |e_| dll.label_rva(e_.target) == ptr - dll.load_address }
					if loaded_dll and ee = loaded_dll.export.exports.find { |ee_| ee_.forwarder_name == e.name }
						# it's a forwarder from the current loaded_dll
						puts "forwarder #{ee.name} -> #{dll.export.libname}!#{e.name}" if $DEBUG
						e = ee
					else
						# new library, start a new importdirectory
						# XXX if 1st import is forwarded, loaded_dll will points to the bad module...
						loaded_dll = dll
						id = ImportDirectory.new
						id.libname = loaded_dll.export.libname
						puts "lib #{id.libname}" if $VERBOSE
						id.imports = []
						id.iat_p = iat_p - ptrsz
						dump.imports << id
					end
				else
					puts 'unknown ptr %x' % ptr if $DEBUG
					# allow holes in the unk_iat_p table
					break if not unk_iat_p or failcnt > 4
					loaded_dll = nil
					failcnt += 1
					next
				end
				failcnt = 0
			end

			# dumped last importdirectory is correct, append the import field
			i = ImportDirectory::Import.new
			if e.name
				puts e.name if $DEBUG
				i.name = e.name
			else
				puts "##{e.ordinal}" if $DEBUG
				i.ordinal = e.ordinal
			end
			dump.imports.last.imports << i
		end
	end
# rebuilds an IAT from the loaded pe and the memory
#  for each loaded iat, find the matching dll in memory
#  for each loaded iat entry, retrieve the exported name from the loaded dll
# OR
#  from a base iat address in memory (unk_iat_p, rva), retrieve the 1st dll, find
#  all iat pointers/forwarders to this dll, on failure try to find another dll
#  allows gaps of 5 invalid pointers between libraries
# dll found by scanning pages 16 by 16 backward from the first iat address (XXX the 1st must not be forwarded)
# TODO bound imports
rebuilds an IAT from the loaded pe and the memory
for each loaded iat, find the matching dll in memory
for each loaded iat entry, retrieve the exported name from the loaded dll
OR
from a base iat address in memory (unk_iat_p, rva), retrieve the 1st dll, find
all iat pointers/forwarders to this dll, on failure try to find another dll
allows gaps of 5 invalid pointers between libraries
dll found by scanning pages 16 by 16 backward from the first iat address (XXX the 1st must not be forwarded)
TODO bound imports
rebuilds an IAT from the loaded pe and the memory for each loaded iat find the matching dll in memory for each loaded iat entry retrieve the exported name from the loaded dll OR from a base iat address in memory ( unk_iat_p rva ) retrieve the 1st dll find all iat pointers / forwarders to this dll on failure try to find another dll allows gaps of 5 invalid pointers between libraries dll found by scanning pages 16 by 16 backward from the first iat address ( XXX the 1st must not be forwarded ) TODO bound imports
def memdump_imports(memory, dump, unk_iat_p=nil)
		puts 'rebuilding imports...' if $VERBOSE
		if unk_iat_p
			iat_p = unk_iat_p
		else
			return if not imports
			imports = @imports.dup
			imports.each { |id| id.iat = id.iat.dup }
			iat_p = imports.first.iat_p	
		end
		failcnt = 0		
		dump.imports ||= []
		loaded_dll = nil	
		ptrsz = (@optheader.signature == 'PE+' ? 8 : 4)
		cache = []	
		loop do
			if unk_iat_p
				ptr = decode_xword(EncodedData.new(memory[@load_address + iat_p, ptrsz]))
				iat_p += ptrsz
			else
				while not ptr = imports.first.iat.shift
					imports.shift
					break if imports.empty?
					iat_p = imports.first.iat_p
				end
				break if imports.empty?
				iat_p += ptrsz
			end
			if not loaded_dll or not e = loaded_dll.export.exports.find { |e_| loaded_dll.label_rva(e_.target) == ptr - loaded_dll.load_address }
				if not dll = cache.find { |dll_| ptr >= dll_.load_address and ptr < dll_.load_address + dll_.optheader.image_size }
					addr = ptr & ~0xffff
					256.times { break if memory[addr, 2] == MZ::MAGIC or addr < 0x10000 ; addr -= 0x10000 }
					if memory[addr, 2] == MZ::MAGIC
						dll = LoadedPE.load memory[addr, 0x1000_0000]
						dll.load_address = addr
						dll.decode_header
						dll.decode_exports
						cache << dll
					end
				end
				if dll and dll.export and e = dll.export.exports.find { |e_| dll.label_rva(e_.target) == ptr - dll.load_address }
					if loaded_dll and ee = loaded_dll.export.exports.find { |ee_| ee_.forwarder_name == e.name }
						puts "forwarder #{ee.name} -> #{dll.export.libname}!#{e.name}" if $DEBUG
						e = ee
					else
						loaded_dll = dll
						id = ImportDirectory.new
						id.libname = loaded_dll.export.libname
						puts "lib #{id.libname}" if $VERBOSE
						id.imports = []
						id.iat_p = iat_p - ptrsz
						dump.imports << id
					end
				else
					puts 'unknown ptr %x' % ptr if $DEBUG
					break if not unk_iat_p or failcnt > 4
					loaded_dll = nil
					failcnt += 1
					next
				end
				failcnt = 0
			end
			i = ImportDirectory::Import.new
			if e.name
				puts e.name if $DEBUG
				i.name = e.name
			else
				puts "##{e.ordinal}" if $DEBUG
				i.ordinal = e.ordinal
			end
			dump.imports.last.imports << i
		end
	end
def memdump_imports ( memory , dump , unk_iat_p = nil ) puts 'rebuilding imports...' if $VERBOSE if unk_iat_p iat_p = unk_iat_p else return if not imports imports = @imports . dup imports . each { | id | id . iat = id . iat . dup } iat_p = imports . first . iat_p end failcnt = 0 dump . imports ||= [ ] loaded_dll = nil ptrsz = ( @optheader . signature == 'PE+' ? 8 : 4 ) cache = [ ] loop do if unk_iat_p ptr = decode_xword ( EncodedData . new ( memory [ @load_address + iat_p , ptrsz ] ) ) iat_p += ptrsz else while not ptr = imports . first . iat . shift imports . shift break if imports . empty? iat_p = imports . first . iat_p end break if imports . empty? iat_p += ptrsz end if not loaded_dll or not e = loaded_dll . export . exports . find { | e_ | loaded_dll . label_rva ( e_ . target ) == ptr - loaded_dll . load_address } if not dll = cache . find { | dll_ | ptr >= dll_ . load_address and ptr < dll_ . load_address + dll_ . optheader . image_size } addr = ptr & ~ 0xffff 256 . times { break if memory [ addr , 2 ] == MZ :: MAGIC or addr < 0x10000 ; addr -= 0x10000 } if memory [ addr , 2 ] == MZ :: MAGIC dll = LoadedPE . load memory [ addr , 0x1000_0000 ] dll . load_address = addr dll . decode_header dll . decode_exports cache << dll end end if dll and dll . export and e = dll . export . exports . find { | e_ | dll . label_rva ( e_ . target ) == ptr - dll . load_address } if loaded_dll and ee = loaded_dll . export . exports . find { | ee_ | ee_ . forwarder_name == e . name } puts "forwarder #{ee.name} -> #{dll.export.libname}!#{e.name}" if $DEBUG e = ee else loaded_dll = dll id = ImportDirectory . new id . libname = loaded_dll . export . libname puts "lib #{id.libname}" if $VERBOSE id . imports = [ ] id . iat_p = iat_p - ptrsz dump . imports << id end else puts 'unknown ptr %x' % ptr if $DEBUG break if not unk_iat_p or failcnt > 4 loaded_dll = nil failcnt += 1 next end failcnt = 0 end i = ImportDirectory :: Import . new if e . name puts e . name if $DEBUG i . name = e . name else puts "##{e.ordinal}" if $DEBUG i . ordinal = e . ordinal end dump . imports . last . imports << i end end
rebuilds an IAT from the loaded pe and the memory
for each loaded iat, find the matching dll in memory
for each loaded iat entry, retrieve the exported name from the loaded dll
OR
from a base iat address in memory (unk_iat_p, rva), retrieve the 1st dll, find
all iat pointers/forwarders to this dll, on failure try to find another dll
allows gaps of 5 invalid pointers between libraries
dll found by scanning pages 16 by 16 backward from the first iat address (XXX the 1st must not be forwarded)
TODO bound imports
rebuilds an IAT from the loaded pe and the memory for each loaded iat find the matching dll in memory for each loaded iat entry retrieve the exported name from the loaded dll OR from a base iat address in memory ( unk_iat_p rva ) retrieve the 1st dll find all iat pointers / forwarders to this dll on failure try to find another dll allows gaps of 5 invalid pointers between libraries dll found by scanning pages 16 by 16 backward from the first iat address ( XXX the 1st must not be forwarded ) TODO bound imports
# read iat data from unk_iat_p # read iat data from @imports # used for iat_p # bad pointers in iat table (unk_ only) # the dll from who we're importing the current importdirectory # optimize forwarder target search # read imported pointer from the table # read imported pointer from the import structure # points to unknown space # find pointed module start # it's a forwarder from the current loaded_dll # new library, start a new importdirectory # XXX if 1st import is forwarded, loaded_dll will points to the bad module... # allow holes in the unk_iat_p table # dumped last importdirectory is correct, append the import field
memory
dump
unk_iat_p