//go:build windows

package winpwn

import (
	"strings"

	"golang.org/x/sys/windows"
)

// ImportedLibs returns the distinct DLLs listed in this PE's import table,
// each loaded into the current process (via LoadLibrary -- already-loaded
// system DLLs just hand back their existing mapping and a bumped refcount,
// which is immediately released again) to report its current live image
// base.
//
// This is useful on Windows specifically because a system DLL's base is
// randomized once per boot, not once per process: every process on the
// machine sees kernel32.dll/ntdll.dll/etc. at the same address until the
// next reboot. So the base reported here is a real, reusable value for
// planning an exploit against this machine -- not a property of some
// already-running target you'd otherwise have to leak from first.
func (p *PEFile) ImportedLibs() ([]ImportedLib, error) {
	imports, err := p.ListImports()
	if err != nil {
		return nil, err
	}

	seen := make(map[string]bool, len(imports))
	var out []ImportedLib
	for _, im := range imports {
		key := strings.ToLower(im.DLL)
		if im.DLL == "" || seen[key] {
			continue
		}
		seen[key] = true

		h, err := windows.LoadLibrary(im.DLL)
		if err != nil {
			out = append(out, ImportedLib{Name: im.DLL, Err: err})
			continue
		}
		out = append(out, ImportedLib{Name: im.DLL, Base: uint64(h)})
		windows.FreeLibrary(h)
	}
	return out, nil
}
