func()

in auditbeat/module/file_integrity/exeobjparser.go [57:258]


func (fields exeObjParser) Parse(dst mapstr.M, path string) (err error) {
	if dst == nil {
		return errors.New("cannot use nil dst for file parser")
	}
	defer func() {
		switch r := recover().(type) {
		case nil:
		case error:
			// This will catch runtime.Error panics differentially.
			// These are the most likely panics during the analysis.
			err = fmt.Errorf("error panic during executable parser analysis of %s: %w", path, r)
		default:
			err = fmt.Errorf("panic during executable parser analysis of %s: %v", path, r)
		}
	}()

	f, err := toutoumomoma.Open(path)
	if err != nil {
		if err == toutoumomoma.ErrUnknownFormat {
			return nil
		}
		return err
	}
	defer f.Close()

	typ := strings.ToLower(f.Type())
	if typ == "mach-o" {
		typ = "macho"
	}

	var details mapstr.M
	d, err := dst.GetValue(typ)
	if err != nil {
		if err != mapstr.ErrKeyNotFound {
			return fmt.Errorf("invalid destination key: %q not found in map", typ)
		}
		details = make(mapstr.M)
		dst[typ] = details
	} else {
		switch d := d.(type) {
		case mapstr.M:
			details = d
		default:
			return fmt.Errorf("cannot write %s details to %T", typ, d)
		}
	}

	if all := wantFields(fields, "file."+typ+".sections"); all || wantFields(fields,
		"file."+typ+".sections.name",
		"file."+typ+".sections.virtual_size",
		"file."+typ+".sections.physical_size",
		"file."+typ+".sections.entropy",
		"file."+typ+".sections.var_entropy",
	) {
		sections, err := f.Sections()
		if err != nil {
			return err
		}
		var (
			name       *string
			size       *uint64
			fileSize   *uint64
			entropy    *float64
			varEntropy *float64

			wantName, wantSize, wantFileSize, wantEntropy, wantVariance bool
		)
		if !all {
			wantName = wantFields(fields, "file."+typ+".sections.name")
			wantSize = wantFields(fields, "file."+typ+".sections.virtual_size")
			wantFileSize = wantFields(fields, "file."+typ+".sections.physical_size")
			wantEntropy = wantFields(fields, "file."+typ+".sections.entropy")
			wantVariance = wantFields(fields, "file."+typ+".sections.var_entropy")
		}
		if len(sections) != 0 {
			// TODO: Replace this []section with a []mapstr.M if additional
			// section attributes are added from another parser.
			stats := make([]objSection, len(sections))
			for i, s := range sections {
				s := s
				if all {
					name = &s.Name
					size = &s.Size
					entropy = &s.Entropy
					varEntropy = &s.VarEntropy
				} else {
					if wantName {
						name = &s.Name
					}
					if wantSize {
						size = &s.Size
					}
					if wantFileSize {
						fileSize = &s.FileSize
					}
					if wantEntropy {
						entropy = &s.Entropy
					}
					if wantVariance {
						varEntropy = &s.VarEntropy
					}
				}
				stats[i] = objSection{
					Name:       name,
					Size:       size,
					FileSize:   fileSize,
					Entropy:    entropy,
					VarEntropy: varEntropy,
				}
			}
			details["sections"] = stats
		}
	}

	if wantFields(fields,
		"file.pe.imphash",
		"file.macho.symhash",
		"file."+typ+".import_hash",
		"file."+typ+".imports",
		"file."+typ+".imports_names_entropy",
		"file."+typ+".imports_names_var_entropy",
	) {
		h, symbols, err := f.ImportHash()
		if err != nil {
			return err
		}
		imphash := Digest(h)
		if wantFields(fields, "file."+typ+".import_hash") {
			details["import_hash"] = imphash
		}
		switch typ {
		case "pe":
			if wantFields(fields, "file.pe.imphash") {
				details["imphash"] = imphash
			}
		case "macho":
			if wantFields(fields, "file.macho.symhash") {
				details["symhash"] = imphash
			}
		}
		if len(symbols) != 0 {
			if wantFields(fields, "file."+typ+".imports") {
				details["imports"] = symbols
			}
			wantEntropy := wantFields(fields, "file."+typ+".imports_names_entropy")
			wantVariance := wantFields(fields, "file."+typ+".imports_names_var_entropy")
			if wantEntropy || wantVariance {
				entropy, varEntropy := toutoumomoma.NameEntropy(symbols)
				if wantEntropy {
					details["imports_names_entropy"] = entropy
				}
				if wantVariance {
					details["imports_names_var_entropy"] = varEntropy
				}
			}
		}
	}

	if wantFields(fields,
		"file."+typ+".go_import_hash",
		"file."+typ+".go_imports",
		"file."+typ+".go_imports_names_entropy",
		"file."+typ+".go_imports_names_var_entropy",
	) {
		h, symbols, err := f.GoSymbolHash(false)
		if err != nil {
			if err == toutoumomoma.ErrNotGoExecutable {
				return nil
			}
			return err
		}
		if wantFields(fields, "file."+typ+".go_import_hash") {
			details["go_import_hash"] = Digest(h)
		}
		if len(symbols) != 0 {
			if wantFields(fields, "file."+typ+".go_imports") {
				details["go_imports"] = symbols
			}
			wantEntropy := wantFields(fields, "file."+typ+".go_imports_names_entropy")
			wantVariance := wantFields(fields, "file."+typ+".go_imports_names_variance")
			if wantEntropy || wantVariance {
				entropy, varEntropy := toutoumomoma.NameEntropy(symbols)
				if wantEntropy {
					details["go_imports_names_entropy"] = entropy
				}
				if wantVariance {
					details["go_imports_names_var_entropy"] = varEntropy
				}
			}
		}
	}

	if wantFields(fields, "file."+typ+".go_stripped") {
		stripped, err := f.Stripped()
		if err != nil {
			return err
		}
		details["go_stripped"] = stripped
	}

	return nil
}