// Package runtime discovers live driver state: loaded kernel modules, device // names, and named sections in the object manager namespace. package runtime import ( "strings" "unsafe" "golang.org/x/sys/windows" ) // Module is a loaded kernel module. type Module struct { ImageBase uintptr ImageSize uint32 Path string } // Modules returns the list of loaded kernel modules via // NtQuerySystemInformation(SystemModuleInformation). func Modules() ([]Module, error) { size := uint32(1 << 20) // 1 MiB initial; grows on STATUS_INFO_LENGTH_MISMATCH for { buf := make([]byte, size) err := windows.NtQuerySystemInformation(windows.SystemModuleInformation, unsafe.Pointer(&buf[0]), size, &size) if err == nil { return parseModules(buf), nil } if err != windows.STATUS_INFO_LENGTH_MISMATCH { return nil, err } } } // parseModules decodes an RTL_PROCESS_MODULES buffer into a slice of Module. func parseModules(buf []byte) []Module { mods := (*windows.RTL_PROCESS_MODULES)(unsafe.Pointer(&buf[0])) out := make([]Module, 0, mods.NumberOfModules) base := unsafe.Pointer(&mods.Modules[0]) entrySize := unsafe.Sizeof(windows.RTL_PROCESS_MODULE_INFORMATION{}) for i := uint32(0); i < mods.NumberOfModules; i++ { mi := (*windows.RTL_PROCESS_MODULE_INFORMATION)(unsafe.Pointer(uintptr(base) + uintptr(i)*entrySize)) out = append(out, Module{ ImageBase: mi.ImageBase, ImageSize: mi.ImageSize, Path: modulePath(mi), }) } return out } // modulePath extracts the null-terminated ANSI path from a module info entry. func modulePath(mi *windows.RTL_PROCESS_MODULE_INFORMATION) string { b := mi.FullPathName[:] n := 0 for n < len(b) && b[n] != 0 { n++ } return string(b[:n]) } // FindModule returns the loaded module whose file name matches name // (case-insensitive), or ok=false if it is not loaded. func FindModule(name string) (Module, bool) { mods, err := Modules() if err != nil { return Module{}, false } for _, m := range mods { base := m.Path if i := strings.LastIndexAny(base, `\/`); i >= 0 { base = base[i+1:] } if strings.EqualFold(base, name) { return m, true } } return Module{}, false }