-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain_windows.go
134 lines (116 loc) · 3.34 KB
/
main_windows.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package main
import (
"fmt"
"path/filepath"
"strings"
"github.com/Microsoft/go-winio"
winacl "github.com/kgoins/go-winacl/pkg"
"golang.org/x/sys/windows"
"www.velocidex.com/golang/go-pe"
)
// Report contains the parsed import and exports of the PE
type Report struct {
Name string `json:"Name"`
Path string `json:"Path"`
Dir string `json:"Dir"`
Type string `json:"Type"`
ImpHash string `json:"ImpHash"`
Exports []string `json:"Exports"`
Imports []PEFunction `json:"Imports"`
Forwards []PEFunction `json:"Forwards"`
DACL DACL `json:"DACL"`
GUIDAge string `json:",omitempty"`
PDB string `json:",omitempty"`
Sections []*pe.Section `json:",omitempty"`
}
type DACL struct {
Owner string `json:"Owner"`
Group string `json:"Group"`
Aces []ReadableAce `json:"Aces"`
}
type ReadableAce struct {
Principal string `json:"Principal"`
Rights []string `json:"Rights"`
}
func populatePEReport(report *Report, peFile *pe.PEFile) error {
report.ImpHash = peFile.ImpHash()
report.Imports = genPEFunctions(peFile.Imports())
report.Forwards = genPEFunctions(patchForwards(peFile.Forwards()))
report.Exports = patchExports(peFile.Exports())
report.Dir = filepath.Dir(report.Path)
if verbose {
report.Sections = peFile.Sections
report.PDB = peFile.PDB
}
dacl, err := pullDACL(report.Path)
if err != nil {
return err
}
report.DACL = dacl
return nil
}
func pullDACL(path string) (DACL, error) {
dacl := DACL{}
sd, err := securityDescriptorFor(path)
if err != nil {
return dacl, err
}
dacl.Owner = sidResolve(sd.Owner)
dacl.Group = sidResolve(sd.Group)
for _, ace := range sd.DACL.Aces {
dacl.Aces = append(dacl.Aces, newReadableAce(ace))
}
return dacl, err
}
func securityDescriptorFor(path string) (sd winacl.NtSecurityDescriptor, err error) {
winSD, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION)
if !winSD.IsValid() {
return sd, fmt.Errorf("invalid security descriptor %s", err)
}
// convert windows.SD into SDDL, then back into an SD
// represented as a byte slice, so go-winacl can parse it
sdBytes, err := winio.SddlToSecurityDescriptor(winSD.String())
if err != nil {
return
}
sd, err = winacl.NewNtSecurityDescriptor(sdBytes)
return
}
func newReadableAce(ace winacl.ACE) ReadableAce {
var rAce ReadableAce
perms := ace.AccessMask.String()
rAce.Rights = strings.Split(perms, " ")
switch ace.ObjectAce.(type) {
case winacl.BasicAce:
rAce.Principal = sidResolve(ace.ObjectAce.GetPrincipal())
case winacl.AdvancedAce:
aa := ace.ObjectAce.(winacl.AdvancedAce)
sid := aa.GetPrincipal()
rAce.Principal = sidResolve(sid)
}
return rAce
}
func sidResolve(sid winacl.SID) string {
res := sid.Resolve()
if strings.HasPrefix(res, "S-1-") {
// failed to resolve
winSID, err := windows.StringToSid(sid.String())
if err != nil {
return res
}
user, domain, _, err := winSID.LookupAccount("")
if err != nil {
return res
}
return fmt.Sprintf(`%s\%s`, domain, user)
}
return res
}
func handleDirPerms(report *Report) error {
dacl, err := pullDACL(report.Path)
if err != nil {
return err
}
report.DACL = dacl
return nil
}