mirror of
https://github.com/kernelstub/Ferrum
synced 2026-06-21 13:55:09 +00:00
fix: CLSID data truncation & more (1.0.1)
This commit is contained in:
@@ -145,6 +145,7 @@ func (m module) Run(ctx *core.Context) error {
|
||||
ctx.Logger.Info("No findings returned for " + m.name + ".")
|
||||
return nil
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("%s findings returned: %d", m.name, len(findings)))
|
||||
for _, finding := range findings {
|
||||
ctx.Logger.Success(fmt.Sprintf("%s %s > %s", finding.Severity, finding.Target, finding.Reason))
|
||||
if finding.Name != "" || finding.Value != "" {
|
||||
|
||||
+24
-18
@@ -8,13 +8,10 @@ import (
|
||||
"sync"
|
||||
|
||||
"ferrum/core"
|
||||
"ferrum/internal"
|
||||
win "ferrum/windows/facade"
|
||||
)
|
||||
|
||||
const maxProcessWorkers = 16
|
||||
const maxVerboseCLSID = 40
|
||||
const maxProcMonCandidates = 120
|
||||
|
||||
func init() {
|
||||
core.Register(Module{})
|
||||
@@ -41,14 +38,16 @@ func (Module) Run(ctx *core.Context) error {
|
||||
ctx.Logger.Info("Inspecting process security context...")
|
||||
enriched := enrichProcesses(ctx, processes)
|
||||
sortProcesses(enriched)
|
||||
ctx.Logger.Info(fmt.Sprintf("Processes enumerated: %d", len(enriched)))
|
||||
|
||||
interesting := 0
|
||||
for _, process := range enriched {
|
||||
if !process.Interesting {
|
||||
continue
|
||||
}
|
||||
status := "process"
|
||||
if process.Interesting {
|
||||
interesting++
|
||||
ctx.Logger.Success(fmt.Sprintf("%s[%d] > %s", process.Name, process.PID, process.Label()))
|
||||
status = "privileged/elevated process"
|
||||
}
|
||||
ctx.Logger.Success(fmt.Sprintf("%s[%d] > %s > %s", process.Name, process.PID, status, process.Label()))
|
||||
if process.Detail != "" {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s[%d] : %s", process.Name, process.PID, process.Detail))
|
||||
}
|
||||
@@ -62,6 +61,7 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if err != nil {
|
||||
ctx.Logger.Error(fmt.Sprintf("CLSID ProcMon candidate scan: %v", err))
|
||||
} else {
|
||||
ctx.Logger.Info(fmt.Sprintf("CLSID ProcMon candidates: %d", len(candidates)))
|
||||
reportProcMonCandidates(ctx, candidates, interestingProcesses(enriched))
|
||||
}
|
||||
|
||||
@@ -76,11 +76,16 @@ func (Module) Run(ctx *core.Context) error {
|
||||
ctx.Logger.Info("No HKCU CLSID registrations found.")
|
||||
return nil
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("HKCU CLSID values enumerated: %d", len(entries)))
|
||||
|
||||
for _, entry := range summarizeCLSID(entries) {
|
||||
ctx.Logger.Success(fmt.Sprintf("HKCU\\Software\\Classes\\CLSID\\%s > %s", entry.CLSID, entry.Kind))
|
||||
name := entry.Name
|
||||
if name == "" {
|
||||
name = "(Default)"
|
||||
}
|
||||
ctx.Logger.Success(fmt.Sprintf("%s > %s > %s", entry.Path, name, entry.Kind))
|
||||
if entry.Value != "" {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s : %s", entry.CLSID, entry.Value))
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s : type=%d value=%s", entry.CLSID, entry.Type, entry.Value))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,19 +111,17 @@ func reportProcMonCandidates(ctx *core.Context, candidates []win.CLSIDProcMonCan
|
||||
processLabel := "NT AUTHORITY\\SYSTEM / privileged COM client"
|
||||
if len(processes) > 0 {
|
||||
names := make([]string, 0, len(processes))
|
||||
for _, process := range internal.Limit(processes, 8) {
|
||||
for _, process := range processes {
|
||||
names = append(names, fmt.Sprintf("%s[%d]", process.Name, process.PID))
|
||||
}
|
||||
processLabel = strings.Join(names, ", ")
|
||||
processLabel = fmt.Sprintf("%d privileged/elevated process(es)", len(processes))
|
||||
ctx.Logger.Info("Privileged/elevated process set: " + strings.Join(names, ", "))
|
||||
}
|
||||
|
||||
for _, candidate := range internal.Limit(candidates, maxProcMonCandidates) {
|
||||
for _, candidate := range candidates {
|
||||
ctx.Logger.Success(fmt.Sprintf("%s > %s > %s", processLabel, candidate.Path, candidate.Result))
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s : CLSID=%s machine=%s", candidate.Kind, candidate.CLSID, candidate.MachineValue))
|
||||
}
|
||||
if len(candidates) > maxProcMonCandidates {
|
||||
ctx.Logger.Info(fmt.Sprintf("CLSID ProcMon candidate output limited to %d of %d rows.", maxProcMonCandidates, len(candidates)))
|
||||
}
|
||||
ctx.Logger.Info("These rows model the ProcMon filter Result=NAME NOT FOUND for HKCU COM override paths. Confirm live process access with ProcMon or ETW before treating a candidate as reachable.")
|
||||
}
|
||||
|
||||
@@ -222,7 +225,7 @@ func detail(token win.TokenInfo) string {
|
||||
parts = append(parts, "elevated=true")
|
||||
}
|
||||
if len(token.Privileges) > 0 {
|
||||
parts = append(parts, "privileges="+strings.Join(internal.Limit(token.Privileges, 8), ","))
|
||||
parts = append(parts, "privileges="+strings.Join(token.Privileges, ","))
|
||||
}
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
@@ -241,7 +244,10 @@ func summarizeCLSID(entries []win.CLSIDEntry) []win.CLSIDEntry {
|
||||
if entries[i].CLSID != entries[j].CLSID {
|
||||
return entries[i].CLSID < entries[j].CLSID
|
||||
}
|
||||
return entries[i].Kind < entries[j].Kind
|
||||
if entries[i].Path != entries[j].Path {
|
||||
return entries[i].Path < entries[j].Path
|
||||
}
|
||||
return entries[i].Name < entries[j].Name
|
||||
})
|
||||
return internal.Limit(entries, maxVerboseCLSID)
|
||||
return entries
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"ferrum/core"
|
||||
"ferrum/internal"
|
||||
win "ferrum/windows/facade"
|
||||
)
|
||||
|
||||
@@ -24,6 +23,7 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("DLL search entries enumerated: %d", len(findings)))
|
||||
reported := 0
|
||||
for _, finding := range findings {
|
||||
if finding.Severity == "Info" {
|
||||
@@ -37,7 +37,7 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if reported == 0 {
|
||||
ctx.Logger.Info("No risky DLL search path entries matched the default heuristics.")
|
||||
}
|
||||
for _, finding := range internal.Limit(findings, 40) {
|
||||
for _, finding := range findings {
|
||||
if finding.Severity == "Info" {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("KnownDLL : %s", finding.Path))
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("Drivers enumerated: %d", len(drivers)))
|
||||
reported := 0
|
||||
for _, driver := range drivers {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("driver inventory : name=%s state=%s start=%s path=%s", driver.Name, driver.State, driver.StartType, driver.BinaryPath))
|
||||
reason := driverReason(driver)
|
||||
if reason == "" {
|
||||
continue
|
||||
@@ -37,7 +39,6 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if reported == 0 {
|
||||
ctx.Logger.Info("No driver load paths matched the suspicious-path heuristics.")
|
||||
}
|
||||
ctx.Logger.Verbose(fmt.Sprintf("Drivers enumerated: %d", len(drivers)))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Vendored
+7
-1
@@ -24,15 +24,21 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("Environment variables inspected: %d", len(vars)))
|
||||
reported := 0
|
||||
for _, env := range vars {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("environment inventory : %s=%s", env.Name, env.Value))
|
||||
reason := envReason(env)
|
||||
if reason == "" {
|
||||
continue
|
||||
}
|
||||
reported++
|
||||
ctx.Logger.Success(fmt.Sprintf("%s > %s", env.Name, reason))
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s=%s", env.Name, env.Value))
|
||||
}
|
||||
ctx.Logger.Verbose(fmt.Sprintf("Environment variables inspected: %d", len(vars)))
|
||||
if reported == 0 {
|
||||
ctx.Logger.Info("No environment variables matched the default audit heuristics.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,10 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("Process mitigations sampled: %d", len(items)))
|
||||
reported := 0
|
||||
for _, item := range items {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("mitigation inventory : name=%s pid=%d DEP=%s ASLR=%s StrictHandle=%s CFG=%s", item.Name, item.PID, item.DEP, item.ASLR, item.Strict, item.CFG))
|
||||
reason := mitigationReason(item)
|
||||
if reason == "" {
|
||||
continue
|
||||
@@ -37,7 +39,6 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if reported == 0 {
|
||||
ctx.Logger.Info("No accessible process mitigation gaps matched the default heuristics.")
|
||||
}
|
||||
ctx.Logger.Verbose(fmt.Sprintf("Processes sampled: %d", len(items)))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"ferrum/core"
|
||||
"ferrum/internal"
|
||||
win "ferrum/windows/facade"
|
||||
)
|
||||
|
||||
@@ -35,7 +34,7 @@ func (Module) Run(ctx *core.Context) error {
|
||||
ctx.Logger.Success(fmt.Sprintf("%s > %s", pipe.Name, reason))
|
||||
}
|
||||
ctx.Logger.Verbose(fmt.Sprintf("Pipes enumerated: %d", len(pipes)))
|
||||
for _, pipe := range internal.Limit(pipes, 50) {
|
||||
for _, pipe := range pipes {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("pipe : %s", pipe.Name))
|
||||
}
|
||||
if reported == 0 {
|
||||
|
||||
@@ -23,6 +23,7 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("Policy checks returned: %d", len(findings)))
|
||||
for _, finding := range findings {
|
||||
ctx.Logger.Success(fmt.Sprintf("%s %s > %s", finding.Severity, finding.Name, finding.Reason))
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s = %s", finding.Name, finding.Value))
|
||||
|
||||
@@ -27,6 +27,7 @@ func (Module) Run(ctx *core.Context) error {
|
||||
ctx.Logger.Info("No sensitive registry findings matched the configured checks.")
|
||||
return nil
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("Registry findings returned: %d", len(findings)))
|
||||
for _, finding := range findings {
|
||||
ctx.Logger.Success(fmt.Sprintf("%s %s\\%s > %s: %s", finding.Severity, finding.Scope, finding.Path, finding.Name, finding.Reason))
|
||||
if finding.Value != "" {
|
||||
|
||||
@@ -24,8 +24,10 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("Scheduled tasks enumerated: %d", len(tasks)))
|
||||
reported := 0
|
||||
for _, task := range tasks {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("task inventory : path=%s enabled=%s author=%s command=%s", task.Path, task.Enabled, task.Author, task.Command))
|
||||
reason := taskReason(task)
|
||||
if reason == "" {
|
||||
continue
|
||||
@@ -37,7 +39,6 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if reported == 0 {
|
||||
ctx.Logger.Info("No scheduled tasks matched the default interesting-command heuristics.")
|
||||
}
|
||||
ctx.Logger.Verbose(fmt.Sprintf("Tasks enumerated: %d", len(tasks)))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"ferrum/core"
|
||||
"ferrum/internal"
|
||||
win "ferrum/windows/facade"
|
||||
)
|
||||
|
||||
@@ -25,8 +24,10 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("Services enumerated: %d", len(services)))
|
||||
reported := 0
|
||||
for _, service := range services {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("service inventory : name=%s display=%s state=%s start=%s account=%s pid=%d type=%d path=%s", service.Name, service.DisplayName, service.State, service.StartType, service.Account, service.ProcessID, service.ServiceType, service.BinaryPath))
|
||||
reasons := serviceReasons(service)
|
||||
if len(reasons) == 0 {
|
||||
continue
|
||||
@@ -38,7 +39,6 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if reported == 0 {
|
||||
ctx.Logger.Info("No service configuration stood out from the default heuristics.")
|
||||
}
|
||||
ctx.Logger.Verbose(fmt.Sprintf("Services enumerated: %d", len(services)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func serviceReasons(service win.ServiceInfo) []string {
|
||||
if service.StartType == "Auto" && service.State != "Running" {
|
||||
reasons = append(reasons, "auto-start not running")
|
||||
}
|
||||
return internal.Limit(reasons, 4)
|
||||
return reasons
|
||||
}
|
||||
|
||||
func isUnquotedPathWithSpaces(path string) bool {
|
||||
|
||||
@@ -24,11 +24,13 @@ func (Module) Run(ctx *core.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Logger.Info(fmt.Sprintf("Startup entries enumerated: %d", len(entries)))
|
||||
if len(entries) == 0 {
|
||||
ctx.Logger.Info("No startup entries found in common locations.")
|
||||
return nil
|
||||
}
|
||||
for _, entry := range entries {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("startup inventory : scope=%s location=%s name=%s command=%s", entry.Scope, entry.Location, entry.Name, entry.Command))
|
||||
ctx.Logger.Success(fmt.Sprintf("%s\\%s > %s", entry.Scope, entry.Name, startupReason(entry.Command)))
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s : %s", entry.Location, entry.Command))
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"ferrum/core"
|
||||
"ferrum/internal"
|
||||
win "ferrum/windows/facade"
|
||||
)
|
||||
|
||||
@@ -35,19 +34,24 @@ func (Module) Run(ctx *core.Context) error {
|
||||
}
|
||||
return findings[i].Name < findings[j].Name
|
||||
})
|
||||
ctx.Logger.Info(fmt.Sprintf("Process tokens inspected: %d", len(findings)))
|
||||
reported := 0
|
||||
for _, finding := range findings {
|
||||
if finding.Error != "" {
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s[%d] : token inspection failed: %s", finding.Name, finding.PID, finding.Error))
|
||||
continue
|
||||
}
|
||||
ctx.Logger.Verbose(fmt.Sprintf("token inventory : name=%s pid=%d %s privileges=%s", finding.Name, finding.PID, finding.Process.Label(), strings.Join(finding.Privileges, ",")))
|
||||
if finding.Score == 0 {
|
||||
continue
|
||||
}
|
||||
reported++
|
||||
ctx.Logger.Success(fmt.Sprintf("%s[%d] > %s", finding.Name, finding.PID, strings.Join(finding.Reasons, ", ")))
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s[%d] : %s privileges=%s", finding.Name, finding.PID, finding.Process.Label(), strings.Join(internal.Limit(finding.Privileges, 12), ",")))
|
||||
ctx.Logger.Verbose(fmt.Sprintf("%s[%d] : %s privileges=%s", finding.Name, finding.PID, finding.Process.Label(), strings.Join(finding.Privileges, ",")))
|
||||
}
|
||||
if reported == 0 {
|
||||
ctx.Logger.Info("No accessible process tokens matched the sensitive privilege heuristics.")
|
||||
}
|
||||
ctx.Logger.Verbose(fmt.Sprintf("Processes inspected: %d", len(processes)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -55,6 +59,7 @@ type tokenFinding struct {
|
||||
win.Process
|
||||
Reasons []string
|
||||
Score int
|
||||
Error string
|
||||
}
|
||||
|
||||
func inspect(processes []win.Process) []tokenFinding {
|
||||
@@ -78,6 +83,8 @@ func inspect(processes []win.Process) []tokenFinding {
|
||||
finding.Elevated = token.Elevated
|
||||
finding.Privileges = token.Privileges
|
||||
finding.Reasons, finding.Score = tokenReasons(token)
|
||||
} else {
|
||||
finding.Error = err.Error()
|
||||
}
|
||||
results <- finding
|
||||
}
|
||||
@@ -130,5 +137,5 @@ func tokenReasons(token win.TokenInfo) ([]string, int) {
|
||||
score += points
|
||||
}
|
||||
}
|
||||
return internal.Limit(reasons, 8), score
|
||||
return reasons, score
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
wintypes "ferrum/windows/types"
|
||||
)
|
||||
|
||||
const advancedLimit = 120
|
||||
|
||||
type AdvancedFinding = wintypes.AdvancedFinding
|
||||
|
||||
func EnumerateAdvancedFindings(check string) ([]AdvancedFinding, error) {
|
||||
@@ -84,5 +82,5 @@ func EnumerateAdvancedFindings(check string) ([]AdvancedFinding, error) {
|
||||
findings = genericSurfaceFindings(check)
|
||||
}
|
||||
sortAdvanced(findings)
|
||||
return limitAdvanced(findings), nil
|
||||
return findings, nil
|
||||
}
|
||||
|
||||
@@ -159,9 +159,6 @@ func protocolFindings() []AdvancedFinding {
|
||||
findings = append(findings, AdvancedFinding{Area: "Protocols", Target: root.name + `\` + base + `\` + key, Name: value.Name, Value: value.Value, Severity: "Medium", Reason: "custom URL protocol handler"})
|
||||
}
|
||||
}
|
||||
if len(findings) >= advancedLimit {
|
||||
return findings
|
||||
}
|
||||
}
|
||||
}
|
||||
return findings
|
||||
|
||||
@@ -146,10 +146,3 @@ func sortAdvanced(findings []AdvancedFinding) {
|
||||
return findings[i].Target < findings[j].Target
|
||||
})
|
||||
}
|
||||
|
||||
func limitAdvanced(findings []AdvancedFinding) []AdvancedFinding {
|
||||
if len(findings) <= advancedLimit {
|
||||
return findings
|
||||
}
|
||||
return findings[:advancedLimit]
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
@@ -26,6 +27,7 @@ var (
|
||||
procRegCloseKey = advapi32.NewProc("RegCloseKey")
|
||||
procRegEnumKeyEx = advapi32.NewProc("RegEnumKeyExW")
|
||||
procRegEnumValue = advapi32.NewProc("RegEnumValueW")
|
||||
procRegQueryInfoKey = advapi32.NewProc("RegQueryInfoKeyW")
|
||||
procRegQueryValueEx = advapi32.NewProc("RegQueryValueExW")
|
||||
)
|
||||
|
||||
@@ -36,7 +38,8 @@ type RegistryValue struct {
|
||||
}
|
||||
|
||||
func EnumerateHKCUCLSID() ([]CLSIDEntry, error) {
|
||||
root, err := openKey(hkeyCurrentUser, `Software\Classes\CLSID`)
|
||||
const base = `Software\Classes\CLSID`
|
||||
root, err := openKey(hkeyCurrentUser, base)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -49,19 +52,58 @@ func EnumerateHKCUCLSID() ([]CLSIDEntry, error) {
|
||||
|
||||
entries := make([]CLSIDEntry, 0)
|
||||
for _, clsid := range clsids {
|
||||
for _, kind := range []string{"InprocServer32", "LocalServer32", "TreatAs", "ProgID"} {
|
||||
subkey, err := openKey(root, clsid+`\`+kind)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
value, _ := queryDefaultValue(subkey)
|
||||
procRegCloseKey.Call(subkey)
|
||||
entries = append(entries, CLSIDEntry{CLSID: clsid, Kind: kind, Value: value})
|
||||
}
|
||||
clsidPath := clsid
|
||||
walkCLSIDKey(root, base, clsid, clsidPath, &entries)
|
||||
}
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
func walkCLSIDKey(parent uintptr, base, clsid, relative string, entries *[]CLSIDEntry) {
|
||||
key, err := openKey(parent, relative)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer procRegCloseKey.Call(key)
|
||||
|
||||
path := base + `\` + relative
|
||||
kind := clsidKind(relative)
|
||||
values, err := enumValues(key)
|
||||
if err == nil {
|
||||
for _, value := range values {
|
||||
*entries = append(*entries, CLSIDEntry{
|
||||
CLSID: clsid,
|
||||
Kind: kind,
|
||||
Path: `HKCU\` + path,
|
||||
Name: displayRegistryName(value.Name),
|
||||
Type: value.Type,
|
||||
Value: value.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
subkeyNames, err := enumSubkeys(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, subkey := range subkeyNames {
|
||||
walkCLSIDKey(parent, base, clsid, relative+`\`+subkey, entries)
|
||||
}
|
||||
}
|
||||
|
||||
func clsidKind(relative string) string {
|
||||
parts := strings.Split(relative, `\`)
|
||||
if len(parts) < 2 {
|
||||
return "(CLSID)"
|
||||
}
|
||||
return parts[1]
|
||||
}
|
||||
|
||||
func displayRegistryName(name string) string {
|
||||
if name == "" {
|
||||
return "(Default)"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func EnumerateCLSIDProcMonCandidates() ([]CLSIDProcMonCandidate, error) {
|
||||
root, err := openKey(hkeyLocalMachine, `Software\Classes\CLSID`)
|
||||
if err != nil {
|
||||
@@ -124,9 +166,17 @@ func CloseKey(key uintptr) {
|
||||
}
|
||||
|
||||
func enumSubkeys(key uintptr) ([]string, error) {
|
||||
info, err := queryKeyInfo(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nameCapacity := info.MaxSubKeyLen + 1
|
||||
if nameCapacity < 256 {
|
||||
nameCapacity = 256
|
||||
}
|
||||
keys := []string{}
|
||||
for index := uint32(0); ; index++ {
|
||||
name := make([]uint16, 256)
|
||||
name := make([]uint16, nameCapacity)
|
||||
length := uint32(len(name))
|
||||
ret, _, _ := procRegEnumKeyEx.Call(key, uintptr(index), uintptr(unsafe.Pointer(&name[0])), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
|
||||
if ret == errorNoMoreItems {
|
||||
@@ -183,11 +233,28 @@ func registryValues(parent uintptr, path string) ([]RegistryValue, error) {
|
||||
}
|
||||
defer procRegCloseKey.Call(key)
|
||||
|
||||
return enumValues(key)
|
||||
}
|
||||
|
||||
func enumValues(key uintptr) ([]RegistryValue, error) {
|
||||
info, err := queryKeyInfo(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nameCapacity := info.MaxValueNameLen + 1
|
||||
if nameCapacity < 512 {
|
||||
nameCapacity = 512
|
||||
}
|
||||
dataCapacity := info.MaxValueLen
|
||||
if dataCapacity < 8192 {
|
||||
dataCapacity = 8192
|
||||
}
|
||||
|
||||
values := []RegistryValue{}
|
||||
for index := uint32(0); ; index++ {
|
||||
name := make([]uint16, 512)
|
||||
name := make([]uint16, nameCapacity)
|
||||
nameLen := uint32(len(name))
|
||||
data := make([]byte, 8192)
|
||||
data := make([]byte, dataCapacity)
|
||||
dataLen := uint32(len(data))
|
||||
var typ uint32
|
||||
ret, _, _ := procRegEnumValue.Call(key, uintptr(index), uintptr(unsafe.Pointer(&name[0])), uintptr(unsafe.Pointer(&nameLen)), 0, uintptr(unsafe.Pointer(&typ)), uintptr(unsafe.Pointer(&data[0])), uintptr(unsafe.Pointer(&dataLen)))
|
||||
@@ -226,3 +293,35 @@ func registryDataString(data []byte, typ uint32) string {
|
||||
}
|
||||
return fmt.Sprintf("%x", data)
|
||||
}
|
||||
|
||||
type keyInfo struct {
|
||||
MaxSubKeyLen uint32
|
||||
MaxValueNameLen uint32
|
||||
MaxValueLen uint32
|
||||
}
|
||||
|
||||
func queryKeyInfo(key uintptr) (keyInfo, error) {
|
||||
var subKeys uint32
|
||||
var maxSubKeyLen uint32
|
||||
var values uint32
|
||||
var maxValueNameLen uint32
|
||||
var maxValueLen uint32
|
||||
ret, _, _ := procRegQueryInfoKey.Call(
|
||||
key,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&subKeys)),
|
||||
uintptr(unsafe.Pointer(&maxSubKeyLen)),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&values)),
|
||||
uintptr(unsafe.Pointer(&maxValueNameLen)),
|
||||
uintptr(unsafe.Pointer(&maxValueLen)),
|
||||
0,
|
||||
0,
|
||||
)
|
||||
if ret != 0 {
|
||||
return keyInfo{}, syscall.Errno(ret)
|
||||
}
|
||||
return keyInfo{MaxSubKeyLen: maxSubKeyLen, MaxValueNameLen: maxValueNameLen, MaxValueLen: maxValueLen}, nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package registry
|
||||
type CLSIDEntry struct {
|
||||
CLSID string
|
||||
Kind string
|
||||
Path string
|
||||
Name string
|
||||
Type uint32
|
||||
Value string
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user