├── LICENSE ├── README.md ├── go.mod ├── go.sum └── win32 ├── advapi32 ├── advapi32.go ├── advapi_test.go ├── exports.go ├── header.go └── helpers.go ├── dbghelp ├── dbghelp.go ├── exports.go ├── header.go └── test │ └── dbghelp_test.go ├── errors.go ├── fltlib ├── exports.go ├── fltlib.go └── headers.go ├── helpers.go ├── kernel32 ├── exports.go ├── header.go ├── helpers.go ├── kernel32.go └── test │ └── kernel32_test.go ├── net.go ├── ntdll ├── exports.go ├── headers.go └── ntdll.go ├── structs.go ├── user32 ├── exports.go ├── test │ └── user32_test.go └── user32.go ├── wevtapi ├── exports.go ├── headers.go ├── helpers.go ├── wevtapi.go └── winevtapi_test.go ├── win32_test.go ├── winbase.go ├── winbase32.go └── winbase64.go /README.md: -------------------------------------------------------------------------------- 1 | # golang-win32 2 | Golang wrappers functions to call Windows APIs 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/0xrawsec/golang-win32 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/0xrawsec/golang-utils v1.3.0 7 | golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 // indirect 8 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect 9 | golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 // indirect 10 | golang.org/x/text v0.3.2 // indirect 11 | golang.org/x/tools v0.0.0-20190625160430-252024b82959 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/0xrawsec/golang-utils v1.1.0 h1:opQAwRONEfxOOl4nxhpPkXiTYgzAw0/wFATAffNjdII= 2 | github.com/0xrawsec/golang-utils v1.1.0/go.mod h1:DADTtCFY10qXjWmUVhhJqQIZdSweaHH4soYUDEi8mj0= 3 | github.com/0xrawsec/golang-utils v1.1.3 h1:ESJhyY4aGuiP4hmDcDNjoL/cc7SWDZVfgg4dEON9eIc= 4 | github.com/0xrawsec/golang-utils v1.1.3/go.mod h1:DADTtCFY10qXjWmUVhhJqQIZdSweaHH4soYUDEi8mj0= 5 | github.com/0xrawsec/golang-utils v1.1.8 h1:9TzAKzC7+V2IXaV/3Y1aXiUFHeShL3BXcfL6BheAEH0= 6 | github.com/0xrawsec/golang-utils v1.1.8/go.mod h1:DADTtCFY10qXjWmUVhhJqQIZdSweaHH4soYUDEi8mj0= 7 | github.com/0xrawsec/golang-utils v1.3.0 h1:fMgwKu5M2PXFwEfwN9B2T1bfg7LPCaV9fL6Xs/nf2Ps= 8 | github.com/0xrawsec/golang-utils v1.3.0/go.mod h1:DADTtCFY10qXjWmUVhhJqQIZdSweaHH4soYUDEi8mj0= 9 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 10 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 11 | github.com/pkg/sftp v1.10.0/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk= 12 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 13 | golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 14 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 15 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 16 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 17 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 18 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 19 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 20 | golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 21 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 22 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 23 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 24 | golang.org/x/tools v0.0.0-20190320215829-36c10c0a621f/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 25 | golang.org/x/tools v0.0.0-20190625160430-252024b82959/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 26 | -------------------------------------------------------------------------------- /win32/advapi32/advapi32.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package advapi32 5 | 6 | import ( 7 | "encoding/binary" 8 | "fmt" 9 | "regexp" 10 | "strconv" 11 | "strings" 12 | "syscall" 13 | "unsafe" 14 | 15 | "github.com/0xrawsec/golang-utils/encoding" 16 | ) 17 | 18 | var ( 19 | guidRE = regexp.MustCompile(`\{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\}`) 20 | ) 21 | 22 | func MustGUIDFromString(sguid string) (guid *GUID) { 23 | var err error 24 | if guid, err = GUIDFromString(sguid); err != nil { 25 | panic(err) 26 | } 27 | return 28 | } 29 | 30 | func GUIDFromString(guid string) (*GUID, error) { 31 | g := GUID{} 32 | guid = strings.ToUpper(guid) 33 | if !guidRE.MatchString(guid) { 34 | return nil, fmt.Errorf("Bad GUID format") 35 | } 36 | guid = strings.Trim(guid, "{}") 37 | sp := strings.Split(guid, "-") 38 | c, _ := strconv.ParseUint(sp[0], 16, 32) 39 | g.Data1 = uint32(c) 40 | c, _ = strconv.ParseUint(sp[1], 16, 16) 41 | g.Data2 = uint16(c) 42 | c, _ = strconv.ParseUint(sp[2], 16, 16) 43 | g.Data3 = uint16(c) 44 | i64, _ := strconv.ParseUint(fmt.Sprintf("%s%s", sp[3], sp[4]), 16, 64) 45 | buf, err := encoding.Marshal(&i64, binary.BigEndian) 46 | if err != nil { 47 | return nil, err 48 | } 49 | copy(g.Data4[:], buf) 50 | 51 | return &g, nil 52 | } 53 | 54 | /* 55 | StartTraceW API wrapper generated from prototype 56 | EXTERN_C ULONG WMIAPI StartTraceW ( 57 | PTRACEHANDLE TraceHandle, 58 | LPCWSTR InstanceName, 59 | PEVENT_TRACE_PROPERTIES Properties); 60 | */ 61 | func StartTrace(traceHandle *uintptr, 62 | instanceName *uint16, 63 | properties *EventTraceProperties) error { 64 | r1, _, _ := startTraceW.Call( 65 | uintptr(unsafe.Pointer(traceHandle)), 66 | uintptr(unsafe.Pointer(instanceName)), 67 | uintptr(unsafe.Pointer(properties))) 68 | if r1 == 0 { 69 | return nil 70 | } 71 | return syscall.Errno(r1) 72 | } 73 | 74 | /* 75 | EnableTraceEx2 API wrapper generated from prototype 76 | EXTERN_C ULONG WMIAPI EnableTraceEx2 ( 77 | TRACEHANDLE TraceHandle, 78 | LPCGUID ProviderId, 79 | ULONG ControlCode, 80 | UCHAR Level, 81 | ULONGLONG MatchAnyKeyword, 82 | ULONGLONG MatchAllKeyword, 83 | ULONG Timeout, 84 | PENABLE_TRACE_PARAMETERS EnableParameters); 85 | */ 86 | func EnableTraceEx2(traceHandle uintptr, 87 | providerId *GUID, 88 | controlCode uint32, 89 | level uint8, 90 | matchAnyKeyword uint64, 91 | matchAllKeyword uint64, 92 | timeout uint32, 93 | enableParameters *EnableTraceParameters) error { 94 | r1, _, _ := enableTraceEx2.Call( 95 | uintptr(traceHandle), 96 | uintptr(unsafe.Pointer(providerId)), 97 | uintptr(controlCode), 98 | uintptr(level), 99 | uintptr(matchAnyKeyword), 100 | uintptr(matchAllKeyword), 101 | uintptr(timeout), 102 | uintptr(unsafe.Pointer(enableParameters))) 103 | if r1 == 0 { 104 | return nil 105 | } 106 | return syscall.Errno(r1) 107 | } 108 | 109 | /* 110 | ProcessTrace API wrapper generated from prototype 111 | EXTERN_C ULONG WMIAPI ProcessTrace ( 112 | PTRACEHANDLE HandleArray, 113 | ULONG HandleCount, 114 | LPFILETIME StartTime, 115 | LPFILETIME EndTime); 116 | */ 117 | func ProcessTrace(handleArray *uint64, 118 | handleCount uint32, 119 | startTime *FileTime, 120 | endTime *FileTime) error { 121 | r1, _, _ := processTrace.Call( 122 | uintptr(unsafe.Pointer(handleArray)), 123 | uintptr(handleCount), 124 | uintptr(unsafe.Pointer(startTime)), 125 | uintptr(unsafe.Pointer(endTime))) 126 | if r1 == 0 { 127 | return nil 128 | } 129 | return syscall.Errno(r1) 130 | } 131 | 132 | /* 133 | OpenTraceW API wrapper generated from prototype 134 | EXTERN_C TRACEHANDLE WMIAPI OpenTraceW ( 135 | PEVENT_TRACE_LOGFILEW Logfile); 136 | */ 137 | func OpenTrace(logfile *EventTraceLogfile) (uint64, error) { 138 | r1, _, err := openTraceW.Call( 139 | uintptr(unsafe.Pointer(logfile))) 140 | if err.(syscall.Errno) == 0 { 141 | return uint64(r1), nil 142 | } 143 | return uint64(r1), err 144 | } 145 | 146 | /* 147 | ControlTraceW API wrapper generated from prototype 148 | EXTERN_C ULONG WMIAPI ControlTraceW ( 149 | TRACEHANDLE TraceHandle, 150 | LPCWSTR InstanceName, 151 | PEVENT_TRACE_PROPERTIES Properties, 152 | ULONG ControlCode); 153 | */ 154 | func ControlTrace(traceHandle uintptr, 155 | instanceName *uint16, 156 | properties *EventTraceProperties, 157 | controlCode uint32) (uint32, error) { 158 | r1, _, err := controlTraceW.Call( 159 | uintptr(traceHandle), 160 | uintptr(unsafe.Pointer(instanceName)), 161 | uintptr(unsafe.Pointer(properties)), 162 | uintptr(controlCode)) 163 | if err.(syscall.Errno) == 0 { 164 | return uint32(r1), nil 165 | } 166 | return uint32(r1), err 167 | } 168 | 169 | /* 170 | CloseTrace API wrapper generated from prototype 171 | EXTERN_C ULONG WMIAPI CloseTrace ( 172 | TRACEHANDLE TraceHandle); 173 | */ 174 | func CloseTrace(traceHandle uint64) (uint32, error) { 175 | r1, _, err := closeTrace.Call( 176 | uintptr(traceHandle)) 177 | if err.(syscall.Errno) == 0 { 178 | return uint32(r1), nil 179 | } 180 | return uint32(r1), err 181 | } 182 | 183 | /* 184 | OpenSCManagerW API wrapper generated from prototype 185 | WINADVAPI SC_HANDLE WINAPI OpenSCManagerW( 186 | LPCWSTR lpMachineName, 187 | LPCWSTR lpDatabaseName, 188 | DWORD dwDesiredAccess); 189 | */ 190 | func OpenSCManagerW(lpMachineName *uint16, 191 | lpDatabaseName *uint16, 192 | dwDesiredAccess uint32) (syscall.Handle, error) { 193 | r1, _, err := openSCManagerW.Call( 194 | uintptr(unsafe.Pointer(lpMachineName)), 195 | uintptr(unsafe.Pointer(lpDatabaseName)), 196 | uintptr(dwDesiredAccess)) 197 | if err.(syscall.Errno) == 0 { 198 | return syscall.Handle(r1), nil 199 | } 200 | return syscall.Handle(r1), err 201 | } 202 | 203 | /* 204 | EnumServicesStatusExW API wrapper generated from prototype 205 | WINADVAPI WINBOOL WINAPI EnumServicesStatusExW( 206 | SC_HANDLE hSCManager, 207 | SC_ENUM_TYPE InfoLevel, 208 | DWORD dwServiceType, 209 | DWORD dwServiceState, 210 | LPBYTE lpServices, 211 | DWORD cbBufSize, 212 | LPDWORD pcbBytesNeeded, 213 | LPDWORD lpServicesReturned, 214 | LPDWORD lpResumeHandle, 215 | LPCWSTR pszGroupName); 216 | */ 217 | func EnumServicesStatusEx(hSCManager syscall.Handle, 218 | infoLevel ScEnumType, 219 | dwServiceType uint32, 220 | dwServiceState uint32, 221 | lpServices *byte, 222 | cbBufSize uint32, 223 | pcbBytesNeeded *uint32, 224 | lpServicesReturned *uint32, 225 | lpResumeHandle *uint32, 226 | pszGroupName *uint16) error { 227 | r1, _, err := enumServicesStatusExW.Call( 228 | uintptr(hSCManager), 229 | uintptr(infoLevel), 230 | uintptr(dwServiceType), 231 | uintptr(dwServiceState), 232 | uintptr(unsafe.Pointer(lpServices)), 233 | uintptr(cbBufSize), 234 | uintptr(unsafe.Pointer(pcbBytesNeeded)), 235 | uintptr(unsafe.Pointer(lpServicesReturned)), 236 | uintptr(unsafe.Pointer(lpResumeHandle)), 237 | uintptr(unsafe.Pointer(pszGroupName))) 238 | if r1 == 0 { 239 | return err 240 | } 241 | return nil 242 | } 243 | 244 | /* 245 | CloseServiceHandle API wrapper generated from prototype 246 | WINADVAPI WINBOOL WINAPI CloseServiceHandle( 247 | SC_HANDLE hSCObject); 248 | */ 249 | func CloseServiceHandle(hSCObject syscall.Handle) error { 250 | r1, _, err := closeServiceHandle.Call( 251 | uintptr(hSCObject)) 252 | if r1 == 0 { 253 | return err 254 | } 255 | return nil 256 | } 257 | 258 | ///////////////////////////////////////////////////////////////////// 259 | 260 | /* 261 | RegOpenKeyExW API wrapper generated from prototype 262 | WINADVAPI LONG WINAPI RegOpenKeyExW( 263 | HKEY hKey, 264 | LPCWSTR lpSubKey, 265 | DWORD ulOptions, 266 | REGSAM samDesired, 267 | PHKEY phkResult); 268 | */ 269 | func RegOpenKeyEx(hKey syscall.Handle, 270 | lpSubKey *uint16, 271 | ulOptions uint32, 272 | samDesired uint32, 273 | phkResult *syscall.Handle) error { 274 | r1, _, _ := regOpenKeyExW.Call( 275 | uintptr(hKey), 276 | uintptr(unsafe.Pointer(lpSubKey)), 277 | uintptr(ulOptions), 278 | uintptr(samDesired), 279 | uintptr(unsafe.Pointer(phkResult))) 280 | if r1 == 0 { 281 | return nil 282 | } 283 | return syscall.Errno(r1) 284 | } 285 | 286 | /* 287 | RegEnumKeyExW API wrapper generated from prototype 288 | WINADVAPI LONG WINAPI RegEnumKeyExW( 289 | HKEY hKey, 290 | DWORD dwIndex, 291 | LPWSTR lpName, 292 | LPDWORD lpcchName, 293 | LPDWORD lpReserved, 294 | LPWSTR lpClass, 295 | LPDWORD lpcchClass, 296 | PFILETIME lpftLastWriteTime); 297 | */ 298 | func RegEnumKeyExW( 299 | hKey syscall.Handle, 300 | dwIndex uint32, 301 | lpName *uint16, 302 | lpcchName *uint32, 303 | lpReserved *uint32, 304 | lpClass *uint16, 305 | lpcchClass *uint32, 306 | lpftLastWriteTime *FileTime) error { 307 | r1, _, _ := regEnumKeyExW.Call( 308 | uintptr(hKey), 309 | uintptr(dwIndex), 310 | uintptr(unsafe.Pointer(lpName)), 311 | uintptr(unsafe.Pointer(lpcchName)), 312 | uintptr(unsafe.Pointer(lpReserved)), 313 | uintptr(unsafe.Pointer(lpClass)), 314 | uintptr(unsafe.Pointer(lpcchClass)), 315 | uintptr(unsafe.Pointer(lpftLastWriteTime))) 316 | if r1 == 0 { 317 | return nil 318 | } 319 | return syscall.Errno(r1) 320 | } 321 | 322 | /* 323 | RegEnumValueW API wrapper generated from prototype 324 | WINADVAPI LONG WINAPI RegEnumValueW( 325 | HKEY hKey, 326 | DWORD dwIndex, 327 | LPWSTR lpValueName, 328 | LPDWORD lpcchValueName, 329 | LPDWORD lpReserved, 330 | LPDWORD lpType, 331 | LPBYTE lpData, 332 | LPDWORD lpcbData); 333 | */ 334 | func RegEnumValueW(hKey syscall.Handle, 335 | dwIndex uint32, 336 | lpValueName *uint16, 337 | lpcchValueName *uint32, 338 | lpReserved *uint32, 339 | lpType *uint32, 340 | lpData *byte, 341 | lpcbData *uint32) error { 342 | r1, _, _ := regEnumValueW.Call( 343 | uintptr(hKey), 344 | uintptr(dwIndex), 345 | uintptr(unsafe.Pointer(lpValueName)), 346 | uintptr(unsafe.Pointer(lpcchValueName)), 347 | uintptr(unsafe.Pointer(lpReserved)), 348 | uintptr(unsafe.Pointer(lpType)), 349 | uintptr(unsafe.Pointer(lpData)), 350 | uintptr(unsafe.Pointer(lpcbData))) 351 | if r1 == 0 { 352 | return nil 353 | } 354 | return syscall.Errno(r1) 355 | } 356 | 357 | /* 358 | RegQueryValueExW API wrapper generated from prototype 359 | WINADVAPI LONG WINAPI RegQueryValueExW( 360 | HKEY hKey, 361 | LPCWSTR lpValueName, 362 | LPDWORD lpReserved, 363 | LPDWORD lpType, 364 | LPBYTE lpData, 365 | LPDWORD lpcbData); 366 | */ 367 | func RegQueryValueEx(hKey syscall.Handle, 368 | lpValueName *uint16, 369 | lpReserved *uint32, 370 | lpType *uint32, 371 | lpData *byte, 372 | lpcbData *uint32) error { 373 | r1, _, _ := regQueryValueExW.Call( 374 | uintptr(hKey), 375 | uintptr(unsafe.Pointer(lpValueName)), 376 | uintptr(unsafe.Pointer(lpReserved)), 377 | uintptr(unsafe.Pointer(lpType)), 378 | uintptr(unsafe.Pointer(lpData)), 379 | uintptr(unsafe.Pointer(lpcbData))) 380 | if r1 == 0 { 381 | return nil 382 | } 383 | return syscall.Errno(r1) 384 | } 385 | 386 | /* 387 | RegCloseKey API wrapper generated from prototype 388 | WINADVAPI LONG WINAPI RegCloseKey( 389 | HKEY hKey); 390 | */ 391 | func RegCloseKey(hKey syscall.Handle) error { 392 | r1, _, _ := regCloseKey.Call( 393 | uintptr(hKey)) 394 | if r1 == 0 { 395 | return nil 396 | } 397 | return syscall.Errno(r1) 398 | } 399 | -------------------------------------------------------------------------------- /win32/advapi32/advapi_test.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package advapi32 5 | 6 | import ( 7 | "bytes" 8 | "encoding/csv" 9 | "math/rand" 10 | "os/exec" 11 | "strconv" 12 | "syscall" 13 | "testing" 14 | "time" 15 | "unsafe" 16 | 17 | "github.com/0xrawsec/golang-utils/log" 18 | ) 19 | 20 | var ( 21 | DNSGuid, _ = GUIDFromString("{1C95126E-7EEA-49A9-A3FE-A378B03DDB4D}") 22 | SysmonGuid, _ = GUIDFromString("{5770385F-C22A-43E0-BF4C-06F5698FFBD9}") 23 | COMGuid, _ = GUIDFromString("{D4263C98-310C-4D97-BA39-B55354F08584}") 24 | KernelMemoryGUID, _ = GUIDFromString("{D1D93EF7-E1F2-4F45-9943-03D245FE6C00}") 25 | SecurityAuditing, _ = GUIDFromString("{54849625-5478-4994-A5BA-3E3B0328C30D}") 26 | URLMon, _ = GUIDFromString("{245F975D-909D-49ED-B8F9-9A75691D6B6B}") 27 | Microsoft_Windows_Ntfs, _ = GUIDFromString("{3FF37A1C-A68D-4D6E-8C9B-F79E8B16C482}") 28 | Ntfs, _ = GUIDFromString("{DD70BC80-EF44-421B-8AC3-CD31DA613A4E}") 29 | ) 30 | 31 | func MakeSessionProperty(sessionName string) (*EventTraceProperties, uint32) { 32 | size := ((len(sessionName) + 1) * 2) + int(unsafe.Sizeof(EventTraceProperties{})) 33 | s := make([]byte, size) 34 | return (*EventTraceProperties)(unsafe.Pointer(&s[0])), uint32(size) 35 | } 36 | 37 | func NewRealTimeSessionProperty(logSessionName string) *EventTraceProperties { 38 | sessionProperties, size := MakeSessionProperty(logSessionName) 39 | 40 | // Necessary fields for SessionProperties struct 41 | sessionProperties.Wnode.BufferSize = size 42 | sessionProperties.Wnode.Guid = GUID{} // To set 43 | sessionProperties.Wnode.ClientContext = 1 // QPC 44 | sessionProperties.Wnode.Flags = WNODE_FLAG_ALL_DATA 45 | sessionProperties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE 46 | sessionProperties.LogFileNameOffset = 0 47 | sessionProperties.LoggerNameOffset = uint32(unsafe.Sizeof(EventTraceProperties{})) 48 | 49 | return sessionProperties 50 | } 51 | 52 | func checkSessionRunning(sname string) bool { 53 | cmd := exec.Command("logman", "query", sname, "-ets") 54 | out, err := cmd.CombinedOutput() 55 | if err != nil { 56 | log.Errorf("Failed to run command line: %s", err) 57 | return false 58 | } 59 | return bytes.Index(out, []byte(sname)) != 1 60 | } 61 | 62 | func TestGuid(t *testing.T) { 63 | dnsClientGuid := "{1C95126E-7EEA-49A9-A3FE-A378B03DDB4D}" 64 | guid, err := GUIDFromString(dnsClientGuid) 65 | if err != nil { 66 | t.Errorf("Failed to parse guid: %s", err) 67 | } 68 | if guid.String() != dnsClientGuid { 69 | t.Errorf("%s != %s (original)", guid, dnsClientGuid) 70 | } 71 | t.Log(guid) 72 | } 73 | 74 | func TestStartTrace(t *testing.T) { 75 | var sessionHandle uintptr 76 | logSessionName := "TestStartTraceGolangPOC" 77 | 78 | sessionProperties := NewRealTimeSessionProperty(logSessionName) 79 | 80 | err := StartTrace(&sessionHandle, syscall.StringToUTF16Ptr(logSessionName), sessionProperties) 81 | 82 | if err != nil { 83 | t.Errorf("Failed to create trace: %s", err) 84 | } 85 | defer ControlTrace(sessionHandle, nil, sessionProperties, EVENT_TRACE_CONTROL_STOP) 86 | if !checkSessionRunning(logSessionName) { 87 | t.Errorf("Session is not running") 88 | } 89 | } 90 | 91 | func BuffCB(e *EventTraceLogfile) uintptr { 92 | //log.Infof("BufferCallback") 93 | // We must return True otherwise the trace stops 94 | return 1 95 | } 96 | 97 | func randomSvcPid() (pid uint32, service string) { 98 | c := exec.Command("tasklist", "/SVC", "/FO", "CSV", "/NH") 99 | 100 | out, err := c.Output() 101 | if err != nil { 102 | log.Errorf("Failed to run tasklist: %s", err) 103 | return 0, "" 104 | } 105 | 106 | r := csv.NewReader(bytes.NewBuffer(out)) 107 | lines, err := r.ReadAll() 108 | if err != nil { 109 | log.Errorf("Failed to read tasklist output") 110 | } 111 | rand.Seed(time.Now().Unix()) 112 | for { 113 | i := rand.Int() % len(lines) 114 | rec := lines[i] 115 | // Expect three fields 116 | if len(rec) == 3 { 117 | svc := rec[2] 118 | if svc != "N/A" { 119 | pid64, err := strconv.ParseUint(rec[1], 10, 32) 120 | if err != nil { 121 | log.Errorf("Failed to parse pid \"%s\"", rec[1]) 122 | } 123 | return uint32(pid64), svc 124 | } 125 | } 126 | } 127 | 128 | log.Errorf("Unexpected tasklist output: %s", out) 129 | return 0, "" 130 | } 131 | 132 | var ( 133 | // moved outside test function to have an accurate timing 134 | pid, expSvc = randomSvcPid() 135 | ) 136 | 137 | func TestServiceEnumerator(t *testing.T) { 138 | 139 | if pid == 0 { 140 | t.Errorf("Failed to find a SVC to test") 141 | t.FailNow() 142 | } 143 | 144 | svc, err := ServiceWin32NamesByPid(pid) 145 | if err != nil { 146 | t.Errorf("Failed to get ServiceNameByPID: %s", err) 147 | t.FailNow() 148 | } 149 | 150 | if expSvc != svc { 151 | t.Fail() 152 | } 153 | 154 | nasvc, err := ServiceWin32NamesByPid(0xffffffff) 155 | if nasvc != "N/A" { 156 | t.Fail() 157 | } 158 | 159 | t.Logf("Expected: %s VS Found: %s", expSvc, svc) 160 | t.Logf("Non existing PID returned: %s", nasvc) 161 | } 162 | 163 | func TestRegGetValueFromString(t *testing.T) { 164 | //reg := "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModel\\StateRepository\\Cache\\ApplicationExtension\\Data\\1da\\Category" 165 | //reg := "HKLM\\SOFTWARE\\Test" 166 | //reg := "HKLM\\SOFTWARE\\Binary" 167 | reg := "HKLM\\SYSTEM\\CurrentControlSet\\Control\\EarlyStartServices" 168 | data, dtype, err := RegGetValueFromString(reg) 169 | if err != nil { 170 | t.Error(err) 171 | } 172 | t.Logf("Data type: %d", dtype) 173 | t.Logf("Data: %q", data) 174 | if p, err := ParseRegValue(data, dtype); err != nil { 175 | t.Error(err) 176 | } else { 177 | t.Logf("Parsed Data: %v", p) 178 | } 179 | } 180 | 181 | func parseRegValueOrPanic(path string) interface{} { 182 | data, dtype, err := RegGetValueFromString(path) 183 | if err != nil { 184 | panic(err) 185 | } 186 | 187 | if p, err := ParseRegValue(data, dtype); err != nil { 188 | panic(err) 189 | } else { 190 | return p 191 | } 192 | } 193 | 194 | func TestParseRegValue(t *testing.T) { 195 | bfRoot := `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\` 196 | keys := []string{ 197 | `HKLM\SYSTEM\CurrentControlSet\Control\EarlyStartServices`, 198 | bfRoot + `BuildBranch`, 199 | bfRoot + `BaseBuildRevisionNumber`, 200 | bfRoot + `BuildLabEx`, 201 | bfRoot + `DigitalProductId`, 202 | bfRoot + `ProductName`, 203 | bfRoot + `EditionSubVersion`, 204 | } 205 | 206 | for _, key := range keys { 207 | t.Logf("%s: %v", key, parseRegValueOrPanic(key)) 208 | } 209 | } 210 | 211 | func TestRegGetValueSizeFromString(t *testing.T) { 212 | reg := "HKLM\\SYSTEM\\CurrentControlSet\\Control\\EarlyStartServices" 213 | size, err := RegGetValueSizeFromString(reg) 214 | if err != nil { 215 | t.Error(err) 216 | } 217 | t.Logf("Registry value size: %d", size) 218 | 219 | } 220 | 221 | func TestRegEnumKeys(t *testing.T) { 222 | if skeys, err := RegEnumKeys(`HKLM\System\CurrentControlSet\Services`); err != nil { 223 | t.Error(err) 224 | } else { 225 | for _, key := range skeys { 226 | t.Log(key) 227 | } 228 | } 229 | } 230 | 231 | func TestRegEnumValues(t *testing.T) { 232 | if values, err := RegEnumValues(`HKLM\System\CurrentControlSet\Enum`); err != nil { 233 | t.Error(err) 234 | } else { 235 | for _, val := range values { 236 | t.Log(val) 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /win32/advapi32/header.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package advapi32 5 | 6 | import ( 7 | "fmt" 8 | "syscall" 9 | "unsafe" 10 | 11 | "github.com/0xrawsec/golang-win32/win32" 12 | ) 13 | 14 | const ( 15 | WNODE_FLAG_ALL_DATA = 0x00000001 16 | WNODE_FLAG_SINGLE_INSTANCE = 0x00000002 17 | WNODE_FLAG_SINGLE_ITEM = 0x00000004 18 | WNODE_FLAG_EVENT_ITEM = 0x00000008 19 | WNODE_FLAG_FIXED_INSTANCE_SIZE = 0x00000010 20 | WNODE_FLAG_TOO_SMALL = 0x00000020 21 | WNODE_FLAG_INSTANCES_SAME = 0x00000040 22 | WNODE_FLAG_STATIC_INSTANCE_NAMES = 0x00000080 23 | WNODE_FLAG_INTERNAL = 0x00000100 24 | WNODE_FLAG_USE_TIMESTAMP = 0x00000200 25 | WNODE_FLAG_PERSIST_EVENT = 0x00000400 26 | WNODE_FLAG_EVENT_REFERENCE = 0x00002000 27 | WNODE_FLAG_ANSI_INSTANCENAMES = 0x00004000 28 | WNODE_FLAG_METHOD_ITEM = 0x00008000 29 | WNODE_FLAG_PDO_INSTANCE_NAMES = 0x00010000 30 | WNODE_FLAG_TRACED_GUID = 0x00020000 31 | WNODE_FLAG_LOG_WNODE = 0x00040000 32 | WNODE_FLAG_USE_GUID_PTR = 0x00080000 33 | WNODE_FLAG_USE_MOF_PTR = 0x00100000 34 | WNODE_FLAG_NO_HEADER = 0x00200000 35 | WNODE_FLAG_SEND_DATA_BLOCK = 0x00400000 36 | WNODE_FLAG_SEVERITY_MASK = 0xff000000 37 | ) 38 | 39 | const ( 40 | EVENT_TRACE_TYPE_INFO = 0x00 41 | EVENT_TRACE_TYPE_START = 0x01 42 | EVENT_TRACE_TYPE_END = 0x02 43 | EVENT_TRACE_TYPE_STOP = 0x02 44 | EVENT_TRACE_TYPE_DC_START = 0x03 45 | EVENT_TRACE_TYPE_DC_END = 0x04 46 | EVENT_TRACE_TYPE_EXTENSION = 0x05 47 | EVENT_TRACE_TYPE_REPLY = 0x06 48 | EVENT_TRACE_TYPE_DEQUEUE = 0x07 49 | EVENT_TRACE_TYPE_RESUME = 0x07 50 | EVENT_TRACE_TYPE_CHECKPOINT = 0x08 51 | EVENT_TRACE_TYPE_SUSPEND = 0x08 52 | EVENT_TRACE_TYPE_WINEVT_SEND = 0x09 53 | EVENT_TRACE_TYPE_WINEVT_RECEIVE = 0xf0 54 | 55 | EVENT_TRACE_TYPE_LOAD = 0x0a 56 | 57 | EVENT_TRACE_TYPE_IO_READ = 0x0a 58 | EVENT_TRACE_TYPE_IO_WRITE = 0x0b 59 | EVENT_TRACE_TYPE_IO_READ_INIT = 0x0c 60 | EVENT_TRACE_TYPE_IO_WRITE_INIT = 0x0d 61 | EVENT_TRACE_TYPE_IO_FLUSH = 0x0e 62 | EVENT_TRACE_TYPE_IO_FLUSH_INIT = 0x0f 63 | 64 | EVENT_TRACE_TYPE_MM_TF = 0x0a 65 | EVENT_TRACE_TYPE_MM_DZF = 0x0b 66 | EVENT_TRACE_TYPE_MM_COW = 0x0c 67 | EVENT_TRACE_TYPE_MM_GPF = 0x0d 68 | EVENT_TRACE_TYPE_MM_HPF = 0x0e 69 | EVENT_TRACE_TYPE_MM_AV = 0x0f 70 | 71 | EVENT_TRACE_TYPE_SEND = 0x0a 72 | EVENT_TRACE_TYPE_RECEIVE = 0x0b 73 | EVENT_TRACE_TYPE_CONNECT = 0x0c 74 | EVENT_TRACE_TYPE_DISCONNECT = 0x0d 75 | EVENT_TRACE_TYPE_RETRANSMIT = 0x0e 76 | EVENT_TRACE_TYPE_ACCEPT = 0x0f 77 | EVENT_TRACE_TYPE_RECONNECT = 0x10 78 | EVENT_TRACE_TYPE_CONNFAIL = 0x11 79 | EVENT_TRACE_TYPE_COPY_TCP = 0x12 80 | EVENT_TRACE_TYPE_COPY_ARP = 0x13 81 | EVENT_TRACE_TYPE_ACKFULL = 0x14 82 | EVENT_TRACE_TYPE_ACKPART = 0x15 83 | EVENT_TRACE_TYPE_ACKDUP = 0x16 84 | 85 | EVENT_TRACE_TYPE_GUIDMAP = 0x0a 86 | EVENT_TRACE_TYPE_CONFIG = 0x0b 87 | EVENT_TRACE_TYPE_SIDINFO = 0x0c 88 | EVENT_TRACE_TYPE_SECURITY = 0x0d 89 | EVENT_TRACE_TYPE_DBGID_RSDS = 0x40 90 | 91 | EVENT_TRACE_TYPE_REGCREATE = 0x0a 92 | EVENT_TRACE_TYPE_REGOPEN = 0x0b 93 | EVENT_TRACE_TYPE_REGDELETE = 0x0c 94 | EVENT_TRACE_TYPE_REGQUERY = 0x0d 95 | EVENT_TRACE_TYPE_REGSETVALUE = 0x0e 96 | EVENT_TRACE_TYPE_REGDELETEVALUE = 0x0f 97 | EVENT_TRACE_TYPE_REGQUERYVALUE = 0x10 98 | EVENT_TRACE_TYPE_REGENUMERATEKEY = 0x11 99 | EVENT_TRACE_TYPE_REGENUMERATEVALUEKEY = 0x12 100 | EVENT_TRACE_TYPE_REGQUERYMULTIPLEVALUE = 0x13 101 | EVENT_TRACE_TYPE_REGSETINFORMATION = 0x14 102 | EVENT_TRACE_TYPE_REGFLUSH = 0x15 103 | EVENT_TRACE_TYPE_REGKCBCREATE = 0x16 104 | EVENT_TRACE_TYPE_REGKCBDELETE = 0x17 105 | EVENT_TRACE_TYPE_REGKCBRUNDOWNBEGIN = 0x18 106 | EVENT_TRACE_TYPE_REGKCBRUNDOWNEND = 0x19 107 | EVENT_TRACE_TYPE_REGVIRTUALIZE = 0x1a 108 | EVENT_TRACE_TYPE_REGCLOSE = 0x1b 109 | EVENT_TRACE_TYPE_REGSETSECURITY = 0x1c 110 | EVENT_TRACE_TYPE_REGQUERYSECURITY = 0x1d 111 | EVENT_TRACE_TYPE_REGCOMMIT = 0x1e 112 | EVENT_TRACE_TYPE_REGPREPARE = 0x1f 113 | EVENT_TRACE_TYPE_REGROLLBACK = 0x20 114 | EVENT_TRACE_TYPE_REGMOUNTHIVE = 0x21 115 | 116 | EVENT_TRACE_TYPE_CONFIG_CPU = 0x0a 117 | EVENT_TRACE_TYPE_CONFIG_PHYSICALDISK = 0x0b 118 | EVENT_TRACE_TYPE_CONFIG_LOGICALDISK = 0x0c 119 | EVENT_TRACE_TYPE_CONFIG_NIC = 0x0d 120 | EVENT_TRACE_TYPE_CONFIG_VIDEO = 0x0e 121 | EVENT_TRACE_TYPE_CONFIG_SERVICES = 0x0f 122 | EVENT_TRACE_TYPE_CONFIG_POWER = 0x10 123 | EVENT_TRACE_TYPE_CONFIG_NETINFO = 0x11 124 | EVENT_TRACE_TYPE_CONFIG_OPTICALMEDIA = 0x12 125 | 126 | EVENT_TRACE_TYPE_CONFIG_IRQ = 0x15 127 | EVENT_TRACE_TYPE_CONFIG_PNP = 0x16 128 | EVENT_TRACE_TYPE_CONFIG_IDECHANNEL = 0x17 129 | EVENT_TRACE_TYPE_CONFIG_NUMANODE = 0x18 130 | EVENT_TRACE_TYPE_CONFIG_PLATFORM = 0x19 131 | EVENT_TRACE_TYPE_CONFIG_PROCESSORGROUP = 0x1a 132 | EVENT_TRACE_TYPE_CONFIG_PROCESSORNUMBER = 0x1b 133 | EVENT_TRACE_TYPE_CONFIG_DPI = 0x1c 134 | 135 | EVENT_TRACE_TYPE_OPTICAL_IO_READ = 0x37 136 | EVENT_TRACE_TYPE_OPTICAL_IO_WRITE = 0x38 137 | EVENT_TRACE_TYPE_OPTICAL_IO_FLUSH = 0x39 138 | EVENT_TRACE_TYPE_OPTICAL_IO_READ_INIT = 0x3a 139 | EVENT_TRACE_TYPE_OPTICAL_IO_WRITE_INIT = 0x3b 140 | EVENT_TRACE_TYPE_OPTICAL_IO_FLUSH_INIT = 0x3c 141 | 142 | EVENT_TRACE_TYPE_FLT_PREOP_INIT = 0x60 143 | EVENT_TRACE_TYPE_FLT_POSTOP_INIT = 0x61 144 | EVENT_TRACE_TYPE_FLT_PREOP_COMPLETION = 0x62 145 | EVENT_TRACE_TYPE_FLT_POSTOP_COMPLETION = 0x63 146 | EVENT_TRACE_TYPE_FLT_PREOP_FAILURE = 0x64 147 | EVENT_TRACE_TYPE_FLT_POSTOP_FAILURE = 0x65 148 | 149 | // See flag documentation here 150 | // https://docs.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties 151 | EVENT_TRACE_FLAG_PROCESS = 0x00000001 152 | EVENT_TRACE_FLAG_THREAD = 0x00000002 153 | EVENT_TRACE_FLAG_IMAGE_LOAD = 0x00000004 154 | 155 | EVENT_TRACE_FLAG_DISK_IO = 0x00000100 156 | EVENT_TRACE_FLAG_DISK_FILE_IO = 0x00000200 157 | 158 | EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS = 0x00001000 159 | EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS = 0x00002000 160 | 161 | EVENT_TRACE_FLAG_NETWORK_TCPIP = 0x00010000 162 | 163 | EVENT_TRACE_FLAG_REGISTRY = 0x00020000 164 | EVENT_TRACE_FLAG_DBGPRINT = 0x00040000 165 | 166 | EVENT_TRACE_FLAG_PROCESS_COUNTERS = 0x00000008 167 | EVENT_TRACE_FLAG_CSWITCH = 0x00000010 168 | EVENT_TRACE_FLAG_DPC = 0x00000020 169 | EVENT_TRACE_FLAG_INTERRUPT = 0x00000040 170 | EVENT_TRACE_FLAG_SYSTEMCALL = 0x00000080 171 | 172 | EVENT_TRACE_FLAG_DISK_IO_INIT = 0x00000400 173 | EVENT_TRACE_FLAG_ALPC = 0x00100000 174 | EVENT_TRACE_FLAG_SPLIT_IO = 0x00200000 175 | 176 | EVENT_TRACE_FLAG_DRIVER = 0x00800000 177 | EVENT_TRACE_FLAG_PROFILE = 0x01000000 178 | EVENT_TRACE_FLAG_FILE_IO = 0x02000000 179 | EVENT_TRACE_FLAG_FILE_IO_INIT = 0x04000000 180 | 181 | EVENT_TRACE_FLAG_DISPATCHER = 0x00000800 182 | EVENT_TRACE_FLAG_VIRTUAL_ALLOC = 0x00004000 183 | 184 | EVENT_TRACE_FLAG_VAMAP = 0x00008000 185 | EVENT_TRACE_FLAG_NO_SYSCONFIG = 0x10000000 186 | 187 | EVENT_TRACE_FLAG_EXTENSION = 0x80000000 188 | EVENT_TRACE_FLAG_FORWARD_WMI = 0x40000000 189 | EVENT_TRACE_FLAG_ENABLE_RESERVE = 0x20000000 190 | 191 | EVENT_TRACE_FILE_MODE_NONE = 0x00000000 192 | EVENT_TRACE_FILE_MODE_SEQUENTIAL = 0x00000001 193 | EVENT_TRACE_FILE_MODE_CIRCULAR = 0x00000002 194 | EVENT_TRACE_FILE_MODE_APPEND = 0x00000004 195 | 196 | EVENT_TRACE_REAL_TIME_MODE = 0x00000100 197 | EVENT_TRACE_DELAY_OPEN_FILE_MODE = 0x00000200 198 | EVENT_TRACE_BUFFERING_MODE = 0x00000400 199 | EVENT_TRACE_PRIVATE_LOGGER_MODE = 0x00000800 200 | EVENT_TRACE_ADD_HEADER_MODE = 0x00001000 201 | 202 | EVENT_TRACE_USE_GLOBAL_SEQUENCE = 0x00004000 203 | EVENT_TRACE_USE_LOCAL_SEQUENCE = 0x00008000 204 | 205 | EVENT_TRACE_RELOG_MODE = 0x00010000 206 | 207 | EVENT_TRACE_USE_PAGED_MEMORY = 0x01000000 208 | 209 | EVENT_TRACE_FILE_MODE_NEWFILE = 0x00000008 210 | EVENT_TRACE_FILE_MODE_PREALLOCATE = 0x00000020 211 | 212 | EVENT_TRACE_NONSTOPPABLE_MODE = 0x00000040 213 | EVENT_TRACE_SECURE_MODE = 0x00000080 214 | EVENT_TRACE_USE_KBYTES_FOR_SIZE = 0x00002000 215 | EVENT_TRACE_PRIVATE_IN_PROC = 0x00020000 216 | EVENT_TRACE_MODE_RESERVED = 0x00100000 217 | 218 | EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING = 0x10000000 219 | 220 | EVENT_TRACE_SYSTEM_LOGGER_MODE = 0x02000000 221 | EVENT_TRACE_ADDTO_TRIAGE_DUMP = 0x80000000 222 | EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN = 0x00400000 223 | EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN = 0x00800000 224 | 225 | EVENT_TRACE_CONTROL_QUERY = 0 226 | EVENT_TRACE_CONTROL_STOP = 1 227 | EVENT_TRACE_CONTROL_UPDATE = 2 228 | EVENT_TRACE_CONTROL_FLUSH = 3 229 | 230 | EVENT_TRACE_USE_PROCTIME = 0x0001 231 | EVENT_TRACE_USE_NOCPUTIME = 0x0002 232 | ) 233 | 234 | const ( 235 | EVENT_CONTROL_CODE_DISABLE_PROVIDER = 0 236 | EVENT_CONTROL_CODE_ENABLE_PROVIDER = 1 237 | EVENT_CONTROL_CODE_CAPTURE_STATE = 2 238 | ) 239 | 240 | const ( 241 | TRACE_LEVEL_NONE = 0 242 | TRACE_LEVEL_CRITICAL = 1 243 | TRACE_LEVEL_FATAL = 1 244 | TRACE_LEVEL_ERROR = 2 245 | TRACE_LEVEL_WARNING = 3 246 | TRACE_LEVEL_INFORMATION = 4 247 | TRACE_LEVEL_VERBOSE = 5 248 | TRACE_LEVEL_RESERVED6 = 6 249 | TRACE_LEVEL_RESERVED7 = 7 250 | TRACE_LEVEL_RESERVED8 = 8 251 | TRACE_LEVEL_RESERVED9 = 9 252 | ) 253 | 254 | const ( 255 | PROCESS_TRACE_MODE_REAL_TIME = 0x00000100 256 | PROCESS_TRACE_MODE_RAW_TIMESTAMP = 0x00001000 257 | PROCESS_TRACE_MODE_EVENT_RECORD = 0x10000000 258 | ) 259 | 260 | const ( 261 | EVENT_HEADER_FLAG_EXTENDED_INFO = 0x0001 262 | EVENT_HEADER_FLAG_PRIVATE_SESSION = 0x0002 263 | EVENT_HEADER_FLAG_STRING_ONLY = 0x0004 264 | EVENT_HEADER_FLAG_TRACE_MESSAGE = 0x0008 265 | EVENT_HEADER_FLAG_NO_CPUTIME = 0x0010 266 | EVENT_HEADER_FLAG_32_BIT_HEADER = 0x0020 267 | EVENT_HEADER_FLAG_64_BIT_HEADER = 0x0040 268 | EVENT_HEADER_FLAG_CLASSIC_HEADER = 0x0100 269 | EVENT_HEADER_FLAG_PROCESSOR_INDEX = 0x0200 270 | ) 271 | 272 | const ( 273 | EVENT_HEADER_PROPERTY_XML = 0x0001 274 | EVENT_HEADER_PROPERTY_FORWARDED_XML = 0x0002 275 | EVENT_HEADER_PROPERTY_LEGACY_EVENTLOG = 0x0004 276 | ) 277 | 278 | ////////////////////////////////////////////////////////////////// 279 | 280 | const ( 281 | SERVICE_ACTIVE = 0x00000001 282 | SERVICE_INACTIVE = 0x00000002 283 | SERVICE_STATE_ALL = (SERVICE_ACTIVE | SERVICE_INACTIVE) 284 | ) 285 | 286 | type ScEnumType int 287 | 288 | const ( 289 | SC_ENUM_PROCESS_INFO = ScEnumType(0) 290 | ) 291 | 292 | const ( 293 | SC_MANAGER_CONNECT = 0x0001 294 | SC_MANAGER_CREATE_SERVICE = 0x0002 295 | SC_MANAGER_ENUMERATE_SERVICE = 0x0004 296 | SC_MANAGER_LOCK = 0x0008 297 | SC_MANAGER_QUERY_LOCK_STATUS = 0x0010 298 | SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020 299 | 300 | SC_MANAGER_ALL_ACCESS = (win32.STANDARD_RIGHTS_REQUIRED | 301 | SC_MANAGER_CONNECT | 302 | SC_MANAGER_CREATE_SERVICE | 303 | SC_MANAGER_ENUMERATE_SERVICE | 304 | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG) 305 | ) 306 | 307 | /* 308 | typedef struct _ENUM_SERVICE_STATUSW { 309 | LPWSTR lpServiceName; 310 | LPWSTR lpDisplayName; 311 | SERVICE_STATUS ServiceStatus; 312 | } ENUM_SERVICE_STATUSW, *LPENUM_SERVICE_STATUSW; 313 | */ 314 | 315 | type EnumServiceStatusProcess struct { 316 | ServiceName *uint16 317 | DisplayName *uint16 318 | ServiceStatusProcess ServiceStatusProcess 319 | } 320 | 321 | func (e EnumServiceStatusProcess) String() string { 322 | return fmt.Sprintf("ServiceName: %s\nDisplayName: %s\nServiceStatusProcess: %s", 323 | win32.UTF16PtrToString(e.ServiceName), 324 | win32.UTF16PtrToString(e.DisplayName), e.ServiceStatusProcess) 325 | } 326 | 327 | /* 328 | typedef struct _SERVICE_STATUS_PROCESS { 329 | DWORD dwServiceType; 330 | DWORD dwCurrentState; 331 | DWORD dwControlsAccepted; 332 | DWORD dwWin32ExitCode; 333 | DWORD dwServiceSpecificExitCode; 334 | DWORD dwCheckPoint; 335 | DWORD dwWaitHint; 336 | DWORD dwProcessId; 337 | DWORD dwServiceFlags; 338 | } SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS; 339 | */ 340 | 341 | type ServiceStatusProcess struct { 342 | ServiceType uint32 343 | CurrentState uint32 344 | ControlAccepted uint32 345 | Win32ExitCode uint32 346 | ServiceSpecificExitCode uint32 347 | CheckPoint uint32 348 | WaitHint uint32 349 | ProcessId uint32 350 | ServiceFlags uint32 351 | } 352 | 353 | func (s ServiceStatusProcess) String() string { 354 | return fmt.Sprintf( 355 | "ServiceType: %d\nCurrentState: %d\nControlAccepted: %d\n"+ 356 | "Win32ExitCode: %d\nServiceSpecificExitCode: %d\nCheckpoint: %d\n"+ 357 | "WaitHint: %d\nProcessId: %d\nServiceFlags: %d", 358 | s.ServiceType, s.CurrentState, s.ControlAccepted, 359 | s.Win32ExitCode, s.ServiceSpecificExitCode, s.CheckPoint, 360 | s.WaitHint, s.ProcessId, s.ServiceFlags) 361 | } 362 | 363 | ////////////////////////////////////////////////////////////////// 364 | 365 | type GUID struct { 366 | win32.GUID 367 | } 368 | 369 | /* 370 | typedef struct _WNODE_HEADER { 371 | ULONG BufferSize; 372 | ULONG ProviderId; 373 | __C89_NAMELESS union { 374 | ULONG64 HistoricalContext; 375 | __C89_NAMELESS struct { 376 | ULONG Version; 377 | ULONG Linkage; 378 | }; 379 | }; 380 | __C89_NAMELESS union { 381 | ULONG CountLost; 382 | HANDLE KernelHandle; 383 | LARGE_INTEGER TimeStamp; 384 | }; 385 | GUID Guid; 386 | ULONG ClientContext; 387 | ULONG Flags; 388 | } WNODE_HEADER,*PWNODE_HEADER 389 | */ 390 | 391 | type WnodeHeader struct { 392 | BufferSize uint32 393 | ProviderId uint32 394 | Union1 uint64 395 | Union2 int64 396 | Guid GUID 397 | ClientContext uint32 398 | Flags uint32 399 | } 400 | 401 | type EventTraceProperties struct { 402 | Wnode WnodeHeader 403 | BufferSize uint32 404 | MinimumBuffers uint32 405 | MaximumBuffers uint32 406 | MaximumFileSize uint32 407 | LogFileMode uint32 408 | FlushTimer uint32 409 | EnableFlags uint32 410 | AgeLimit int32 411 | NumberOfBuffers uint32 412 | FreeBuffers uint32 413 | EventsLost uint32 414 | BuffersWritten uint32 415 | LogBuffersLost uint32 416 | RealTimeBuffersLost uint32 417 | LoggerThreadId syscall.Handle 418 | LogFileNameOffset uint32 419 | LoggerNameOffset uint32 420 | } 421 | 422 | /* 423 | typedef struct _ENABLE_TRACE_PARAMETERS { 424 | ULONG Version; 425 | ULONG EnableProperty; 426 | ULONG ControlFlags; 427 | GUID SourceId; 428 | PEVENT_FILTER_DESCRIPTOR EnableFilterDesc; 429 | ULONG FilterDescCount; 430 | } ENABLE_TRACE_PARAMETERS, *PENABLE_TRACE_PARAMETERS; 431 | */ 432 | 433 | type EnableTraceParameters struct { 434 | Version uint32 435 | EnableProperty uint32 436 | ControlFlags uint32 437 | SourceId GUID 438 | EnableFilterDesc *EventFilterDescriptor 439 | FilterDescrCount uint32 440 | } 441 | 442 | /* 443 | typedef struct _EVENT_FILTER_DESCRIPTOR { 444 | ULONGLONG Ptr; 445 | ULONG Size; 446 | ULONG Type; 447 | } EVENT_FILTER_DESCRIPTOR, *PEVENT_FILTER_DESCRIPTOR; 448 | */ 449 | // sizeof: 0x10 (OK) 450 | type EventFilterDescriptor struct { 451 | Ptr uint64 452 | Size uint32 453 | Type uint32 454 | } 455 | 456 | /* 457 | typedef struct _FILETIME { 458 | DWORD dwLowDateTime; 459 | DWORD dwHighDateTime; 460 | } FILETIME, *PFILETIME, *LPFILETIME; 461 | */ 462 | type FileTime struct { 463 | dwLowDateTime uint32 464 | dwHighDateTime uint32 465 | } 466 | 467 | /* 468 | typedef struct _EVENT_TRACE_LOGFILEW { 469 | LPWSTR LogFileName; 470 | LPWSTR LoggerName; 471 | LONGLONG CurrentTime; 472 | ULONG BuffersRead; 473 | union { 474 | ULONG LogFileMode; 475 | ULONG ProcessTraceMode; 476 | } DUMMYUNIONNAME; 477 | EVENT_TRACE CurrentEvent; 478 | TRACE_LOGFILE_HEADER LogfileHeader; 479 | PEVENT_TRACE_BUFFER_CALLBACKW BufferCallback; 480 | ULONG BufferSize; 481 | ULONG Filled; 482 | ULONG EventsLost; 483 | union { 484 | PEVENT_CALLBACK EventCallback; 485 | PEVENT_RECORD_CALLBACK EventRecordCallback; 486 | } DUMMYUNIONNAME2; 487 | ULONG IsKernelTrace; 488 | PVOID Context; 489 | } EVENT_TRACE_LOGFILEW, *PEVENT_TRACE_LOGFILEW; 490 | */ 491 | 492 | type EventTraceLogfile struct { 493 | LogFileName *uint16 494 | LoggerName *uint16 495 | CurrentTime int64 496 | BuffersRead uint32 497 | Union1 uint32 498 | CurrentEvent EventTrace 499 | LogfileHeader TraceLogfileHeader 500 | //BufferCallback *EventTraceBufferCallback 501 | BufferCallback uintptr 502 | BufferSize uint32 503 | Filled uint32 504 | EventsLost uint32 505 | Callback uintptr 506 | IsKernelTrace uint32 507 | Context uintptr 508 | } 509 | 510 | func (e *EventTraceLogfile) SetProcessTraceMode(ptm uint32) { 511 | e.Union1 = ptm 512 | } 513 | 514 | type EventCallback func(*EventTrace) 515 | type EventRecordCallback func(*EventRecord) 516 | type EventTraceBufferCallback func(*EventTraceLogfile) uint32 517 | 518 | /* 519 | typedef struct _EVENT_RECORD { 520 | EVENT_HEADER EventHeader; 521 | ETW_BUFFER_CONTEXT BufferContext; 522 | USHORT ExtendedDataCount; 523 | USHORT UserDataLength; 524 | PEVENT_HEADER_EXTENDED_DATA_ITEM ExtendedData; 525 | PVOID UserData; 526 | PVOID UserContext; 527 | } EVENT_RECORD, *PEVENT_RECORD; 528 | */ 529 | 530 | type EventRecord struct { 531 | EventHeader EventHeader 532 | BufferContext EtwBufferContext 533 | ExtendedDataCount uint16 534 | UserDataLength uint16 535 | ExtendedData *EventHeaderExtendedDataItem 536 | UserData uintptr 537 | UserContext uintptr 538 | } 539 | 540 | func (e *EventRecord) pointer() uintptr { 541 | return (uintptr)(unsafe.Pointer(e)) 542 | } 543 | 544 | func (e *EventRecord) pointerOffset(offset uintptr) uintptr { 545 | return e.pointer() + offset 546 | } 547 | 548 | /* 549 | typedef struct _EVENT_HEADER_EXTENDED_DATA_ITEM { 550 | USHORT Reserved1; 551 | USHORT ExtType; 552 | struct { 553 | USHORT Linkage : 1; 554 | USHORT Reserved2 : 15; 555 | }; 556 | USHORT DataSize; 557 | ULONGLONG DataPtr; 558 | } EVENT_HEADER_EXTENDED_DATA_ITEM, *PEVENT_HEADER_EXTENDED_DATA_ITEM; 559 | */ 560 | 561 | type EventHeaderExtendedDataItem struct { 562 | Reserved1 uint16 563 | ExtType uint16 564 | InternalStruct uint16 565 | DataSize uint16 566 | DataPtr uint64 567 | } 568 | 569 | /* 570 | typedef struct _EVENT_HEADER { 571 | USHORT Size; 572 | USHORT HeaderType; 573 | USHORT Flags; 574 | USHORT EventProperty; 575 | ULONG ThreadId; 576 | ULONG ProcessId; 577 | LARGE_INTEGER TimeStamp; 578 | GUID ProviderId; 579 | EVENT_DESCRIPTOR EventDescriptor; 580 | union { 581 | struct { 582 | ULONG KernelTime; 583 | ULONG UserTime; 584 | } DUMMYSTRUCTNAME; 585 | ULONG64 ProcessorTime; 586 | } DUMMYUNIONNAME; 587 | GUID ActivityId; 588 | } EVENT_HEADER, *PEVENT_HEADER; 589 | */ 590 | type EventHeader struct { 591 | Size uint16 592 | HeaderType uint16 593 | Flags uint16 594 | EventProperty uint16 595 | ThreadId uint32 596 | ProcessId uint32 597 | TimeStamp int64 598 | ProviderId GUID 599 | EventDescriptor EventDescriptor 600 | Time int64 601 | ActivityId GUID 602 | } 603 | 604 | /* 605 | typedef struct _EVENT_DESCRIPTOR { 606 | USHORT Id; 607 | UCHAR Version; 608 | UCHAR Channel; 609 | UCHAR Level; 610 | UCHAR Opcode; 611 | USHORT Task; 612 | ULONGLONG Keyword; 613 | } EVENT_DESCRIPTOR, *PEVENT_DESCRIPTOR; 614 | */ 615 | type EventDescriptor struct { 616 | Id uint16 617 | Version uint8 618 | Channel uint8 619 | Level uint8 620 | Opcode uint8 621 | Task uint16 622 | Keyword uint64 623 | } 624 | 625 | /* 626 | typedef struct _EVENT_TRACE { 627 | EVENT_TRACE_HEADER Header; 628 | ULONG InstanceId; 629 | ULONG ParentInstanceId; 630 | GUID ParentGuid; 631 | PVOID MofData; 632 | ULONG MofLength; 633 | union { 634 | ULONG ClientContext; 635 | ETW_BUFFER_CONTEXT BufferContext; 636 | } DUMMYUNIONNAME; 637 | } EVENT_TRACE, *PEVENT_TRACE; 638 | */ 639 | type EventTrace struct { 640 | Header EventTraceHeader 641 | InstanceId uint32 642 | ParentInstanceId uint32 643 | ParentGuid GUID 644 | MofData uintptr 645 | MofLength uint32 646 | UnionCtx uint32 647 | } 648 | 649 | /* 650 | typedef struct _ETW_BUFFER_CONTEXT { 651 | union { 652 | struct { 653 | UCHAR ProcessorNumber; 654 | UCHAR Alignment; 655 | } DUMMYSTRUCTNAME; // siize UCHAR 656 | USHORT ProcessorIndex; // USHORT 657 | } DUMMYUNIONNAME; // USHORT 658 | USHORT LoggerId; 659 | } ETW_BUFFER_CONTEXT, *PETW_BUFFER_CONTEXT; 660 | */ 661 | // sizeof: 0x4 (OK) 662 | type EtwBufferContext struct { 663 | Union uint16 664 | LoggerId uint16 665 | } 666 | 667 | /* 668 | typedef struct _EVENT_TRACE_HEADER { 669 | USHORT Size; 670 | union { 671 | USHORT FieldTypeFlags; 672 | struct { 673 | UCHAR HeaderType; 674 | UCHAR MarkerFlags; 675 | } DUMMYSTRUCTNAME; 676 | } DUMMYUNIONNAME; 677 | union { 678 | ULONG Version; 679 | struct { 680 | UCHAR Type; 681 | UCHAR Level; 682 | USHORT Version; 683 | } Class; 684 | } DUMMYUNIONNAME2; 685 | ULONG ThreadId; 686 | ULONG ProcessId; 687 | LARGE_INTEGER TimeStamp; 688 | union { 689 | GUID Guid; 690 | ULONGLONG GuidPtr; 691 | } DUMMYUNIONNAME3; 692 | union { 693 | struct { 694 | ULONG KernelTime; 695 | ULONG UserTime; 696 | } DUMMYSTRUCTNAME; uint64 697 | ULONG64 ProcessorTime; uint64 698 | struct { 699 | ULONG ClientContext; 700 | ULONG Flags; 701 | } DUMMYSTRUCTNAME2; uint64 702 | } DUMMYUNIONNAME4; 703 | } EVENT_TRACE_HEADER, *PEVENT_TRACE_HEADER; 704 | */ 705 | 706 | // sizeof: 0x30 (48) 707 | type EventTraceHeader struct { 708 | Size uint16 709 | Union1 uint16 710 | Union2 uint32 711 | ThreadId uint32 712 | ProcessId uint32 713 | TimeStamp int64 714 | Union3 [16]byte 715 | Union4 uint64 716 | } 717 | 718 | /* 719 | typedef struct _TRACE_LOGFILE_HEADER { 720 | ULONG BufferSize; 721 | union { 722 | ULONG Version; 723 | struct { 724 | UCHAR MajorVersion; 725 | UCHAR MinorVersion; 726 | UCHAR SubVersion; 727 | UCHAR SubMinorVersion; 728 | } VersionDetail; 729 | }; 730 | ULONG ProviderVersion; 731 | ULONG NumberOfProcessors; 732 | LARGE_INTEGER EndTime; 733 | ULONG TimerResolution; 734 | ULONG MaximumFileSize; 735 | ULONG LogFileMode; 736 | ULONG BuffersWritten; 737 | union { 738 | GUID LogInstanceGuid; 739 | struct { 740 | ULONG StartBuffers; 741 | ULONG PointerSize; 742 | ULONG EventsLost; 743 | ULONG CpuSpeedInMHz; 744 | }; 745 | }; 746 | LPWSTR LoggerName; 747 | LPWSTR LogFileName; 748 | TIME_ZONE_INFORMATION TimeZone; 749 | LARGE_INTEGER BootTime; 750 | LARGE_INTEGER PerfFreq; 751 | LARGE_INTEGER StartTime; 752 | ULONG ReservedFlags; 753 | ULONG BuffersLost; 754 | } TRACE_LOGFILE_HEADER, *PTRACE_LOGFILE_HEADER; 755 | */ 756 | 757 | type TraceLogfileHeader struct { 758 | BufferSize uint32 759 | VersionUnion uint32 760 | ProviderVersion uint32 761 | NumberOfProcessors uint32 762 | EndTime int64 763 | TimerResolution uint32 764 | MaximumFileSize uint32 765 | LogFileMode uint32 766 | BuffersWritten uint32 767 | Union1 [16]byte 768 | LoggerName *uint16 769 | LogFileName *uint16 770 | TimeZone TimeZoneInformation 771 | BootTime int64 772 | PerfFreq int64 773 | StartTime int64 774 | ReservedFlags uint32 775 | BuffersLost uint32 776 | } 777 | 778 | /* 779 | typedef struct _TIME_ZONE_INFORMATION { 780 | LONG Bias; 781 | WCHAR StandardName[32]; 782 | SYSTEMTIME StandardDate; 783 | LONG StandardBias; 784 | WCHAR DaylightName[32]; 785 | SYSTEMTIME DaylightDate; 786 | LONG DaylightBias; 787 | } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION; 788 | */ 789 | 790 | type TimeZoneInformation struct { 791 | Bias int32 792 | StandardName [32]uint16 793 | StandardDate SystemTime 794 | StandardBias int32 795 | DaylightName [32]uint16 796 | DaylightDate SystemTime 797 | DaylighBias int32 798 | } 799 | 800 | /* 801 | typedef struct _SYSTEMTIME { 802 | WORD wYear; 803 | WORD wMonth; 804 | WORD wDayOfWeek; 805 | WORD wDay; 806 | WORD wHour; 807 | WORD wMinute; 808 | WORD wSecond; 809 | WORD wMilliseconds; 810 | } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; 811 | */ 812 | // sizeof: 0x10 (OK) 813 | type SystemTime struct { 814 | Year uint16 815 | Month uint16 816 | DayOfWeek uint16 817 | Day uint16 818 | Hour uint16 819 | Minute uint16 820 | Second uint16 821 | Milliseconds uint16 822 | } 823 | 824 | //////////////////////// Registry ////////////////////////// 825 | 826 | const ( 827 | HKEY_CLASSES_ROOT = syscall.Handle(0x80000000) 828 | HKEY_CURRENT_USER = syscall.Handle(0x80000001) 829 | HKEY_LOCAL_MACHINE = syscall.Handle(0x80000002) 830 | HKEY_USERS = syscall.Handle(0x80000003) 831 | HKEY_PERFORMANCE_DATA = syscall.Handle(0x80000004) 832 | HKEY_PERFORMANCE_TEXT = syscall.Handle(0x80000050) 833 | HKEY_PERFORMANCE_NLSTEXT = syscall.Handle(0x80000060) 834 | HKEY_CURRENT_CONFIG = syscall.Handle(0x80000005) 835 | HKEY_DYN_DATA = syscall.Handle(0x80000006) 836 | ) 837 | 838 | const ( 839 | // https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits 840 | MAX_KEY_LENGTH = 255 841 | MAX_VALUE_NAME = 16383 842 | ) 843 | -------------------------------------------------------------------------------- /win32/advapi32/helpers.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package advapi32 5 | 6 | import ( 7 | "encoding/binary" 8 | "errors" 9 | "fmt" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | "syscall" 14 | "unsafe" 15 | 16 | "github.com/0xrawsec/golang-win32/win32" 17 | ) 18 | 19 | // ServiceWin32NamesByPid is an helper function to return the service 20 | // name of a SERVICE_WIN32 from a pid 21 | func ServiceWin32NamesByPid(pid uint32) (string, error) { 22 | se, err := NewServiceEnumerator() 23 | if err != nil { 24 | return "", err 25 | } 26 | defer se.Close() 27 | return se.ServiceNamesByPID(pid, win32.SERVICE_WIN32) 28 | } 29 | 30 | // ServiceEnumerator structure used to enumerate windows services 31 | type ServiceEnumerator struct { 32 | hMan syscall.Handle 33 | } 34 | 35 | // NewServiceEnumerator initializes a new ServiceEnumerator structure 36 | func NewServiceEnumerator() (*ServiceEnumerator, error) { 37 | hman, err := OpenSCManagerW(nil, nil, SC_MANAGER_ENUMERATE_SERVICE) 38 | if err != nil { 39 | return nil, fmt.Errorf("Failed to open service manager: %s", err) 40 | } 41 | return &ServiceEnumerator{hman}, nil 42 | } 43 | 44 | // Services retrieves the list of services of a certain type 45 | // for service types look at https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-enumservicesstatusexw 46 | // service types are available in win32 package Ex: win32.SERVICE_WIN32 47 | func (s *ServiceEnumerator) Services(stype uint32) (ss []EnumServiceStatusProcess, err error) { 48 | ss = make([]EnumServiceStatusProcess, 0) 49 | bytesNeeded := uint32(0) 50 | servicesReturned := uint32(0) 51 | resumeHandle := uint32(0) 52 | cbBufSize := uint32(0) 53 | 54 | if err = EnumServicesStatusEx(s.hMan, 55 | SC_ENUM_PROCESS_INFO, 56 | stype, 57 | SERVICE_ACTIVE, 58 | nil, 59 | cbBufSize, 60 | &bytesNeeded, 61 | &servicesReturned, 62 | &resumeHandle, 63 | nil); err.(syscall.Errno) != win32.ERROR_MORE_DATA { 64 | return 65 | } 66 | ss = make([]EnumServiceStatusProcess, int(bytesNeeded/uint32(unsafe.Sizeof(EnumServiceStatusProcess{})))+1) 67 | cbBufSize = uint32(uintptr(len(ss)) * unsafe.Sizeof(EnumServiceStatusProcess{})) 68 | 69 | // Reset handle 70 | resumeHandle = uint32(0) 71 | 72 | if err = EnumServicesStatusEx(s.hMan, 73 | SC_ENUM_PROCESS_INFO, 74 | stype, 75 | SERVICE_ACTIVE, 76 | (*byte)(unsafe.Pointer(&ss[0])), 77 | cbBufSize, 78 | &bytesNeeded, 79 | &servicesReturned, 80 | &resumeHandle, 81 | nil); err != nil { 82 | return 83 | } 84 | return ss[:servicesReturned], err 85 | } 86 | 87 | // ServiceNamesByPID returns a comma separated list of the service names 88 | // a process (svchost in particular) can be associated with several services 89 | func (s *ServiceEnumerator) ServiceNamesByPID(pid uint32, stype uint32) (string, error) { 90 | out := make([]string, 0) 91 | services, err := s.Services(stype) 92 | if err != nil { 93 | return "", err 94 | } 95 | for _, service := range services { 96 | if service.ServiceStatusProcess.ProcessId == pid { 97 | sn := win32.UTF16PtrToString(service.ServiceName) 98 | out = append(out, sn) 99 | } 100 | } 101 | 102 | // pid is not a service 103 | if len(out) == 0 { 104 | return "N/A", nil 105 | } 106 | return strings.Join(out, ","), nil 107 | } 108 | 109 | // Close gently closes the ServiceEnumerator 110 | func (s *ServiceEnumerator) Close() error { 111 | return CloseServiceHandle(s.hMan) 112 | } 113 | 114 | /////////////////////////////////////////////////////////////// 115 | 116 | // regOpenKeyRecFromPath opens registry keys recursively 117 | func regOpenKeyRecFromPath(hKey syscall.Handle, path []string, samDesired uint32) (hSubKey syscall.Handle, err error) { 118 | defer RegCloseKey(hKey) 119 | subkey := path[0] 120 | err = RegOpenKeyEx( 121 | hKey, 122 | syscall.StringToUTF16Ptr(subkey), 123 | 0, 124 | samDesired, 125 | &hSubKey) 126 | if err != nil || len(path) == 1 { 127 | return 128 | } 129 | return regOpenKeyRecFromPath(hSubKey, path[1:], samDesired) 130 | } 131 | 132 | // RegOpenKeyRecFromString returns a handle to the registry key pointed by a full path 133 | // it opens keys recursively Ex: HKLM\\SYSTEM\\CurrentControlSet\\Control\\EarlyStartServices 134 | func RegOpenKeyRecFromString(path string, samDesired uint32) (hSubKey syscall.Handle, err error) { 135 | var hKey syscall.Handle 136 | sp := strings.Split(path, string(os.PathSeparator)) 137 | root, key := sp[0], sp[1:] 138 | switch root { 139 | case "HKLM", "HKEY_LOCAL_MACHINE": 140 | hKey = HKEY_LOCAL_MACHINE 141 | case "HKU", "HKEY_USERS": 142 | hKey = HKEY_USERS 143 | case "HKCR", "HKEY_CLASSES_ROOT": 144 | hKey = HKEY_CLASSES_ROOT 145 | case "HKCU", "HKEY_CURRENT_USER": 146 | hKey = HKEY_CURRENT_USER 147 | case "HKEY_CURRENT_CONFIG": 148 | hKey = HKEY_CURRENT_CONFIG 149 | default: 150 | err = fmt.Errorf("Unknown root key %s", root) 151 | return 152 | } 153 | return regOpenKeyRecFromPath(hKey, key, samDesired) 154 | } 155 | 156 | // RegGetValueSizeFromString returns the size of a registry value in bytes 157 | func RegGetValueSizeFromString(reg string) (size uint32, err error) { 158 | var hKey syscall.Handle 159 | 160 | sp := strings.Split(reg, string(os.PathSeparator)) 161 | value := sp[len(sp)-1] 162 | 163 | if hKey, err = RegOpenKeyRecFromString(filepath.Join(sp[0:len(sp)-1]...), win32.KEY_READ); err != nil { 164 | return 165 | } 166 | defer RegCloseKey(hKey) 167 | if err = RegQueryValueEx( 168 | hKey, 169 | syscall.StringToUTF16Ptr(value), 170 | nil, 171 | nil, 172 | nil, 173 | &size); err != nil { 174 | return 175 | } 176 | return 177 | } 178 | 179 | var ( 180 | ErrUnkownRegValueType = errors.New("unknown registry value type") 181 | ) 182 | 183 | // ParseRegValue is a helper function to parse data stored in registry 184 | func ParseRegValue(data []byte, dtype uint32) (interface{}, error) { 185 | switch dtype { 186 | case syscall.REG_BINARY: 187 | return data, nil 188 | case syscall.REG_DWORD: 189 | return binary.LittleEndian.Uint32(data), nil 190 | case syscall.REG_DWORD_BIG_ENDIAN: 191 | return binary.BigEndian.Uint32(data), nil 192 | case syscall.REG_MULTI_SZ: 193 | out := make([]string, 0) 194 | buf := make([]uint16, 0) 195 | if len(data) > 0 { 196 | p := unsafe.Pointer(&data[0]) 197 | for i := uintptr(2); i < uintptr(len(data)); i += 2 { 198 | wc := (*uint16)(p) 199 | if *wc == 0 { 200 | out = append(out, syscall.UTF16ToString(buf)) 201 | buf = make([]uint16, 0) 202 | } else { 203 | buf = append(buf, *wc) 204 | } 205 | p = win32.Add(p, 2) 206 | } 207 | if len(buf) > 0 { 208 | out = append(out, syscall.UTF16ToString(buf)) 209 | } 210 | } 211 | return out, nil 212 | case syscall.REG_NONE: 213 | return nil, nil 214 | case syscall.REG_QWORD: 215 | return binary.LittleEndian.Uint64(data), nil 216 | case syscall.REG_SZ, syscall.REG_EXPAND_SZ, syscall.REG_LINK: 217 | return win32.UTF16BytesToString(data), nil 218 | default: 219 | return nil, fmt.Errorf("%w 0x%08x", ErrUnkownRegValueType, dtype) 220 | } 221 | } 222 | 223 | // RegGetValueFromString returns the data associated to a registry value as well as 224 | // its type represented by a uint32 225 | func RegGetValueFromString(path string) (data []byte, dtype uint32, err error) { 226 | var hKey syscall.Handle 227 | var lpcbData uint32 228 | 229 | sp := strings.Split(path, string(os.PathSeparator)) 230 | value := sp[len(sp)-1] 231 | 232 | if hKey, err = RegOpenKeyRecFromString(filepath.Join(sp[0:len(sp)-1]...), win32.KEY_READ); err != nil { 233 | return 234 | } 235 | defer RegCloseKey(hKey) 236 | 237 | if err = RegQueryValueEx( 238 | hKey, 239 | syscall.StringToUTF16Ptr(value), 240 | nil, 241 | &dtype, 242 | nil, 243 | &lpcbData); err != nil { 244 | return 245 | } 246 | 247 | // there is nothing to query for 248 | if lpcbData == 0 { 249 | return 250 | } 251 | 252 | data = make([]byte, lpcbData) 253 | if err = RegQueryValueEx( 254 | hKey, 255 | syscall.StringToUTF16Ptr(value), 256 | nil, 257 | &dtype, 258 | (*byte)(unsafe.Pointer(&data[0])), 259 | &lpcbData); err != nil { 260 | return 261 | } 262 | return 263 | } 264 | 265 | func RegEnumValues(root string) (values []string, err error) { 266 | var hKey syscall.Handle 267 | 268 | values = make([]string, 0) 269 | valueName := [MAX_VALUE_NAME]uint16{} 270 | 271 | if hKey, err = RegOpenKeyRecFromString(root, win32.KEY_READ); err != nil { 272 | return 273 | } 274 | 275 | for i := uint32(0); err == nil; i++ { 276 | valueNameLen := uint32(MAX_KEY_LENGTH) 277 | err = RegEnumValueW( 278 | hKey, 279 | i, 280 | &valueName[0], 281 | &valueNameLen, 282 | nil, 283 | nil, 284 | nil, 285 | nil, 286 | ) 287 | 288 | if err == nil { 289 | values = append(values, syscall.UTF16ToString(valueName[:])) 290 | } 291 | } 292 | 293 | // means we enumerated all keys 294 | if err == syscall.Errno(win32.ERROR_NO_MORE_ITEMS) { 295 | err = nil 296 | } 297 | 298 | return 299 | } 300 | 301 | func RegEnumKeys(root string) (keys []string, err error) { 302 | var hKey syscall.Handle 303 | 304 | keys = make([]string, 0) 305 | keyName := [MAX_KEY_LENGTH]uint16{} 306 | 307 | if hKey, err = RegOpenKeyRecFromString(root, win32.KEY_READ); err != nil { 308 | return 309 | } 310 | 311 | for i := uint32(0); err == nil; i++ { 312 | keyNameLen := uint32(MAX_KEY_LENGTH) 313 | err = RegEnumKeyExW( 314 | hKey, 315 | i, 316 | &keyName[0], 317 | &keyNameLen, 318 | nil, 319 | nil, 320 | nil, 321 | nil, 322 | ) 323 | 324 | if err == nil { 325 | keys = append(keys, syscall.UTF16ToString(keyName[:])) 326 | } 327 | } 328 | 329 | // means we enumerated all keys 330 | if err == syscall.Errno(win32.ERROR_NO_MORE_ITEMS) { 331 | err = nil 332 | } 333 | 334 | return 335 | } 336 | -------------------------------------------------------------------------------- /win32/dbghelp/dbghelp.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package dbghelp 4 | 5 | import ( 6 | "syscall" 7 | 8 | "github.com/0xrawsec/golang-win32/win32" 9 | "github.com/0xrawsec/golang-win32/win32/kernel32" 10 | ) 11 | 12 | // MiniDumpWriteDump Win32 API wrapper, the three last args are skipped for the moment 13 | func MiniDumpWriteDump(hProcess win32.HANDLE, ProcessId win32.DWORD, 14 | hFile win32.HANDLE, DumpType win32.DWORD) error { 15 | r1, _, lastErr := miniDumpWriteDump.Call(uintptr(hProcess), uintptr(ProcessId), 16 | uintptr(hFile), uintptr(DumpType), win32.NULL, win32.NULL, win32.NULL) 17 | // If function succeed output is TRUE 18 | if r1 == uintptr(win32.TRUE) { 19 | return nil 20 | } 21 | return lastErr 22 | } 23 | 24 | //////////////////////////////// Helpers /////////////////////////////////////// 25 | 26 | // FullMemoryMiniDump helper function to create a FullMemoryMinidump of a process identified by pid 27 | func FullMemoryMiniDump(pid int, dumpFile string) error { 28 | // Define the outfile 29 | hFile, err := syscall.Open(dumpFile, syscall.O_RDWR|syscall.O_CREAT, 0700) 30 | if err != nil { 31 | return err 32 | } 33 | defer syscall.Close(hFile) 34 | 35 | // Open the process with appropriate access rights 36 | da := uint32(kernel32.PROCESS_ALL_ACCESS) 37 | hProcess, err := syscall.OpenProcess(da, false, uint32(pid)) 38 | if err != nil { 39 | return err 40 | } 41 | // Now we can do the minidump 42 | err = MiniDumpWriteDump( 43 | win32.HANDLE(hProcess), // Process Handle 44 | win32.DWORD(pid), // PID of process to dump 45 | win32.HANDLE(hFile), // Dump file Handle 46 | MiniDumpWithFullMemory) // Minidump type 47 | return err 48 | } 49 | -------------------------------------------------------------------------------- /win32/dbghelp/exports.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package dbghelp 4 | 5 | import "syscall" 6 | 7 | var ( 8 | dbghelp = syscall.NewLazyDLL("dbghelp.dll") 9 | symGetOmapBlockBase = dbghelp.NewProc("SymGetOmapBlockBase") 10 | dbgHelpCreateUserDump = dbghelp.NewProc("DbgHelpCreateUserDump") 11 | dbgHelpCreateUserDumpW = dbghelp.NewProc("DbgHelpCreateUserDumpW") 12 | enumDirTree = dbghelp.NewProc("EnumDirTree") 13 | enumDirTreeW = dbghelp.NewProc("EnumDirTreeW") 14 | enumerateLoadedModules = dbghelp.NewProc("EnumerateLoadedModules") 15 | enumerateLoadedModules64 = dbghelp.NewProc("EnumerateLoadedModules64") 16 | enumerateLoadedModulesEx = dbghelp.NewProc("EnumerateLoadedModulesEx") 17 | enumerateLoadedModulesExW = dbghelp.NewProc("EnumerateLoadedModulesExW") 18 | enumerateLoadedModulesW64 = dbghelp.NewProc("EnumerateLoadedModulesW64") 19 | extensionApiVersion = dbghelp.NewProc("ExtensionApiVersion") 20 | findDebugInfoFile = dbghelp.NewProc("FindDebugInfoFile") 21 | findDebugInfoFileEx = dbghelp.NewProc("FindDebugInfoFileEx") 22 | findDebugInfoFileExW = dbghelp.NewProc("FindDebugInfoFileExW") 23 | findExecutableImage = dbghelp.NewProc("FindExecutableImage") 24 | findExecutableImageEx = dbghelp.NewProc("FindExecutableImageEx") 25 | findExecutableImageExW = dbghelp.NewProc("FindExecutableImageExW") 26 | findFileInPath = dbghelp.NewProc("FindFileInPath") 27 | findFileInSearchPath = dbghelp.NewProc("FindFileInSearchPath") 28 | getTimestampForLoadedLibrary = dbghelp.NewProc("GetTimestampForLoadedLibrary") 29 | imageDirectoryEntryToData = dbghelp.NewProc("ImageDirectoryEntryToData") 30 | imageDirectoryEntryToDataEx = dbghelp.NewProc("ImageDirectoryEntryToDataEx") 31 | imageNtHeader = dbghelp.NewProc("ImageNtHeader") 32 | imageRvaToSection = dbghelp.NewProc("ImageRvaToSection") 33 | imageRvaToVa = dbghelp.NewProc("ImageRvaToVa") 34 | imagehlpApiVersion = dbghelp.NewProc("ImagehlpApiVersion") 35 | imagehlpApiVersionEx = dbghelp.NewProc("ImagehlpApiVersionEx") 36 | makeSureDirectoryPathExists = dbghelp.NewProc("MakeSureDirectoryPathExists") 37 | miniDumpReadDumpStream = dbghelp.NewProc("MiniDumpReadDumpStream") 38 | miniDumpWriteDump = dbghelp.NewProc("MiniDumpWriteDump") 39 | searchTreeForFile = dbghelp.NewProc("SearchTreeForFile") 40 | searchTreeForFileW = dbghelp.NewProc("SearchTreeForFileW") 41 | stackWalk = dbghelp.NewProc("StackWalk") 42 | stackWalk64 = dbghelp.NewProc("StackWalk64") 43 | symAddSourceStream = dbghelp.NewProc("SymAddSourceStream") 44 | symAddSourceStreamA = dbghelp.NewProc("SymAddSourceStreamA") 45 | symAddSourceStreamW = dbghelp.NewProc("SymAddSourceStreamW") 46 | symAddSymbol = dbghelp.NewProc("SymAddSymbol") 47 | symAddSymbolW = dbghelp.NewProc("SymAddSymbolW") 48 | symCleanup = dbghelp.NewProc("SymCleanup") 49 | symDeleteSymbol = dbghelp.NewProc("SymDeleteSymbol") 50 | symDeleteSymbolW = dbghelp.NewProc("SymDeleteSymbolW") 51 | symEnumLines = dbghelp.NewProc("SymEnumLines") 52 | symEnumLinesW = dbghelp.NewProc("SymEnumLinesW") 53 | symEnumProcesses = dbghelp.NewProc("SymEnumProcesses") 54 | symEnumSourceFileTokens = dbghelp.NewProc("SymEnumSourceFileTokens") 55 | symEnumSourceFiles = dbghelp.NewProc("SymEnumSourceFiles") 56 | symEnumSourceFilesW = dbghelp.NewProc("SymEnumSourceFilesW") 57 | symEnumSourceLines = dbghelp.NewProc("SymEnumSourceLines") 58 | symEnumSourceLinesW = dbghelp.NewProc("SymEnumSourceLinesW") 59 | symEnumSym = dbghelp.NewProc("SymEnumSym") 60 | symEnumSymbols = dbghelp.NewProc("SymEnumSymbols") 61 | symEnumSymbolsForAddr = dbghelp.NewProc("SymEnumSymbolsForAddr") 62 | symEnumSymbolsForAddrW = dbghelp.NewProc("SymEnumSymbolsForAddrW") 63 | symEnumSymbolsW = dbghelp.NewProc("SymEnumSymbolsW") 64 | symEnumTypes = dbghelp.NewProc("SymEnumTypes") 65 | symEnumTypesByName = dbghelp.NewProc("SymEnumTypesByName") 66 | symEnumTypesByNameW = dbghelp.NewProc("SymEnumTypesByNameW") 67 | symEnumTypesW = dbghelp.NewProc("SymEnumTypesW") 68 | symEnumerateModules = dbghelp.NewProc("SymEnumerateModules") 69 | symEnumerateModules64 = dbghelp.NewProc("SymEnumerateModules64") 70 | symEnumerateModulesW64 = dbghelp.NewProc("SymEnumerateModulesW64") 71 | symEnumerateSymbols = dbghelp.NewProc("SymEnumerateSymbols") 72 | symEnumerateSymbols64 = dbghelp.NewProc("SymEnumerateSymbols64") 73 | symEnumerateSymbolsW = dbghelp.NewProc("SymEnumerateSymbolsW") 74 | symEnumerateSymbolsW64 = dbghelp.NewProc("SymEnumerateSymbolsW64") 75 | symFindDebugInfoFile = dbghelp.NewProc("SymFindDebugInfoFile") 76 | symFindDebugInfoFileW = dbghelp.NewProc("SymFindDebugInfoFileW") 77 | symFindExecutableImage = dbghelp.NewProc("SymFindExecutableImage") 78 | symFindExecutableImageW = dbghelp.NewProc("SymFindExecutableImageW") 79 | symFindFileInPath = dbghelp.NewProc("SymFindFileInPath") 80 | symFindFileInPathW = dbghelp.NewProc("SymFindFileInPathW") 81 | symFromAddr = dbghelp.NewProc("SymFromAddr") 82 | symFromAddrW = dbghelp.NewProc("SymFromAddrW") 83 | symFromIndex = dbghelp.NewProc("SymFromIndex") 84 | symFromIndexW = dbghelp.NewProc("SymFromIndexW") 85 | symFromName = dbghelp.NewProc("SymFromName") 86 | symFromNameW = dbghelp.NewProc("SymFromNameW") 87 | symFromToken = dbghelp.NewProc("SymFromToken") 88 | symFromTokenW = dbghelp.NewProc("SymFromTokenW") 89 | symFunctionTableAccess = dbghelp.NewProc("SymFunctionTableAccess") 90 | symFunctionTableAccess64 = dbghelp.NewProc("SymFunctionTableAccess64") 91 | symGetFileLineOffsets64 = dbghelp.NewProc("SymGetFileLineOffsets64") 92 | symGetHomeDirectory = dbghelp.NewProc("SymGetHomeDirectory") 93 | symGetHomeDirectoryW = dbghelp.NewProc("SymGetHomeDirectoryW") 94 | symGetLineFromAddr = dbghelp.NewProc("SymGetLineFromAddr") 95 | symGetLineFromAddr64 = dbghelp.NewProc("SymGetLineFromAddr64") 96 | symGetLineFromAddrW64 = dbghelp.NewProc("SymGetLineFromAddrW64") 97 | symGetLineFromName = dbghelp.NewProc("SymGetLineFromName") 98 | symGetLineFromName64 = dbghelp.NewProc("SymGetLineFromName64") 99 | symGetLineFromNameW64 = dbghelp.NewProc("SymGetLineFromNameW64") 100 | symGetLineNext = dbghelp.NewProc("SymGetLineNext") 101 | symGetLineNext64 = dbghelp.NewProc("SymGetLineNext64") 102 | symGetLineNextW64 = dbghelp.NewProc("SymGetLineNextW64") 103 | symGetLinePrev = dbghelp.NewProc("SymGetLinePrev") 104 | symGetLinePrev64 = dbghelp.NewProc("SymGetLinePrev64") 105 | symGetLinePrevW64 = dbghelp.NewProc("SymGetLinePrevW64") 106 | symGetModuleBase = dbghelp.NewProc("SymGetModuleBase") 107 | symGetModuleBase64 = dbghelp.NewProc("SymGetModuleBase64") 108 | symGetModuleInfo = dbghelp.NewProc("SymGetModuleInfo") 109 | symGetModuleInfo64 = dbghelp.NewProc("SymGetModuleInfo64") 110 | symGetModuleInfoW = dbghelp.NewProc("SymGetModuleInfoW") 111 | symGetModuleInfoW64 = dbghelp.NewProc("SymGetModuleInfoW64") 112 | symGetOmaps = dbghelp.NewProc("SymGetOmaps") 113 | symGetOptions = dbghelp.NewProc("SymGetOptions") 114 | symGetScope = dbghelp.NewProc("SymGetScope") 115 | symGetScopeW = dbghelp.NewProc("SymGetScopeW") 116 | symGetSearchPath = dbghelp.NewProc("SymGetSearchPath") 117 | symGetSearchPathW = dbghelp.NewProc("SymGetSearchPathW") 118 | symGetSourceFile = dbghelp.NewProc("SymGetSourceFile") 119 | symGetSourceFileFromToken = dbghelp.NewProc("SymGetSourceFileFromToken") 120 | symGetSourceFileFromTokenW = dbghelp.NewProc("SymGetSourceFileFromTokenW") 121 | symGetSourceFileToken = dbghelp.NewProc("SymGetSourceFileToken") 122 | symGetSourceFileTokenW = dbghelp.NewProc("SymGetSourceFileTokenW") 123 | symGetSourceFileW = dbghelp.NewProc("SymGetSourceFileW") 124 | symGetSourceVarFromToken = dbghelp.NewProc("SymGetSourceVarFromToken") 125 | symGetSourceVarFromTokenW = dbghelp.NewProc("SymGetSourceVarFromTokenW") 126 | symGetSymFromAddr = dbghelp.NewProc("SymGetSymFromAddr") 127 | symGetSymFromAddr64 = dbghelp.NewProc("SymGetSymFromAddr64") 128 | symGetSymFromName = dbghelp.NewProc("SymGetSymFromName") 129 | symGetSymFromName64 = dbghelp.NewProc("SymGetSymFromName64") 130 | symGetSymNext = dbghelp.NewProc("SymGetSymNext") 131 | symGetSymNext64 = dbghelp.NewProc("SymGetSymNext64") 132 | symGetSymPrev = dbghelp.NewProc("SymGetSymPrev") 133 | symGetSymPrev64 = dbghelp.NewProc("SymGetSymPrev64") 134 | symGetSymbolFile = dbghelp.NewProc("SymGetSymbolFile") 135 | symGetSymbolFileW = dbghelp.NewProc("SymGetSymbolFileW") 136 | symGetTypeFromName = dbghelp.NewProc("SymGetTypeFromName") 137 | symGetTypeFromNameW = dbghelp.NewProc("SymGetTypeFromNameW") 138 | symGetTypeInfo = dbghelp.NewProc("SymGetTypeInfo") 139 | symGetTypeInfoEx = dbghelp.NewProc("SymGetTypeInfoEx") 140 | symGetUnwindInfo = dbghelp.NewProc("SymGetUnwindInfo") 141 | symInitialize = dbghelp.NewProc("SymInitialize") 142 | symInitializeW = dbghelp.NewProc("SymInitializeW") 143 | symLoadModule = dbghelp.NewProc("SymLoadModule") 144 | symLoadModule64 = dbghelp.NewProc("SymLoadModule64") 145 | symLoadModuleEx = dbghelp.NewProc("SymLoadModuleEx") 146 | symLoadModuleExW = dbghelp.NewProc("SymLoadModuleExW") 147 | symMatchFileName = dbghelp.NewProc("SymMatchFileName") 148 | symMatchFileNameW = dbghelp.NewProc("SymMatchFileNameW") 149 | symMatchString = dbghelp.NewProc("SymMatchString") 150 | symMatchStringA = dbghelp.NewProc("SymMatchStringA") 151 | symMatchStringW = dbghelp.NewProc("SymMatchStringW") 152 | symNext = dbghelp.NewProc("SymNext") 153 | symNextW = dbghelp.NewProc("SymNextW") 154 | symPrev = dbghelp.NewProc("SymPrev") 155 | symPrevW = dbghelp.NewProc("SymPrevW") 156 | symRefreshModuleList = dbghelp.NewProc("SymRefreshModuleList") 157 | symRegisterCallback = dbghelp.NewProc("SymRegisterCallback") 158 | symRegisterCallback64 = dbghelp.NewProc("SymRegisterCallback64") 159 | symRegisterCallbackW64 = dbghelp.NewProc("SymRegisterCallbackW64") 160 | symRegisterFunctionEntryCallback = dbghelp.NewProc("SymRegisterFunctionEntryCallback") 161 | symRegisterFunctionEntryCallback64 = dbghelp.NewProc("SymRegisterFunctionEntryCallback64") 162 | symSearch = dbghelp.NewProc("SymSearch") 163 | symSearchW = dbghelp.NewProc("SymSearchW") 164 | symSetContext = dbghelp.NewProc("SymSetContext") 165 | symSetHomeDirectory = dbghelp.NewProc("SymSetHomeDirectory") 166 | symSetHomeDirectoryW = dbghelp.NewProc("SymSetHomeDirectoryW") 167 | symSetOptions = dbghelp.NewProc("SymSetOptions") 168 | symSetParentWindow = dbghelp.NewProc("SymSetParentWindow") 169 | symSetScopeFromAddr = dbghelp.NewProc("SymSetScopeFromAddr") 170 | symSetScopeFromIndex = dbghelp.NewProc("SymSetScopeFromIndex") 171 | symSetSearchPath = dbghelp.NewProc("SymSetSearchPath") 172 | symSetSearchPathW = dbghelp.NewProc("SymSetSearchPathW") 173 | symSrvDeltaName = dbghelp.NewProc("SymSrvDeltaName") 174 | symSrvDeltaNameW = dbghelp.NewProc("SymSrvDeltaNameW") 175 | symSrvGetFileIndexInfo = dbghelp.NewProc("SymSrvGetFileIndexInfo") 176 | symSrvGetFileIndexInfoW = dbghelp.NewProc("SymSrvGetFileIndexInfoW") 177 | symSrvGetFileIndexString = dbghelp.NewProc("SymSrvGetFileIndexString") 178 | symSrvGetFileIndexStringW = dbghelp.NewProc("SymSrvGetFileIndexStringW") 179 | symSrvGetFileIndexes = dbghelp.NewProc("SymSrvGetFileIndexes") 180 | symSrvGetFileIndexesW = dbghelp.NewProc("SymSrvGetFileIndexesW") 181 | symSrvGetSupplement = dbghelp.NewProc("SymSrvGetSupplement") 182 | symSrvGetSupplementW = dbghelp.NewProc("SymSrvGetSupplementW") 183 | symSrvIsStore = dbghelp.NewProc("SymSrvIsStore") 184 | symSrvIsStoreW = dbghelp.NewProc("SymSrvIsStoreW") 185 | symSrvStoreFile = dbghelp.NewProc("SymSrvStoreFile") 186 | symSrvStoreFileW = dbghelp.NewProc("SymSrvStoreFileW") 187 | symSrvStoreSupplement = dbghelp.NewProc("SymSrvStoreSupplement") 188 | symSrvStoreSupplementW = dbghelp.NewProc("SymSrvStoreSupplementW") 189 | symUnDName = dbghelp.NewProc("SymUnDName") 190 | symUnDName64 = dbghelp.NewProc("SymUnDName64") 191 | symUnloadModule = dbghelp.NewProc("SymUnloadModule") 192 | symUnloadModule64 = dbghelp.NewProc("SymUnloadModule64") 193 | unDecorateSymbolName = dbghelp.NewProc("UnDecorateSymbolName") 194 | unDecorateSymbolNameW = dbghelp.NewProc("UnDecorateSymbolNameW") 195 | winDbgExtensionDllInit = dbghelp.NewProc("WinDbgExtensionDllInit") 196 | ) 197 | -------------------------------------------------------------------------------- /win32/dbghelp/header.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package dbghelp 4 | 5 | const ( 6 | MiniDumpNormal = 0x00000000 7 | MiniDumpWithDataSegs = 0x00000001 8 | MiniDumpWithFullMemory = 0x00000002 9 | MiniDumpWithHandleData = 0x00000004 10 | MiniDumpFilterMemory = 0x00000008 11 | MiniDumpScanMemory = 0x00000010 12 | MiniDumpWithUnloadedModules = 0x00000020 13 | MiniDumpWithIndirectlyReferencedMemory = 0x00000040 14 | MiniDumpFilterModulePaths = 0x00000080 15 | MiniDumpWithProcessThreadData = 0x00000100 16 | MiniDumpWithPrivateReadWriteMemory = 0x00000200 17 | MiniDumpWithoutOptionalData = 0x00000400 18 | MiniDumpWithFullMemoryInfo = 0x00000800 19 | MiniDumpWithThreadInfo = 0x00001000 20 | MiniDumpWithCodeSegs = 0x00002000 21 | MiniDumpWithoutAuxiliaryState = 0x00004000 22 | MiniDumpWithFullAuxiliaryState = 0x00008000 23 | MiniDumpWithPrivateWriteCopyMemory = 0x00010000 24 | MiniDumpIgnoreInaccessibleMemory = 0x00020000 25 | MiniDumpWithTokenInformation = 0x00040000 26 | MiniDumpWithModuleHeaders = 0x00080000 27 | MiniDumpFilterTriage = 0x00100000 28 | MiniDumpValidTypeFlags = 0x001fffff 29 | ) 30 | -------------------------------------------------------------------------------- /win32/dbghelp/test/dbghelp_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "testing" 7 | 8 | "github.com/0xrawsec/golang-win32/win32" 9 | "github.com/0xrawsec/golang-win32/win32/dbghelp" 10 | "github.com/0xrawsec/golang-win32/win32/kernel32" 11 | ) 12 | 13 | func TestMiniDumpWriteDump(t *testing.T) { 14 | outfile := "minidump.dmp" 15 | // Fork process first because not good idea to minidump the current process 16 | // It does not work to minidump a process created with CREATE_SUSPENDED flag 17 | name, err := syscall.UTF16PtrFromString(`C:\Windows\System32\cmd.exe`) 18 | if err != nil { 19 | panic(err) 20 | } 21 | si := new(syscall.StartupInfo) 22 | pi := new(syscall.ProcessInformation) 23 | t.Logf("Creating new process: %s", os.Args[0]) 24 | err = syscall.CreateProcess(name, nil, nil, nil, false, win32.CREATE_NO_WINDOW, nil, nil, si, pi) 25 | if err != nil { 26 | panic(err) 27 | } 28 | defer func() { 29 | syscall.TerminateProcess(pi.Process, 0) 30 | }() 31 | 32 | os.Remove(outfile) 33 | 34 | // Define the outfile 35 | hFile, err := syscall.Open(outfile, syscall.O_RDWR|syscall.O_CREAT, 0777) 36 | if err != nil { 37 | panic(err) 38 | } 39 | 40 | // Get proper process accesses 41 | pid := uint32(pi.ProcessId) 42 | //da := uint32(kernel32.PROCESS_ALL_ACCESS | kernel32.PROCESS_VM_READ | kernel32.PROCESS_QUERY_INFORMATION | kernel32.PROCESS_DUP_HANDLE) 43 | da := uint32(kernel32.PROCESS_ALL_ACCESS) 44 | hProcess, err := syscall.OpenProcess(da, false, pid) 45 | if err != nil { 46 | panic(err) 47 | } 48 | 49 | // Now we can do the minidump 50 | err = dbghelp.MiniDumpWriteDump(win32.HANDLE(hProcess), 51 | win32.DWORD(pid), 52 | win32.HANDLE(hFile), 53 | dbghelp.MiniDumpWithFullMemory) 54 | 55 | if err != nil { 56 | panic(err) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /win32/fltlib/exports.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package fltlib 4 | 5 | import "syscall" 6 | 7 | var ( 8 | fltlib = syscall.NewLazyDLL("fltlib.dll") 9 | filterAttach = fltlib.NewProc("FilterAttach") 10 | filterAttachAtAltitude = fltlib.NewProc("FilterAttachAtAltitude") 11 | filterClose = fltlib.NewProc("FilterClose") 12 | filterConnectCommunicationPort = fltlib.NewProc("FilterConnectCommunicationPort") 13 | filterCreate = fltlib.NewProc("FilterCreate") 14 | filterDetach = fltlib.NewProc("FilterDetach") 15 | filterFindClose = fltlib.NewProc("FilterFindClose") 16 | filterFindFirst = fltlib.NewProc("FilterFindFirst") 17 | filterFindNext = fltlib.NewProc("FilterFindNext") 18 | filterGetDosName = fltlib.NewProc("FilterGetDosName") 19 | filterGetInformation = fltlib.NewProc("FilterGetInformation") 20 | filterGetMessage = fltlib.NewProc("FilterGetMessage") 21 | filterInstanceClose = fltlib.NewProc("FilterInstanceClose") 22 | filterInstanceCreate = fltlib.NewProc("FilterInstanceCreate") 23 | filterInstanceFindClose = fltlib.NewProc("FilterInstanceFindClose") 24 | filterInstanceFindFirst = fltlib.NewProc("FilterInstanceFindFirst") 25 | filterInstanceFindNext = fltlib.NewProc("FilterInstanceFindNext") 26 | filterInstanceGetInformation = fltlib.NewProc("FilterInstanceGetInformation") 27 | filterLoad = fltlib.NewProc("FilterLoad") 28 | filterReplyMessage = fltlib.NewProc("FilterReplyMessage") 29 | filterSendMessage = fltlib.NewProc("FilterSendMessage") 30 | filterUnload = fltlib.NewProc("FilterUnload") 31 | filterVolumeClose = fltlib.NewProc("FilterVolumeClose") 32 | filterVolumeFindClose = fltlib.NewProc("FilterVolumeFindClose") 33 | filterVolumeFindFirst = fltlib.NewProc("FilterVolumeFindFirst") 34 | filterVolumeFindNext = fltlib.NewProc("FilterVolumeFindNext") 35 | filterVolumeInstanceFindClose = fltlib.NewProc("FilterVolumeInstanceFindClose") 36 | filterVolumeInstanceFindFirst = fltlib.NewProc("FilterVolumeInstanceFindFirst") 37 | filterVolumeInstanceFindNext = fltlib.NewProc("FilterVolumeInstanceFindNext") 38 | ) 39 | -------------------------------------------------------------------------------- /win32/fltlib/fltlib.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package fltlib 4 | 5 | import ( 6 | "syscall" 7 | "unsafe" 8 | ) 9 | 10 | /* 11 | FilterAttach API wrapper generated from prototype 12 | HRESULT WINAPI FilterAttach( 13 | LPCWSTR lpFilterName, 14 | LPCWSTR lpVolumeName, 15 | LPCWSTR lpInstanceName, 16 | DWORD dwCreatedInstanceNameLength, 17 | LPWSTR lpCreatedInstanceName); 18 | */ 19 | func FilterAttach(lpFilterName *uint16, 20 | lpVolumeName *uint16, 21 | lpInstanceName *uint16, 22 | dwCreatedInstanceNameLength uint32, 23 | lpCreatedInstanceName *uint16) (int32, error) { 24 | r1, _, err := filterAttach.Call( 25 | uintptr(unsafe.Pointer(lpFilterName)), 26 | uintptr(unsafe.Pointer(lpVolumeName)), 27 | uintptr(unsafe.Pointer(lpInstanceName)), 28 | uintptr(dwCreatedInstanceNameLength), 29 | uintptr(unsafe.Pointer(lpCreatedInstanceName))) 30 | if err.(syscall.Errno) == 0 { 31 | return int32(r1), nil 32 | } 33 | return int32(r1), err 34 | } 35 | 36 | /* 37 | FilterAttachAtAltitude API wrapper generated from prototype 38 | HRESULT WINAPI FilterAttachAtAltitude( 39 | LPCWSTR lpFilterName, 40 | LPCWSTR lpVolumeName, 41 | LPCWSTR lpAltitude, 42 | LPCWSTR lpInstanceName, 43 | DWORD dwCreatedInstanceNameLength, 44 | LPWSTR lpCreatedInstanceName); 45 | */ 46 | func FilterAttachAtAltitude(lpFilterName *uint16, 47 | lpVolumeName *uint16, 48 | lpAltitude *uint16, 49 | lpInstanceName *uint16, 50 | dwCreatedInstanceNameLength uint32, 51 | lpCreatedInstanceName *uint16) (int32, error) { 52 | r1, _, err := filterAttachAtAltitude.Call( 53 | uintptr(unsafe.Pointer(lpFilterName)), 54 | uintptr(unsafe.Pointer(lpVolumeName)), 55 | uintptr(unsafe.Pointer(lpAltitude)), 56 | uintptr(unsafe.Pointer(lpInstanceName)), 57 | uintptr(dwCreatedInstanceNameLength), 58 | uintptr(unsafe.Pointer(lpCreatedInstanceName))) 59 | if err.(syscall.Errno) == 0 { 60 | return int32(r1), nil 61 | } 62 | return int32(r1), err 63 | } 64 | 65 | /* 66 | FilterClose API wrapper generated from prototype 67 | HRESULT WINAPI FilterClose( 68 | HFILTER hFilter); 69 | */ 70 | func FilterClose(hFilter syscall.Handle) (int32, error) { 71 | r1, _, err := filterClose.Call( 72 | uintptr(hFilter)) 73 | if err.(syscall.Errno) == 0 { 74 | return int32(r1), nil 75 | } 76 | return int32(r1), err 77 | } 78 | 79 | /* 80 | FilterConnectCommunicationPort API wrapper generated from prototype 81 | HRESULT WINAPI FilterConnectCommunicationPort( 82 | LPCWSTR lpPortName, 83 | DWORD dwOptions, 84 | LPCVOID lpContext, 85 | WORD wSizeOfContext, 86 | LPSECURITY_ATTRIBUTES lpSecurityAttributes, 87 | HANDLE *hPort); 88 | */ 89 | func FilterConnectCommunicationPort(lpPortName *uint16, 90 | dwOptions uint32, 91 | lpContext uintptr, 92 | wSizeOfContext uint16, 93 | lpSecurityAttributes LpsecurityAttributes, 94 | hPort *syscall.Handle) (int32, error) { 95 | r1, _, err := filterConnectCommunicationPort.Call( 96 | uintptr(unsafe.Pointer(lpPortName)), 97 | uintptr(dwOptions), 98 | uintptr(lpContext), 99 | uintptr(wSizeOfContext), 100 | uintptr(lpSecurityAttributes), 101 | uintptr(unsafe.Pointer(hPort))) 102 | if err.(syscall.Errno) == 0 { 103 | return int32(r1), nil 104 | } 105 | return int32(r1), err 106 | } 107 | 108 | /* 109 | FilterCreate API wrapper generated from prototype 110 | HRESULT WINAPI FilterCreate( 111 | LPCWSTR lpFilterName, 112 | HFILTER *hFilter); 113 | */ 114 | func FilterCreate(lpFilterName *uint16, 115 | hFilter *syscall.Handle) (int32, error) { 116 | r1, _, err := filterCreate.Call( 117 | uintptr(unsafe.Pointer(lpFilterName)), 118 | uintptr(unsafe.Pointer(hFilter))) 119 | if err.(syscall.Errno) == 0 { 120 | return int32(r1), nil 121 | } 122 | return int32(r1), err 123 | } 124 | 125 | /* 126 | FilterDetach API wrapper generated from prototype 127 | HRESULT WINAPI FilterDetach( 128 | LPCWSTR lpFilterName, 129 | LPCWSTR lpVolumeName, 130 | LPCWSTR lpInstanceName); 131 | */ 132 | func FilterDetach(lpFilterName *uint16, 133 | lpVolumeName *uint16, 134 | lpInstanceName *uint16) (int32, error) { 135 | r1, _, err := filterDetach.Call( 136 | uintptr(unsafe.Pointer(lpFilterName)), 137 | uintptr(unsafe.Pointer(lpVolumeName)), 138 | uintptr(unsafe.Pointer(lpInstanceName))) 139 | if err.(syscall.Errno) == 0 { 140 | return int32(r1), nil 141 | } 142 | return int32(r1), err 143 | } 144 | 145 | /* 146 | FilterFindClose API wrapper generated from prototype 147 | HRESULT WINAPI FilterFindClose( 148 | HANDLE hFilterFind); 149 | */ 150 | func FilterFindClose(hFilterFind syscall.Handle) (int32, error) { 151 | r1, _, err := filterFindClose.Call( 152 | uintptr(hFilterFind)) 153 | if err.(syscall.Errno) == 0 { 154 | return int32(r1), nil 155 | } 156 | return int32(r1), err 157 | } 158 | 159 | /* 160 | FilterFindFirst API wrapper generated from prototype 161 | HRESULT WINAPI FilterFindFirst( 162 | FILTER_INFORMATION_CLASS dwInformationClass, 163 | LPVOID lpBuffer, 164 | DWORD dwBufferSize, 165 | LPDWORD lpBytesReturned, 166 | LPHANDLE lpFilterFind); 167 | */ 168 | func FilterFindFirst(dwInformationClass FilterInformationClass, 169 | lpBuffer uintptr, 170 | dwBufferSize uint32, 171 | lpBytesReturned *uint32, 172 | lpFilterFind *syscall.Handle) (int32, error) { 173 | r1, _, err := filterFindFirst.Call( 174 | uintptr(dwInformationClass), 175 | uintptr(lpBuffer), 176 | uintptr(dwBufferSize), 177 | uintptr(unsafe.Pointer(lpBytesReturned)), 178 | uintptr(lpFilterFind)) 179 | if err.(syscall.Errno) == 0 { 180 | return int32(r1), nil 181 | } 182 | return int32(r1), err 183 | } 184 | 185 | /* 186 | FilterFindNext API wrapper generated from prototype 187 | HRESULT WINAPI FilterFindNext( 188 | HANDLE hFilterFind, 189 | FILTER_INFORMATION_CLASS dwInformationClass, 190 | LPVOID lpBuffer, 191 | DWORD dwBufferSize, 192 | LPDWORD lpBytesReturned); 193 | */ 194 | func FilterFindNext(hFilterFind syscall.Handle, 195 | dwInformationClass FilterInformationClass, 196 | lpBuffer uintptr, 197 | dwBufferSize uint32, 198 | lpBytesReturned *uint32) (int32, error) { 199 | r1, _, err := filterFindNext.Call( 200 | uintptr(hFilterFind), 201 | uintptr(dwInformationClass), 202 | uintptr(lpBuffer), 203 | uintptr(dwBufferSize), 204 | uintptr(unsafe.Pointer(lpBytesReturned))) 205 | if err.(syscall.Errno) == 0 { 206 | return int32(r1), nil 207 | } 208 | return int32(r1), err 209 | } 210 | 211 | /* 212 | FilterGetDosName API wrapper generated from prototype 213 | HRESULT WINAPI FilterGetDosName( 214 | LPCWSTR lpVolumeName, 215 | LPWSTR lpDosName, 216 | DWORD dwDosNameBufferSize); 217 | */ 218 | func FilterGetDosName(lpVolumeName *uint16, 219 | lpDosName *uint16, 220 | dwDosNameBufferSize uint32) (int32, error) { 221 | r1, _, err := filterGetDosName.Call( 222 | uintptr(unsafe.Pointer(lpVolumeName)), 223 | uintptr(unsafe.Pointer(lpDosName)), 224 | uintptr(dwDosNameBufferSize)) 225 | if err.(syscall.Errno) == 0 { 226 | return int32(r1), nil 227 | } 228 | return int32(r1), err 229 | } 230 | 231 | /* 232 | FilterGetInformation API wrapper generated from prototype 233 | HRESULT WINAPI FilterGetInformation( 234 | HFILTER hFilter, 235 | FILTER_INFORMATION_CLASS dwInformationClass, 236 | LPVOID lpBuffer, 237 | DWORD dwBufferSize, 238 | LPDWORD lpBytesReturned); 239 | */ 240 | func FilterGetInformation(hFilter syscall.Handle, 241 | dwInformationClass FilterInformationClass, 242 | lpBuffer uintptr, 243 | dwBufferSize uint32, 244 | lpBytesReturned *uint32) (int32, error) { 245 | r1, _, err := filterGetInformation.Call( 246 | uintptr(hFilter), 247 | uintptr(dwInformationClass), 248 | uintptr(lpBuffer), 249 | uintptr(dwBufferSize), 250 | uintptr(unsafe.Pointer(lpBytesReturned))) 251 | if err.(syscall.Errno) == 0 { 252 | return int32(r1), nil 253 | } 254 | return int32(r1), err 255 | } 256 | 257 | /* 258 | FilterGetMessage API wrapper generated from prototype 259 | HRESULT WINAPI FilterGetMessage( 260 | HANDLE hPort, 261 | PFILTER_MESSAGE_HEADER lpMessageBuffer, 262 | DWORD dwMessageBufferSize, 263 | LPOVERLAPPED lpOverlapped); 264 | */ 265 | func FilterGetMessage(hPort syscall.Handle, 266 | lpMessageBuffer *FilterMessageHeader, 267 | dwMessageBufferSize uint32, 268 | lpOverlapped LPOVERLAPPED) (int32, error) { 269 | r1, _, err := filterGetMessage.Call( 270 | uintptr(hPort), 271 | uintptr(unsafe.Pointer(lpMessageBuffer)), 272 | uintptr(dwMessageBufferSize), 273 | uintptr(lpOverlapped)) 274 | if err.(syscall.Errno) == 0 { 275 | return int32(r1), nil 276 | } 277 | return int32(r1), err 278 | } 279 | 280 | /* 281 | FilterInstanceClose API wrapper generated from prototype 282 | HRESULT WINAPI FilterInstanceClose( 283 | HFILTER_INSTANCE hInstance); 284 | */ 285 | func FilterInstanceClose(hInstance HfilterInstance) (int32, error) { 286 | r1, _, err := filterInstanceClose.Call( 287 | uintptr(hInstance)) 288 | if err.(syscall.Errno) == 0 { 289 | return int32(r1), nil 290 | } 291 | return int32(r1), err 292 | } 293 | 294 | /* 295 | FilterInstanceCreate API wrapper generated from prototype 296 | HRESULT WINAPI FilterInstanceCreate( 297 | LPCWSTR lpFilterName, 298 | LPCWSTR lpVolumeName, 299 | LPCWSTR lpInstanceName, 300 | HFILTER_INSTANCE *hInstance); 301 | */ 302 | func FilterInstanceCreate(lpFilterName *uint16, 303 | lpVolumeName *uint16, 304 | lpInstanceName *uint16, 305 | hInstance *HfilterInstance) (int32, error) { 306 | r1, _, err := filterInstanceCreate.Call( 307 | uintptr(unsafe.Pointer(lpFilterName)), 308 | uintptr(unsafe.Pointer(lpVolumeName)), 309 | uintptr(unsafe.Pointer(lpInstanceName)), 310 | uintptr(unsafe.Pointer(hInstance))) 311 | if err.(syscall.Errno) == 0 { 312 | return int32(r1), nil 313 | } 314 | return int32(r1), err 315 | } 316 | 317 | /* 318 | FilterInstanceFindClose API wrapper generated from prototype 319 | HRESULT WINAPI FilterInstanceFindClose( 320 | HANDLE hFilterInstanceFind); 321 | */ 322 | func FilterInstanceFindClose(hFilterInstanceFind syscall.Handle) (int32, error) { 323 | r1, _, err := filterInstanceFindClose.Call( 324 | uintptr(hFilterInstanceFind)) 325 | if err.(syscall.Errno) == 0 { 326 | return int32(r1), nil 327 | } 328 | return int32(r1), err 329 | } 330 | 331 | /* 332 | FilterInstanceFindFirst API wrapper generated from prototype 333 | HRESULT WINAPI FilterInstanceFindFirst( 334 | LPCWSTR lpFilterName, 335 | INSTANCE_INFORMATION_CLASS dwInformationClass, 336 | LPVOID lpBuffer, 337 | DWORD dwBufferSize, 338 | LPDWORD lpBytesReturned, 339 | LPHANDLE lpFilterInstanceFind); 340 | */ 341 | func FilterInstanceFindFirst(lpFilterName *uint16, 342 | dwInformationClass InstanceInformationClass, 343 | lpBuffer uintptr, 344 | dwBufferSize uint32, 345 | lpBytesReturned *uint32, 346 | lpFilterInstanceFind *syscall.Handle) (int32, error) { 347 | r1, _, err := filterInstanceFindFirst.Call( 348 | uintptr(unsafe.Pointer(lpFilterName)), 349 | uintptr(dwInformationClass), 350 | uintptr(lpBuffer), 351 | uintptr(dwBufferSize), 352 | uintptr(unsafe.Pointer(lpBytesReturned)), 353 | uintptr(lpFilterInstanceFind)) 354 | if err.(syscall.Errno) == 0 { 355 | return int32(r1), nil 356 | } 357 | return int32(r1), err 358 | } 359 | 360 | /* 361 | FilterInstanceFindNext API wrapper generated from prototype 362 | HRESULT WINAPI FilterInstanceFindNext( 363 | HANDLE hFilterInstanceFind, 364 | INSTANCE_INFORMATION_CLASS dwInformationClass, 365 | LPVOID lpBuffer, 366 | DWORD dwBufferSize, 367 | LPDWORD lpBytesReturned); 368 | */ 369 | func FilterInstanceFindNext(hFilterInstanceFind syscall.Handle, 370 | dwInformationClass InstanceInformationClass, 371 | lpBuffer uintptr, 372 | dwBufferSize uint32, 373 | lpBytesReturned *uint32) (int32, error) { 374 | r1, _, err := filterInstanceFindNext.Call( 375 | uintptr(hFilterInstanceFind), 376 | uintptr(dwInformationClass), 377 | uintptr(lpBuffer), 378 | uintptr(dwBufferSize), 379 | uintptr(unsafe.Pointer(lpBytesReturned))) 380 | if err.(syscall.Errno) == 0 { 381 | return int32(r1), nil 382 | } 383 | return int32(r1), err 384 | } 385 | 386 | /* 387 | FilterInstanceGetInformation API wrapper generated from prototype 388 | HRESULT WINAPI FilterInstanceGetInformation( 389 | HFILTER_INSTANCE hInstance, 390 | INSTANCE_INFORMATION_CLASS dwInformationClass, 391 | LPVOID lpBuffer, 392 | DWORD dwBufferSize, 393 | LPDWORD lpBytesReturned); 394 | */ 395 | func FilterInstanceGetInformation(hInstance HfilterInstance, 396 | dwInformationClass InstanceInformationClass, 397 | lpBuffer uintptr, 398 | dwBufferSize uint32, 399 | lpBytesReturned *uint32) (int32, error) { 400 | r1, _, err := filterInstanceGetInformation.Call( 401 | uintptr(hInstance), 402 | uintptr(dwInformationClass), 403 | uintptr(lpBuffer), 404 | uintptr(dwBufferSize), 405 | uintptr(unsafe.Pointer(lpBytesReturned))) 406 | if err.(syscall.Errno) == 0 { 407 | return int32(r1), nil 408 | } 409 | return int32(r1), err 410 | } 411 | 412 | /* 413 | FilterLoad API wrapper generated from prototype 414 | HRESULT WINAPI FilterLoad( 415 | LPCWSTR lpFilterName); 416 | */ 417 | func FilterLoad(lpFilterName *uint16) (int32, error) { 418 | r1, _, err := filterLoad.Call( 419 | uintptr(unsafe.Pointer(lpFilterName))) 420 | if err.(syscall.Errno) == 0 { 421 | return int32(r1), nil 422 | } 423 | return int32(r1), err 424 | } 425 | 426 | /* 427 | FilterReplyMessage API wrapper generated from prototype 428 | HRESULT WINAPI FilterReplyMessage( 429 | HANDLE hPort, 430 | PFILTER_REPLY_HEADER lpReplyBuffer, 431 | DWORD dwReplyBufferSize); 432 | */ 433 | func FilterReplyMessage(hPort syscall.Handle, 434 | lpReplyBuffer *FilterReplyHeader, 435 | dwReplyBufferSize uint32) (int32, error) { 436 | r1, _, err := filterReplyMessage.Call( 437 | uintptr(hPort), 438 | uintptr(unsafe.Pointer(lpReplyBuffer)), 439 | uintptr(dwReplyBufferSize)) 440 | if err.(syscall.Errno) == 0 { 441 | return int32(r1), nil 442 | } 443 | return int32(r1), err 444 | } 445 | 446 | /* 447 | FilterSendMessage API wrapper generated from prototype 448 | HRESULT WINAPI FilterSendMessage( 449 | HANDLE hPort, 450 | LPVOID lpInBuffer, 451 | DWORD dwInBufferSize, 452 | LPVOID lpOutBuffer, 453 | DWORD dwOutBufferSize, 454 | LPDWORD lpBytesReturned); 455 | */ 456 | func FilterSendMessage(hPort syscall.Handle, 457 | lpInBuffer uintptr, 458 | dwInBufferSize uint32, 459 | lpOutBuffer uintptr, 460 | dwOutBufferSize uint32, 461 | lpBytesReturned *uint32) (int32, error) { 462 | r1, _, err := filterSendMessage.Call( 463 | uintptr(hPort), 464 | uintptr(lpInBuffer), 465 | uintptr(dwInBufferSize), 466 | uintptr(lpOutBuffer), 467 | uintptr(dwOutBufferSize), 468 | uintptr(unsafe.Pointer(lpBytesReturned))) 469 | if err.(syscall.Errno) == 0 { 470 | return int32(r1), nil 471 | } 472 | return int32(r1), err 473 | } 474 | 475 | /* 476 | FilterUnload API wrapper generated from prototype 477 | HRESULT WINAPI FilterUnload( 478 | LPCWSTR lpFilterName); 479 | */ 480 | func FilterUnload(lpFilterName *uint16) (int32, error) { 481 | r1, _, err := filterUnload.Call( 482 | uintptr(unsafe.Pointer(lpFilterName))) 483 | if err.(syscall.Errno) == 0 { 484 | return int32(r1), nil 485 | } 486 | return int32(r1), err 487 | } 488 | 489 | /* 490 | FilterVolumeFindClose API wrapper generated from prototype 491 | HRESULT WINAPI FilterVolumeFindClose( 492 | HANDLE hVolumeFind); 493 | */ 494 | func FilterVolumeFindClose(hVolumeFind syscall.Handle) (int32, error) { 495 | r1, _, err := filterVolumeFindClose.Call( 496 | uintptr(hVolumeFind)) 497 | if err.(syscall.Errno) == 0 { 498 | return int32(r1), nil 499 | } 500 | return int32(r1), err 501 | } 502 | 503 | /* 504 | FilterVolumeFindFirst API wrapper generated from prototype 505 | HRESULT WINAPI FilterVolumeFindFirst( 506 | FILTER_VOLUME_INFORMATION_CLASS dwInformationClass, 507 | LPVOID lpBuffer, 508 | DWORD dwBufferSize, 509 | LPDWORD lpBytesReturned, 510 | PHANDLE lpVolumeFind); 511 | */ 512 | func FilterVolumeFindFirst(dwInformationClass FilterVolumeInformationClass, 513 | lpBuffer uintptr, 514 | dwBufferSize uint32, 515 | lpBytesReturned *uint32, 516 | lpVolumeFind *syscall.Handle) (int32, error) { 517 | r1, _, err := filterVolumeFindFirst.Call( 518 | uintptr(dwInformationClass), 519 | uintptr(lpBuffer), 520 | uintptr(dwBufferSize), 521 | uintptr(unsafe.Pointer(lpBytesReturned)), 522 | uintptr(unsafe.Pointer(lpVolumeFind))) 523 | if err.(syscall.Errno) == 0 { 524 | return int32(r1), nil 525 | } 526 | return int32(r1), err 527 | } 528 | 529 | /* 530 | FilterVolumeFindNext API wrapper generated from prototype 531 | HRESULT WINAPI FilterVolumeFindNext( 532 | HANDLE hVolumeFind, 533 | FILTER_VOLUME_INFORMATION_CLASS dwInformationClass, 534 | LPVOID lpBuffer, 535 | DWORD dwBufferSize, 536 | LPDWORD lpBytesReturned); 537 | */ 538 | func FilterVolumeFindNext(hVolumeFind syscall.Handle, 539 | dwInformationClass FilterVolumeInformationClass, 540 | lpBuffer uintptr, 541 | dwBufferSize uint32, 542 | lpBytesReturned *uint32) (int32, error) { 543 | r1, _, err := filterVolumeFindNext.Call( 544 | uintptr(hVolumeFind), 545 | uintptr(dwInformationClass), 546 | uintptr(lpBuffer), 547 | uintptr(dwBufferSize), 548 | uintptr(unsafe.Pointer(lpBytesReturned))) 549 | if err.(syscall.Errno) == 0 { 550 | return int32(r1), nil 551 | } 552 | return int32(r1), err 553 | } 554 | 555 | /* 556 | FilterVolumeInstanceFindClose API wrapper generated from prototype 557 | HRESULT WINAPI FilterVolumeInstanceFindClose( 558 | HANDLE hVolumeInstanceFind); 559 | */ 560 | func FilterVolumeInstanceFindClose(hVolumeInstanceFind syscall.Handle) (int32, error) { 561 | r1, _, err := filterVolumeInstanceFindClose.Call( 562 | uintptr(hVolumeInstanceFind)) 563 | if err.(syscall.Errno) == 0 { 564 | return int32(r1), nil 565 | } 566 | return int32(r1), err 567 | } 568 | 569 | /* 570 | FilterVolumeInstanceFindFirst API wrapper generated from prototype 571 | HRESULT WINAPI FilterVolumeInstanceFindFirst( 572 | LPCWSTR lpVolumeName, 573 | INSTANCE_INFORMATION_CLASS dwInformationClass, 574 | LPVOID lpBuffer, 575 | DWORD dwBufferSize, 576 | LPDWORD lpBytesReturned, 577 | LPHANDLE lpVolumeInstanceFind); 578 | */ 579 | func FilterVolumeInstanceFindFirst(lpVolumeName *uint16, 580 | dwInformationClass InstanceInformationClass, 581 | lpBuffer uintptr, 582 | dwBufferSize uint32, 583 | lpBytesReturned *uint32, 584 | lpVolumeInstanceFind syscall.Handle) (int32, error) { 585 | r1, _, err := filterVolumeInstanceFindFirst.Call( 586 | uintptr(unsafe.Pointer(lpVolumeName)), 587 | uintptr(dwInformationClass), 588 | uintptr(lpBuffer), 589 | uintptr(dwBufferSize), 590 | uintptr(unsafe.Pointer(lpBytesReturned)), 591 | uintptr(lpVolumeInstanceFind)) 592 | if err.(syscall.Errno) == 0 { 593 | return int32(r1), nil 594 | } 595 | return int32(r1), err 596 | } 597 | 598 | /* 599 | FilterVolumeInstanceFindNext API wrapper generated from prototype 600 | HRESULT WINAPI FilterVolumeInstanceFindNext( 601 | HANDLE hVolumeInstanceFind, 602 | INSTANCE_INFORMATION_CLASS dwInformationClass, 603 | LPVOID lpBuffer, 604 | DWORD dwBufferSize, 605 | LPDWORD lpBytesReturned); 606 | */ 607 | func FilterVolumeInstanceFindNext(hVolumeInstanceFind syscall.Handle, 608 | dwInformationClass InstanceInformationClass, 609 | lpBuffer uintptr, 610 | dwBufferSize uint32, 611 | lpBytesReturned *uint32) (int32, error) { 612 | r1, _, err := filterVolumeInstanceFindNext.Call( 613 | uintptr(hVolumeInstanceFind), 614 | uintptr(dwInformationClass), 615 | uintptr(lpBuffer), 616 | uintptr(dwBufferSize), 617 | uintptr(unsafe.Pointer(lpBytesReturned))) 618 | if err.(syscall.Errno) == 0 { 619 | return int32(r1), nil 620 | } 621 | return int32(r1), err 622 | } 623 | -------------------------------------------------------------------------------- /win32/fltlib/headers.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package fltlib 4 | 5 | type FilterInformationClass interface{} 6 | 7 | /* 8 | typedef struct _FILTER_FULL_INFORMATION { 9 | ULONG NextEntryOffset; 10 | ULONG FrameID; 11 | ULONG NumberOfInstances; 12 | USHORT FilterNameLength; 13 | WCHAR FilterNameBuffer[1]; 14 | } FILTER_FULL_INFORMATION, *PFILTER_FULL_INFORMATION; 15 | */ 16 | 17 | type FilterFullInformation struct{} 18 | 19 | /* 20 | typedef struct _FILTER_AGGREGATE_BASIC_INFORMATION { 21 | ULONG NextEntryOffset; 22 | ULONG Flags; 23 | union { 24 | struct { 25 | ULONG FrameID; 26 | ULONG NumberOfInstances; 27 | USHORT FilterNameLength; 28 | USHORT FilterNameBufferOffset; 29 | USHORT FilterAltitudeLength; 30 | USHORT FilterAltitudeBufferOffset; 31 | } MiniFilter; 32 | struct { 33 | USHORT FilterNameLength; 34 | USHORT FilterNameBufferOffset; 35 | } LegacyFilter; 36 | } Type; 37 | } FILTER_AGGREGATE_BASIC_INFORMATION, *PFILTER_AGGREGATE_BASIC_INFORMATION; 38 | */ 39 | 40 | type FilterAggregateBasicInformation struct{} 41 | 42 | /* 43 | typedef struct _FILTER_AGGREGATE_STANDARD_INFORMATION { 44 | ULONG NextEntryOffset; 45 | ULONG Flags; 46 | union { 47 | struct { 48 | ULONG Flags; 49 | ULONG FrameID; 50 | ULONG NumberOfInstances; 51 | USHORT FilterNameLength; 52 | USHORT FilterNameBufferOffset; 53 | USHORT FilterAltitudeLength; 54 | USHORT FilterAltitudeBufferOffset; 55 | } MiniFilter; 56 | struct { 57 | ULONG Flags; 58 | USHORT FilterNameLength; 59 | USHORT FilterNameBufferOffset; 60 | USHORT FilterAltitudeLength; 61 | USHORT FilterAltitudeBufferOffset; 62 | } LegacyFilter; 63 | } Type; 64 | } FILTER_AGGREGATE_STANDARD_INFORMATION, *PFILTER_AGGREGATE_STANDARD_INFORMATION; 65 | */ 66 | 67 | type FilterAggregateStandardInformation struct{} 68 | -------------------------------------------------------------------------------- /win32/helpers.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package win32 5 | 6 | import ( 7 | "crypto/rand" 8 | "fmt" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | func unsafeUTF16PtrToString(ptr unsafe.Pointer) string { 14 | out := make([]uint16, 0, 64) 15 | for wc := *(*uint16)(ptr); wc != 0; wc = *(*uint16)(ptr) { 16 | out = append(out, wc) 17 | ptr = Add(ptr, 2) 18 | } 19 | return syscall.UTF16ToString(out) 20 | } 21 | 22 | // UTF16BytesToString transforms a bytes array of UTF16 encoded characters to 23 | // a Go string 24 | func UTF16BytesToString(utf16 []byte) string { 25 | if len(utf16) > 0 { 26 | return unsafeUTF16PtrToString(unsafe.Pointer(&utf16[0])) 27 | } 28 | return "" 29 | } 30 | 31 | // UTF16PtrToString transforms a *uint16 to a Go string 32 | func UTF16PtrToString(utf16 *uint16) string { 33 | return unsafeUTF16PtrToString(unsafe.Pointer(utf16)) 34 | } 35 | 36 | func CopyData(pointer uintptr, size int) []byte { 37 | out := make([]byte, size) 38 | for it := pointer; it != pointer+uintptr(size); it++ { 39 | b := (*byte)(unsafe.Pointer(it)) 40 | out = append(out, *b) 41 | } 42 | return out 43 | } 44 | 45 | // UUID is a simple UUID generator 46 | func UUID() (uuid string, err error) { 47 | b := make([]byte, 16) 48 | _, err = rand.Read(b) 49 | if err != nil { 50 | return 51 | } 52 | uuid = fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) 53 | return 54 | } 55 | 56 | // Add helper for pointer arithmetic 57 | func Add(p unsafe.Pointer, i uintptr) unsafe.Pointer { 58 | return unsafe.Pointer(uintptr(p) + i) 59 | } 60 | 61 | func Lower(p, other unsafe.Pointer) bool { 62 | return uintptr(p) < uintptr(other) 63 | } 64 | -------------------------------------------------------------------------------- /win32/kernel32/header.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package kernel32 5 | 6 | import ( 7 | "fmt" 8 | "math" 9 | "unsafe" 10 | 11 | "github.com/0xrawsec/golang-win32/win32" 12 | ) 13 | 14 | const ( 15 | STANDARD_RIGHTS_REQUIRED = 0x000F0000 16 | DELETE = 0x00010000 17 | READ_CONTROL = 0x00020000 18 | WRITE_DAC = 0x00040000 19 | WRITE_OWNER = 0x00080000 20 | SYNCHRONIZE = 0x00100000 21 | 22 | STANDARD_RIGHTS_READ = READ_CONTROL 23 | STANDARD_RIGHTS_WRITE = READ_CONTROL 24 | STANDARD_RIGHTS_EXECUTE = READ_CONTROL 25 | 26 | STANDARD_RIGHTS_ALL = 0x001F0000 27 | 28 | SPECIFIC_RIGHTS_ALL = 0x0000FFFF 29 | 30 | ACCESS_SYSTEM_SECURITY = 0x01000000 31 | MAXIMUM_ALLOWED = 0x02000000 32 | 33 | GENERIC_READ = 0x80000000 34 | GENERIC_WRITE = 0x40000000 35 | GENERIC_EXECUTE = 0x20000000 36 | GENERIC_ALL = 0x10000000 37 | 38 | PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff 39 | PROCESS_TERMINATE = 0x0001 40 | PROCESS_CREATE_THREAD = 0x0002 41 | PROCESS_SET_SESSIONID = 0x0004 42 | PROCESS_VM_OPERATION = 0x0008 43 | PROCESS_VM_READ = 0x0010 44 | PROCESS_VM_WRITE = 0x0020 45 | PROCESS_DUP_HANDLE = 0x0040 46 | PROCESS_CREATE_PROCESS = 0x0080 47 | PROCESS_SET_QUOTA = 0x0100 48 | PROCESS_SET_INFORMATION = 0x0200 49 | PROCESS_QUERY_INFORMATION = 0x0400 50 | PROCESS_SUSPEND_RESUME = 0x0800 51 | PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 52 | ) 53 | 54 | // threads 55 | const ( 56 | THREAD_TERMINATE = 0x0001 57 | THREAD_SUSPEND_RESUME = 0x0002 58 | THREAD_GET_CONTEXT = 0x0008 59 | THREAD_SET_CONTEXT = 0x0010 60 | THREAD_SET_INFORMATION = 0x0020 61 | THREAD_QUERY_INFORMATION = 0x0040 62 | THREAD_SET_THREAD_TOKEN = 0x0080 63 | THREAD_IMPERSONATE = 0x0100 64 | THREAD_DIRECT_IMPERSONATION = 0x0200 65 | THREAD_SET_LIMITED_INFORMATION = 0x0400 66 | THREAD_QUERY_LIMITED_INFORMATION = 0x0800 67 | THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff 68 | ) 69 | 70 | // thelp32.h 71 | 72 | type LPTHREADENTRY32 *THREADENTRY32 73 | type LPCTHREADENTRY32 *THREADENTRY32 74 | 75 | const ( 76 | TH32CS_SNAPHEAPLIST = 0x00000001 77 | TH32CS_SNAPPROCESS = 0x00000002 78 | TH32CS_SNAPTHREAD = 0x00000004 79 | TH32CS_SNAPMODULE = 0x00000008 80 | TH32CS_SNAPMODULE32 = 0x00000010 81 | TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE 82 | TH32CS_INHERIT = 0x80000000 83 | ) 84 | 85 | type THREADENTRY32 struct { 86 | DwSize win32.DWORD 87 | CntUsage win32.DWORD 88 | Th32ThreadID win32.DWORD 89 | Th32OwnerProcessID win32.DWORD 90 | TpBasePri win32.LONG 91 | TpDeltaPri win32.LONG 92 | DwFlags win32.DWORD 93 | } 94 | 95 | func NewThreadEntry32() THREADENTRY32 { 96 | te := THREADENTRY32{} 97 | te.DwSize = win32.DWORD(unsafe.Sizeof(te)) 98 | return te 99 | } 100 | 101 | type PROCESSENTRY32W struct { 102 | DwSize win32.DWORD 103 | CntUsage win32.DWORD 104 | Th32ProcessID win32.DWORD 105 | Th32DefaultHeapID win32.ULONG_PTR 106 | Th32ModuleID win32.DWORD 107 | CntThreads win32.DWORD 108 | Th32ParentProcessID win32.DWORD 109 | PcPriClassBase win32.LONG 110 | DwFlags win32.DWORD 111 | SzExeFile [win32.MAX_PATH]uint16 112 | } 113 | 114 | type LPPROCESSENTRY32W *PROCESSENTRY32W 115 | type LPCPROCESSENTRY32W *PROCESSENTRY32W 116 | 117 | func NewProcessEntry32W() PROCESSENTRY32W { 118 | return PROCESSENTRY32W{DwSize: win32.DWORD(unsafe.Sizeof(PROCESSENTRY32W{}))} 119 | } 120 | 121 | type MODULEINFO struct { 122 | LpBaseOfDll win32.LPVOID 123 | // Size of the image mapped in memory 124 | // To compute it from the image file we need to add all section sizes 125 | // rounded up to the dwPageSize (minimum alloc size) + 1 page for the PE header 126 | SizeOfImage win32.DWORD 127 | EntryPoint win32.LPVOID 128 | } 129 | 130 | func (mi MODULEINFO) String() string { 131 | return fmt.Sprintf("LpBaseOfDll: 0x%016x SizeOfImage: %d Entrypoint: 0x%016x Entrypoint (relative to base): 0x%08x", mi.LpBaseOfDll, mi.SizeOfImage, mi.EntryPoint, 132 | mi.EntryPoint-mi.LpBaseOfDll) 133 | } 134 | 135 | type ProcessInformationClass uint32 136 | 137 | const ( 138 | ProcessMemoryPriorityClass = ProcessInformationClass(iota) 139 | ProcessMemoryExhaustionInfoClass 140 | ProcessAppMemoryInfoClass 141 | ProcessInPrivateInfoClass 142 | ProcessPowerThrottlingClass 143 | ProcessReservedValue1Class 144 | ProcessTelemetryCoverageInfoClass 145 | ProcessProtectionLevelInfoClass 146 | ProcessLeapSecondInfoClass 147 | ProcessMachineTypeInfoClass 148 | ProcessInformationClassMaxClass 149 | ) 150 | 151 | type ProcessProtectionLevelInformation uint32 152 | 153 | const ( 154 | // values assumed from https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_protection_level_information 155 | // partially confirmed from: https://github.com/processhacker/processhacker/blob/master/phnt/include/ntpsapi.h 156 | ProtectionLevelWintcbLight = ProcessProtectionLevelInformation(iota) 157 | ProtectionLevelWindows 158 | ProtectionLevelWindowsLight 159 | ProtectionLevelAntimalwareLight 160 | ProtectionLevelLsaLight 161 | ProtectionLevelWintcb 162 | ProtectionLevelCodegenLight 163 | ProtectionLevelAuthenticode 164 | ProtectionLevelPplApp 165 | 166 | ProtectionLevelNone = math.MaxUint32 - 1 167 | ) 168 | 169 | type MemoryPriorityInformation uint32 170 | 171 | const ( 172 | MemoryPriorityVeryLow = MemoryPriorityInformation(iota + 1) 173 | MemoryPriorityLow 174 | MemoryPriorityMedium 175 | MemoryPriorityBelowNormal 176 | MemoryPriorityNormal 177 | ) 178 | 179 | type ProcessMemoryExhaustionType uint32 180 | 181 | const ( 182 | PMETypeFailFastOnCommitFailure = ProcessMemoryExhaustionType(iota) 183 | PMETypeMax 184 | ) 185 | 186 | type ProcessMemoryExhaustionInfo struct { 187 | Version uint16 188 | Reserved uint16 189 | Type ProcessMemoryExhaustionType 190 | Value uintptr 191 | } 192 | 193 | type AppMemoryInformation struct { 194 | AvailableCommit uint64 195 | PrivateCommitUsage uint64 196 | PeakPrivateCommitUsage uint64 197 | TotalCommitUsage uint64 198 | } 199 | -------------------------------------------------------------------------------- /win32/kernel32/helpers.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package kernel32 5 | 6 | import ( 7 | "debug/pe" 8 | "encoding/json" 9 | "fmt" 10 | "os" 11 | "reflect" 12 | "strings" 13 | "syscall" 14 | "time" 15 | "unsafe" 16 | 17 | "github.com/0xrawsec/golang-utils/log" 18 | "github.com/0xrawsec/golang-win32/win32" 19 | ) 20 | 21 | func ToJSON(data interface{}) string { 22 | b, err := json.Marshal(data) 23 | if err != nil { 24 | panic(err) 25 | } 26 | return string(b) 27 | } 28 | 29 | // AllVirtualQueryEx helper function 30 | func AllVirtualQueryEx(hProcess win32.HANDLE) (cmbi chan win32.MemoryBasicInformation) { 31 | cmbi = make(chan win32.MemoryBasicInformation) 32 | go func() { 33 | defer close(cmbi) 34 | lpAddress := win32.LPCVOID(0) 35 | for { 36 | var mbi win32.MemoryBasicInformation 37 | mbi, err := VirtualQueryEx(hProcess, lpAddress) 38 | if err != nil { 39 | break 40 | } 41 | lpAddress += win32.LPCVOID(mbi.RegionSize) 42 | cmbi <- mbi 43 | } 44 | }() 45 | return 46 | } 47 | 48 | // ForceDumpAllMemory helper function 49 | // TODO : increase the limitation used to dump memory 50 | func ForceDumpAllMemory(pid int, dumpFile string) error { 51 | // Open out file 52 | f, err := os.Create(dumpFile) 53 | if err != nil { 54 | return err 55 | } 56 | // Open the process with appropriate access rights 57 | da := uint32(PROCESS_ALL_ACCESS) 58 | hProcess, err := syscall.OpenProcess(da, false, uint32(pid)) 59 | if err != nil { 60 | return err 61 | } 62 | defer CloseHandle(win32.HANDLE(hProcess)) 63 | 64 | for mbi := range AllVirtualQueryEx(win32.HANDLE(hProcess)) { 65 | // Filter by size 66 | if mbi.RegionSize < (1 << 25) { 67 | mem := make([]byte, mbi.RegionSize) 68 | lpAddress := win32.LPCVOID(mbi.BaseAddress) 69 | ReadProcessMemory(win32.HANDLE(hProcess), lpAddress, mem) 70 | f.Write(mem) 71 | } 72 | } 73 | return nil 74 | } 75 | 76 | // FindTextSection returns the Memory Basic Information of the memory 77 | // zone containing the entrypoint of the image 78 | func FindTextSection(hProcess win32.HANDLE, mi MODULEINFO) (mbi win32.MemoryBasicInformation, err error) { 79 | for address := win32.LPCVOID(mi.LpBaseOfDll); address-win32.LPCVOID(mi.LpBaseOfDll) < win32.LPCVOID(mi.SizeOfImage); { 80 | mbi, err = VirtualQueryEx(win32.HANDLE(hProcess), address) 81 | // Entrypoint is in this memory area 82 | // Explicit casting is needed because MemoryBasicInformation fields 83 | // have not the same types between architectures 84 | if win32.ULONGLONG(mi.EntryPoint) > win32.ULONGLONG(mbi.BaseAddress) && win32.ULONGLONG(mi.EntryPoint) < win32.ULONGLONG(mbi.BaseAddress)+win32.ULONGLONG(mbi.RegionSize) { 85 | return 86 | } 87 | address += win32.LPCVOID(mbi.RegionSize) 88 | } 89 | return 90 | } 91 | 92 | // FindTextSectionFromImage returns the section containing the entrypoint 93 | func FindTextSectionFromImage(image string) (section []byte, err error) { 94 | // parse the pe file 95 | var entrypoint uint32 96 | imPe, err := pe.Open(image) 97 | if err != nil { 98 | return 99 | } 100 | defer imPe.Close() 101 | switch imPe.OptionalHeader.(type) { 102 | case *pe.OptionalHeader32: 103 | entrypoint = imPe.OptionalHeader.(*pe.OptionalHeader32).AddressOfEntryPoint 104 | case *pe.OptionalHeader64: 105 | entrypoint = imPe.OptionalHeader.(*pe.OptionalHeader64).AddressOfEntryPoint 106 | } 107 | 108 | for _, s := range imPe.Sections { 109 | header := s.SectionHeader 110 | if entrypoint > header.VirtualAddress && entrypoint < header.VirtualAddress+header.Size { 111 | return s.Data() 112 | } 113 | } 114 | return 115 | } 116 | 117 | func max(i, j int) int { 118 | if i < j { 119 | return j 120 | } 121 | return i 122 | } 123 | 124 | func min(i, j int) int { 125 | if i < j { 126 | return i 127 | } 128 | return j 129 | } 130 | 131 | // CheckProcessIntegrity helper function to check process integrity 132 | // compare entrypoint section on disk and in memory 133 | func CheckProcessIntegrity(hProcess win32.HANDLE) (bytediff int, length int, err error) { 134 | image, err := QueryFullProcessImageName(hProcess) 135 | if err != nil { 136 | return 0, 0, fmt.Errorf("Cannot get image of process") 137 | } 138 | mi, err := GetImageModuleInfo(hProcess) 139 | if err != nil { 140 | return 0, 0, fmt.Errorf("Cannot get module info") 141 | } 142 | // We get the text section from memory 143 | memInfoTextInMem, err := FindTextSection(hProcess, mi) 144 | if err != nil { 145 | return 0, 0, fmt.Errorf("Cannot find section in memory") 146 | } 147 | textInMem := make([]byte, memInfoTextInMem.RegionSize) 148 | _, err = ReadProcessMemory(hProcess, win32.LPCVOID(memInfoTextInMem.BaseAddress), textInMem) 149 | if err != nil { 150 | return 0, 0, fmt.Errorf("Cannot read process memory") 151 | } 152 | textOnDisk, err := FindTextSectionFromImage(image) 153 | if err != nil { 154 | return 0, 0, fmt.Errorf("Cannot find section on disk") 155 | } 156 | return fastDiff(&textInMem, &textOnDisk), max(len(textOnDisk), len(textInMem)), nil 157 | } 158 | 159 | func fastDiff(b1, b2 *[]byte) (diff int) { 160 | min := min(len(*b1), len(*b2)) 161 | max := max(len(*b1), len(*b2)) 162 | diff = max - min 163 | for i := 0; i < min; i++ { 164 | if (*b1)[i] != (*b2)[i] { 165 | diff++ 166 | } 167 | } 168 | return diff 169 | } 170 | 171 | // GetModuleFilenameSelf helper function to retrieve self executable module 172 | // filename 173 | func GetModuleFilenameSelf() (string, error) { 174 | return GetModuleFilename(0) 175 | } 176 | 177 | // GetModuleFilenameFromPID helper function to retrieve the module filename from 178 | // a pid 179 | func GetModuleFilenameFromPID(pid int) (fn string, err error) { 180 | // Open the process with appropriate access rights 181 | hProcess, err := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, win32.FALSE, win32.DWORD(pid)) 182 | if err != nil { 183 | return 184 | } 185 | defer CloseHandle(hProcess) 186 | return QueryFullProcessImageName(win32.HANDLE(hProcess)) 187 | } 188 | 189 | // ListThreads list the threads of process pid 190 | func ListThreads(pid int) (ctid chan int) { 191 | ctid = make(chan int, 42) 192 | go func() { 193 | defer close(ctid) 194 | for i := 0; i < 100000; i++ { 195 | hThread, err := OpenThread(THREAD_QUERY_LIMITED_INFORMATION, win32.FALSE, win32.DWORD(i)) 196 | if err == nil { 197 | ppid, err := GetProcessIdOfThread(hThread) 198 | if err != nil { 199 | log.Error(err) 200 | } 201 | if int(ppid) == pid { 202 | ctid <- i 203 | } 204 | CloseHandle(hThread) 205 | } 206 | } 207 | }() 208 | return 209 | } 210 | 211 | // GetFirstTidOfPid list the threads of process pid 212 | func GetFirstTidOfPid(pid int) int { 213 | for i := 0; i < 100000; i++ { 214 | hThread, err := OpenThread(THREAD_QUERY_LIMITED_INFORMATION, win32.FALSE, win32.DWORD(i)) 215 | if err == nil { 216 | defer CloseHandle(hThread) 217 | ppid, err := GetProcessIdOfThread(hThread) 218 | if err != nil { 219 | log.Error(err) 220 | } 221 | if int(ppid) == pid { 222 | return i 223 | } 224 | } 225 | } 226 | return -1 227 | } 228 | 229 | // IsThreadRunning returns true if hThread is running else false 230 | // It is a little hack since I am not aware of any API call to check 231 | // whether a thread is running or not 232 | func IsThreadRunning(hThread win32.HANDLE) (bool, error) { 233 | count, err := SuspendThread(hThread) 234 | if err != nil { 235 | return false, err 236 | } 237 | ResumeThread(hThread) 238 | return count == 0, nil 239 | } 240 | 241 | // IsProcessRunning returns true if the process is running and false if not 242 | func IsProcessRunning(hProcess win32.HANDLE) bool { 243 | exitCode, err := GetExitCodeProcess(hProcess) 244 | if err == nil { 245 | if exitCode == win32.STILL_ACTIVE { 246 | return true 247 | } 248 | } 249 | return false 250 | } 251 | 252 | // IsPIDRunning returns true if the process referenced by pid is running 253 | func IsPIDRunning(pid int) bool { 254 | if pid == 0 { 255 | return true 256 | } 257 | if pid < 0 { 258 | return false 259 | } 260 | if hProcess, err := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, win32.FALSE, win32.DWORD(pid)); err == nil { 261 | defer CloseHandle(hProcess) 262 | return IsProcessRunning(hProcess) 263 | } 264 | return false 265 | } 266 | 267 | // WaitThreadRuns waits until a thread is running 268 | func WaitThreadRuns(hThread win32.HANDLE, step, timeout time.Duration) bool { 269 | for wait := time.Duration(0); wait < timeout; wait += step { 270 | if ok, _ := IsThreadRunning(hThread); ok { 271 | return true 272 | } 273 | time.Sleep(step) 274 | } 275 | return false 276 | } 277 | 278 | // GetImageModuleInfo helper function 279 | func GetImageModuleInfo(hProcess win32.HANDLE) (mi MODULEINFO, err error) { 280 | procImage, err := QueryFullProcessImageName(hProcess) 281 | if err != nil { 282 | return 283 | } 284 | modules, err := EnumProcessModules(hProcess) 285 | if err != nil { 286 | return 287 | } 288 | for _, hMod := range modules { 289 | var modName string 290 | modName, err = GetModuleFilenameExW(hProcess, hMod) 291 | if err != nil { 292 | return 293 | } 294 | // need this otherwise we can have issue not finding the module 295 | if strings.ToLower(modName) == strings.ToLower(procImage) { 296 | log.Debugf("Found module name: %s", modName) 297 | mi, err = GetModuleInformation(hProcess, hMod) 298 | return mi, err 299 | } 300 | } 301 | return mi, fmt.Errorf("Module not found") 302 | } 303 | 304 | // GetImageModuleInfoFromPID helper function 305 | func GetImageModuleInfoFromPID(pid uint32) (mi MODULEINFO, err error) { 306 | // open remote process 307 | hProcess, err := OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, win32.FALSE, win32.DWORD(pid)) 308 | if err != nil { 309 | return 310 | } 311 | defer CloseHandle(hProcess) 312 | return GetImageModuleInfo(hProcess) 313 | } 314 | 315 | // GetProcessProtectionLevel gives the protection level associated to the process identified by pid 316 | func GetProcessProtectionLevel(pid uint32) (ppli ProcessProtectionLevelInformation, err error) { 317 | 318 | hProcess, err := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, win32.FALSE, win32.DWORD(pid)) 319 | if err != nil { 320 | return 321 | } 322 | 323 | defer CloseHandle(hProcess) 324 | 325 | err = GetProcessInformation( 326 | syscall.Handle(hProcess), 327 | ProcessProtectionLevelInfoClass, 328 | uintptr(unsafe.Pointer(&ppli)), 329 | uint32(unsafe.Sizeof(ppli)), 330 | ) 331 | 332 | return 333 | } 334 | 335 | // SuspendProcess suspends a given process 336 | func SuspendProcess(pid int) { 337 | if IsPIDRunning(pid) { 338 | for tid := range ListThreads(pid) { 339 | hThread, err := OpenThread(THREAD_SUSPEND_RESUME, win32.FALSE, win32.DWORD(tid)) 340 | if err != nil { 341 | log.Error(err) 342 | } else { 343 | _, err := SuspendThread(hThread) 344 | if err != nil { 345 | log.Error(err) 346 | } 347 | } 348 | CloseHandle(hThread) 349 | } 350 | } 351 | } 352 | 353 | // SetCurrentThreadPriority helper function to set priority of current Thread 354 | func SetCurrentThreadPriority(nPriority int) error { 355 | hThread := GetCurrentThread() 356 | defer CloseHandle(hThread) 357 | return SetThreadPriority(hThread, nPriority) 358 | } 359 | 360 | // ResumeProcess resumes a previously suspended process 361 | func ResumeProcess(pid int) { 362 | if IsPIDRunning(pid) { 363 | for tid := range ListThreads(pid) { 364 | hThread, err := OpenThread(THREAD_SUSPEND_RESUME, win32.FALSE, win32.DWORD(tid)) 365 | if err != nil { 366 | log.Error(err) 367 | } else { 368 | _, err := ResumeThread(hThread) 369 | if err != nil { 370 | log.Error(err) 371 | } 372 | } 373 | CloseHandle(hThread) 374 | } 375 | } 376 | } 377 | 378 | // WriteMemoryAndControl write a buffer in memory and control it has been 379 | // properly written. This function also manages the memory protections. 380 | func WriteMemoryAndControl(hProcess win32.HANDLE, lpBaseAddress win32.LPCVOID, lpBuffer []byte) error { 381 | checkBuf := make([]byte, len(lpBuffer)) 382 | // Changing memory protection 383 | op, err := VirtualProtect(win32.LPVOID(lpBaseAddress), win32.SIZE_T(len(lpBuffer)), win32.PAGE_EXECUTE_READWRITE) 384 | if err != nil { 385 | return err 386 | } 387 | // Writing Memory 388 | w, err := WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer) 389 | if err != nil { 390 | return err 391 | } 392 | // Control that we wrote the good number of bytes 393 | if w != len(lpBuffer) { 394 | return fmt.Errorf("Partial write only") 395 | } 396 | // Control what has been read 397 | r, err := ReadProcessMemory(hProcess, lpBaseAddress, checkBuf) 398 | if err != nil { 399 | return err 400 | } 401 | if r != len(lpBuffer) { 402 | return fmt.Errorf("Partial read only") 403 | } 404 | // We compare what we have written with what we have read 405 | if !reflect.DeepEqual(lpBuffer, checkBuf) { 406 | return fmt.Errorf("Data copy failed") 407 | } 408 | // Changing back the memory protections 409 | log.Debugf("Restoring memory protections: 0x%04x", op) 410 | rwep, err := VirtualProtect(win32.LPVOID(lpBaseAddress), win32.SIZE_T(len(lpBuffer)), op) 411 | if err != nil { 412 | return err 413 | } 414 | if rwep != win32.PAGE_EXECUTE_READWRITE { 415 | return fmt.Errorf("Cannot change memory protection") 416 | } 417 | return nil 418 | } 419 | -------------------------------------------------------------------------------- /win32/kernel32/kernel32.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package kernel32 5 | 6 | import ( 7 | "syscall" 8 | "unsafe" 9 | 10 | "github.com/0xrawsec/golang-utils/log" 11 | "github.com/0xrawsec/golang-win32/win32" 12 | ) 13 | 14 | // CloseHandle Win32 API wrapper 15 | func CloseHandle(hObject win32.HANDLE) error { 16 | r1, _, lastErr := closeHandle.Call( 17 | uintptr(hObject)) 18 | if r1 != 0 { 19 | return nil 20 | } 21 | return lastErr 22 | } 23 | 24 | func CreateEvent(lpEventAttribute uintptr, 25 | bManualReset win32.BOOL, 26 | bInitialState win32.BOOL, 27 | lpName string) (win32.HANDLE, error) { 28 | bLpName := []byte(lpName) 29 | r1, _, lastErr := createEventA.Call(lpEventAttribute, 30 | uintptr(bManualReset), 31 | uintptr(bInitialState), 32 | uintptr(unsafe.Pointer(&bLpName))) 33 | if r1 == win32.NULL { 34 | return win32.HANDLE(r1), lastErr 35 | } 36 | return win32.HANDLE(r1), nil 37 | } 38 | 39 | // CreateToolhelp32Snapshot Win32 API wrapper 40 | func CreateToolhelp32Snapshot(dwFlags win32.DWORD, th32ProcessID win32.DWORD) (win32.HANDLE, error) { 41 | r1, _, lastErr := createToolhelp32Snapshot.Call( 42 | uintptr(dwFlags), 43 | uintptr(th32ProcessID)) 44 | log.Debug(lastErr) 45 | if win32.LONG_PTR(r1) != win32.INVALID_HANDLE { 46 | return win32.HANDLE(r1), nil 47 | } 48 | return win32.HANDLE(r1), lastErr 49 | } 50 | 51 | func EnumProcessModules(hProcess win32.HANDLE) ([]win32.HANDLE, error) { 52 | var hMods [1024]win32.HANDLE 53 | needed := win32.DWORD(0) 54 | _, _, err := k32EnumProcessModules.Call( 55 | uintptr(hProcess), 56 | uintptr(unsafe.Pointer(&hMods)), 57 | uintptr(len(hMods)), 58 | uintptr(unsafe.Pointer(&needed))) 59 | if err.(syscall.Errno) == 0 { 60 | // Number of hModules returned 61 | n := (uintptr(needed) / unsafe.Sizeof(win32.HANDLE(0))) 62 | return hMods[:n], nil 63 | } 64 | return hMods[:], err 65 | } 66 | 67 | func Process32FirstW(hSnapshot win32.HANDLE, lppe LPPROCESSENTRY32W) (bool, error) { 68 | _, _, lastErr := process32FirstW.Call( 69 | uintptr(hSnapshot), 70 | uintptr(unsafe.Pointer(lppe))) 71 | if lastErr.(syscall.Errno) == 0 { 72 | return true, nil 73 | } 74 | return false, lastErr 75 | } 76 | 77 | // Thread32First Win32 API wrapper 78 | func Thread32First(hSnapshot win32.HANDLE, lpte LPTHREADENTRY32) (bool, error) { 79 | _, _, lastErr := thread32First.Call( 80 | uintptr(hSnapshot), 81 | uintptr(unsafe.Pointer(lpte))) 82 | if lastErr.(syscall.Errno) == 0 { 83 | return true, nil 84 | } 85 | return false, lastErr 86 | } 87 | 88 | // Thread32Next Win32 API wrapper 89 | func Thread32Next(hSnapshot win32.HANDLE, lpte LPTHREADENTRY32) (bool, error) { 90 | _, _, lastErr := thread32First.Call( 91 | uintptr(hSnapshot), 92 | uintptr(unsafe.Pointer(lpte))) 93 | if lastErr.(syscall.Errno) == 0 { 94 | return true, nil 95 | } 96 | return false, lastErr 97 | } 98 | 99 | // GetExitCodeProcess win32 API wrapper 100 | // hProcess must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION 101 | func GetExitCodeProcess(hProcess win32.HANDLE) (exitCode win32.DWORD, err error) { 102 | rc, _, err := getExitCodeProcess.Call( 103 | uintptr(hProcess), 104 | uintptr(unsafe.Pointer(&exitCode))) 105 | // return FALSE if failed 106 | if win32.BOOL(rc) == win32.FALSE { 107 | return 108 | } 109 | return exitCode, nil 110 | } 111 | 112 | // GetCurrentProcess Win32 API wrapper 113 | func GetCurrentProcess() (pseudoHandle win32.HANDLE, lastError error) { 114 | pHUint, _, _ := getCurrentProcess.Call() 115 | pseudoHandle = win32.HANDLE(pHUint) 116 | return pseudoHandle, nil 117 | } 118 | 119 | // GetLastError win32 API wrapper 120 | func GetLastError() win32.DWORD { 121 | r1, _, _ := getLastError.Call() 122 | return win32.DWORD(r1) 123 | } 124 | 125 | // GetProcessIdOfThread win32 API wrapper 126 | func GetProcessIdOfThread(hThread win32.HANDLE) (win32.DWORD, error) { 127 | r1, _, lastErr := getProcessIdOfThread.Call(uintptr(hThread)) 128 | if r1 == 0 { 129 | return 0, lastErr 130 | } 131 | return win32.DWORD(r1), nil 132 | } 133 | 134 | // GetCurrentThread win32 API wrapper 135 | func GetCurrentThread() win32.HANDLE { 136 | hThread, _, _ := getCurrentThread.Call() 137 | return win32.HANDLE(hThread) 138 | } 139 | 140 | // GetCurrentThreadId win32 API wrapper 141 | func GetCurrentThreadId() win32.DWORD { 142 | r1, _, _ := getCurrentThreadId.Call() 143 | return win32.DWORD(r1) 144 | } 145 | 146 | // GetThreadId win32 API wrapper 147 | func GetThreadId(thread win32.HANDLE) (win32.DWORD, error) { 148 | r1, _, err := getThreadId.Call( 149 | uintptr(thread)) 150 | if err.(syscall.Errno) == 0 { 151 | return win32.DWORD(r1), nil 152 | } 153 | return win32.DWORD(r1), err 154 | } 155 | 156 | // GetThreadContext Win32 API wrapper 157 | func GetThreadContext(hThread win32.HANDLE, lpContext win32.LPCONTEXT) error { 158 | r1, _, lastErr := getThreadContext.Call(uintptr(hThread), uintptr(unsafe.Pointer(lpContext))) 159 | // If function succeed output is not ZERO 160 | if r1 != win32.NULL { 161 | return nil 162 | } 163 | return lastErr 164 | } 165 | 166 | // GetModuleHandleW Win32 API wrapper 167 | func GetModuleHandleW(lpModuleName string) (win32.HANDLE, error) { 168 | us, err := syscall.UTF16PtrFromString(lpModuleName) 169 | if err != nil { 170 | return win32.HANDLE(win32.NULL), err 171 | } 172 | r1, _, lastErr := getModuleHandleW.Call(uintptr(unsafe.Pointer(us))) 173 | if r1 == win32.NULL { 174 | return win32.HANDLE(win32.NULL), lastErr 175 | } 176 | return win32.HANDLE(r1), nil 177 | } 178 | 179 | // GetModuleFilename Win32 API wrapper 180 | func GetModuleFilename(hProcess win32.HANDLE) (string, error) { 181 | var buf [win32.MAX_PATH]uint16 182 | n := win32.DWORD(len(buf)) 183 | _, _, lastErr := getModuleFileNameW.Call( 184 | uintptr(hProcess), 185 | uintptr(unsafe.Pointer(&buf)), 186 | uintptr(n)) 187 | if lastErr.(syscall.Errno) == 0 { 188 | return syscall.UTF16ToString(buf[:n]), nil 189 | } 190 | return "", lastErr 191 | } 192 | 193 | // GetModuleFilenameExW Win32 API wrapper 194 | func GetModuleFilenameExW(hProcess win32.HANDLE, hModule win32.HANDLE) (string, error) { 195 | var buf [win32.MAX_PATH]uint16 196 | n := win32.DWORD(len(buf)) 197 | _, _, lastErr := k32GetModuleFileNameExW.Call( 198 | uintptr(hProcess), 199 | uintptr(hModule), 200 | uintptr(unsafe.Pointer(&buf)), 201 | uintptr(n)) 202 | if lastErr.(syscall.Errno) == 0 { 203 | return syscall.UTF16ToString(buf[:]), nil 204 | } 205 | return "", lastErr 206 | } 207 | 208 | // GetModuleInformation Win32 API wrapper 209 | // Calling process needs PROCESS_QUERY_INFORMATION and VM_READ 210 | func GetModuleInformation(hProcess win32.HANDLE, hModule win32.HANDLE) (MODULEINFO, error) { 211 | mi := MODULEINFO{} 212 | _, _, err := k32GetModuleInformation.Call( 213 | uintptr(hProcess), 214 | uintptr(hModule), 215 | uintptr(unsafe.Pointer(&mi)), 216 | uintptr(win32.DWORD(unsafe.Sizeof(mi)))) 217 | if err.(syscall.Errno) != 0 { 218 | return mi, err 219 | } 220 | return mi, nil 221 | } 222 | 223 | /* 224 | GetProcessInformation API wrapper generated from prototype 225 | WINBASEAPI WINBOOL WINAPI GetProcessInformation ( 226 | HANDLE hProcess, 227 | PROCESS_INFORMATION_CLASS ProcessInformationClass, 228 | LPVOID ProcessInformation, 229 | DWORD ProcessInformationSize); 230 | */ 231 | func GetProcessInformation( 232 | hProcess syscall.Handle, 233 | processInformationClass ProcessInformationClass, 234 | processInformation uintptr, 235 | processInformationSize uint32) error { 236 | _, _, err := getProcessInformation.Call( 237 | uintptr(hProcess), 238 | uintptr(processInformationClass), 239 | uintptr(processInformation), 240 | uintptr(processInformationSize)) 241 | 242 | if err.(syscall.Errno) == win32.ERROR_SUCCESS { 243 | return nil 244 | } 245 | 246 | return err 247 | } 248 | 249 | // QueryFullProcessImageName Win32 API wrapper 250 | func QueryFullProcessImageName(hProcess win32.HANDLE) (string, error) { 251 | var buf [win32.MAX_PATH]uint16 252 | n := win32.DWORD(len(buf)) 253 | _, _, lastErr := queryFullProcessImageNameW.Call( 254 | uintptr(hProcess), 255 | uintptr(0), 256 | uintptr(unsafe.Pointer(&buf)), 257 | uintptr(unsafe.Pointer(&n))) 258 | if lastErr.(syscall.Errno) == 0 { 259 | return syscall.UTF16ToString(buf[:n]), nil 260 | } 261 | return "", lastErr 262 | } 263 | 264 | // SetThreadContext Win32 API wrapper 265 | func SetThreadContext(hThread win32.HANDLE, lpContext win32.LPCONTEXT) error { 266 | r1, _, lastErr := setThreadContext.Call(uintptr(hThread), uintptr(unsafe.Pointer(lpContext))) 267 | // If function succeed output is not ZERO 268 | if r1 != win32.NULL { 269 | return nil 270 | } 271 | return lastErr 272 | } 273 | 274 | // SetThreadPriority Win32 API wrapper 275 | func SetThreadPriority(hThread win32.HANDLE, nPriority int) error { 276 | if _, _, err := setThreadPriority.Call(uintptr(hThread), uintptr(nPriority)); err.(syscall.Errno) != 0 { 277 | return err 278 | } 279 | return nil 280 | } 281 | 282 | // OpenThread Win32 api wrapper 283 | func OpenThread(dwDesiredAccess win32.DWORD, bInheritHandle win32.BOOL, dwThreadId win32.DWORD) (win32.HANDLE, error) { 284 | r1, _, lastErr := openThread.Call(uintptr(dwDesiredAccess), 285 | uintptr(bInheritHandle), 286 | uintptr(dwThreadId)) 287 | if r1 == win32.NULL { 288 | return win32.HANDLE(0), lastErr 289 | } 290 | return win32.HANDLE(r1), nil 291 | } 292 | 293 | // OpenProcess Win32 API wrapper 294 | func OpenProcess(dwDesiredAccess win32.DWORD, bInheritHandle win32.BOOL, dwProcessId win32.DWORD) (win32.HANDLE, error) { 295 | r1, _, lastErr := openProcess.Call(uintptr(dwDesiredAccess), 296 | uintptr(bInheritHandle), 297 | uintptr(dwProcessId)) 298 | if r1 == win32.NULL { 299 | return win32.HANDLE(0), lastErr 300 | } 301 | return win32.HANDLE(r1), nil 302 | } 303 | 304 | // ReadProcessMemory Win32 API wrapper 305 | // TODO: verify that we have everything 306 | func ReadProcessMemory(hProcess win32.HANDLE, lpBaseAddress win32.LPCVOID, lpBuffer []byte) (int, error) { 307 | const bufSize = 4096 308 | var tmpBuf [bufSize]byte 309 | var read int 310 | lpNumberOfBytesRead := win32.SIZE_T(0) 311 | mod := len(lpBuffer) % bufSize 312 | nSize := bufSize 313 | for read = 0; read < len(lpBuffer); read += nSize { 314 | if len(lpBuffer)-read < bufSize { 315 | nSize = mod 316 | } 317 | r1, _, lastErr := readProcessMemory.Call( 318 | uintptr(hProcess), 319 | uintptr(lpBaseAddress+win32.LPCVOID(read)), 320 | //uintptr(unsafe.Pointer(&lpBuffer)), 321 | uintptr(unsafe.Pointer(&tmpBuf)), 322 | //uintptr(len(lpBuffer)), 323 | uintptr(nSize), 324 | uintptr(unsafe.Pointer(&lpNumberOfBytesRead))) 325 | // if error, we return 326 | if r1 == 0 { 327 | return read + int(lpNumberOfBytesRead), lastErr 328 | } 329 | copy(lpBuffer[read:], tmpBuf[:nSize]) 330 | } 331 | return read, nil 332 | } 333 | 334 | // WriteProcessMemory Win32 API wrapper 335 | // TODO: write test 336 | func WriteProcessMemory(hProcess win32.HANDLE, lpBaseAddress win32.LPCVOID, lpBuffer []byte) (int, error) { 337 | const bufSize = 4096 338 | var tmpBuf [bufSize]byte 339 | var lpNumberOfBytesWritten = win32.SIZE_T(0) 340 | written := 0 341 | for written < len(lpBuffer) { 342 | var src []byte 343 | // Maybe need <= 344 | if written+bufSize < len(lpBuffer) { 345 | src = lpBuffer[written : written+bufSize] 346 | } else { 347 | src = lpBuffer[written:] 348 | } 349 | nSize := copy(tmpBuf[:], src) 350 | r1, _, lastErr := writeProcessMemory.Call( 351 | uintptr(hProcess), 352 | uintptr(lpBaseAddress+win32.LPCVOID(written)), 353 | uintptr(unsafe.Pointer(&tmpBuf)), 354 | uintptr(nSize), 355 | uintptr(unsafe.Pointer(&lpNumberOfBytesWritten))) 356 | if r1 == 0 { 357 | return written + int(lpNumberOfBytesWritten), lastErr 358 | } 359 | written += int(lpNumberOfBytesWritten) 360 | } 361 | return written, nil 362 | } 363 | 364 | // SuspendThread Win32 API wrapper 365 | func SuspendThread(hThread win32.HANDLE) (win32.DWORD, error) { 366 | r1, _, lastErr := suspendThread.Call(uintptr(hThread)) 367 | if lastErr.(syscall.Errno) != 0 { 368 | return 0, lastErr 369 | } 370 | return win32.DWORD(r1), nil 371 | } 372 | 373 | // ResumeThread Win32 API wrapper 374 | func ResumeThread(hThread win32.HANDLE) (win32.DWORD, error) { 375 | r1, _, lastErr := resumeThread.Call(uintptr(hThread)) 376 | if lastErr.(syscall.Errno) != 0 { 377 | return 0, lastErr 378 | } 379 | return win32.DWORD(r1), nil 380 | } 381 | 382 | // ResetEvent Win32 API wrapper 383 | func ResetEvent(hEvent win32.HANDLE) error { 384 | r1, _, lastErr := resetEvent.Call(uintptr(hEvent)) 385 | if win32.BOOL(r1) == win32.FALSE { 386 | return lastErr 387 | } 388 | return nil 389 | } 390 | 391 | func TerminateProcess(hProcess win32.HANDLE, exitCode win32.UINT) (err error) { 392 | _, _, err = terminateProcess.Call(uintptr(hProcess), uintptr(exitCode)) 393 | if err.(syscall.Errno) != 0 { 394 | return err 395 | } 396 | return nil 397 | } 398 | 399 | // VirtualProtect Win32 API wrapper 400 | func VirtualProtect(lpAddress win32.LPVOID, dwSize win32.SIZE_T, flNewProtect win32.DWORD) (lpflOldProtect win32.DWORD, err error) { 401 | r1, _, lastErr := virtualProtect.Call(uintptr(lpAddress), 402 | uintptr(dwSize), 403 | uintptr(flNewProtect), 404 | uintptr(unsafe.Pointer(&lpflOldProtect))) 405 | if r1 == 0 { 406 | return 0, lastErr 407 | } 408 | return lpflOldProtect, nil 409 | } 410 | 411 | // VirtualQueryEx Win32 API wrapper 412 | func VirtualQueryEx(hProcess win32.HANDLE, lpAddress win32.LPCVOID) (win32.MemoryBasicInformation, error) { 413 | mbi := win32.MemoryBasicInformation{} 414 | r1, _, lastErr := virtualQueryEx.Call( 415 | uintptr(hProcess), 416 | uintptr(lpAddress), 417 | uintptr(unsafe.Pointer(&mbi)), 418 | uintptr(unsafe.Sizeof(mbi))) 419 | if r1 == 0 { 420 | return mbi, lastErr 421 | } 422 | return mbi, nil 423 | } 424 | 425 | // VirtualAllocEx Win32 API wrapper 426 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366890(v=vs.85).aspx 427 | // LPVOID WINAPI VirtualAllocEx( 428 | //_In_ HANDLE hProcess, 429 | //_In_opt_ LPVOID lpAddress, 430 | //_In_ SIZE_T dwSize, 431 | //_In_ DWORD flAllocationType, 432 | //_In_ DWORD flProtect 433 | //); 434 | // TODO: Test it 435 | func VirtualAllocEx(hProcess win32.HANDLE, lpAddress win32.LPVOID, dwSize win32.SIZE_T, 436 | flAllocationType win32.DWORD, flProtect win32.DWORD) (win32.LPVOID, error) { 437 | r1, _, lastErr := virtualAllocEx.Call(uintptr(hProcess), 438 | uintptr(lpAddress), 439 | uintptr(dwSize), 440 | uintptr(flAllocationType), 441 | uintptr(flProtect)) 442 | if r1 == win32.NULL { 443 | return win32.LPVOID(r1), lastErr 444 | } 445 | return win32.LPVOID(r1), nil 446 | } 447 | 448 | func WaitForSingleObject(hHandle win32.HANDLE, dwMilliseconds win32.DWORD) win32.DWORD { 449 | r1, _, _ := waitForSingleObject.Call(uintptr(hHandle), uintptr(dwMilliseconds)) 450 | return win32.DWORD(r1) 451 | } 452 | 453 | /* 454 | WaitForMultipleObjects wrapper 455 | DWORD WaitForMultipleObjects( 456 | DWORD nCount, 457 | const HANDLE *lpHandles, 458 | BOOL bWaitAll, 459 | DWORD dwMilliseconds 460 | ); 461 | https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitformultipleobjects 462 | */ 463 | func WaitForMultipleObjects(lpHandles []win32.HANDLE, bWaitAll win32.BOOL, dwMilliseconds win32.DWORD) win32.DWORD { 464 | /*func BytePointer(b []byte) *byte { 465 | return (*byte)(unsafe.Pointer(&b[0])) 466 | }*/ 467 | r1, _, _ := waitForMultipleObjects.Call( 468 | uintptr(len(lpHandles)), 469 | uintptr(unsafe.Pointer(&lpHandles[0])), 470 | uintptr(bWaitAll), 471 | uintptr(dwMilliseconds)) 472 | return win32.DWORD(r1) 473 | } 474 | 475 | // QueryDosDevice API wrapper 476 | // if device is "" it retrieves the list of all available Devices 477 | // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-querydosdevicew 478 | func QueryDosDevice(device string) (out []string, err error) { 479 | var targetPath [win32.MAX_PATH * 0x100]uint16 480 | var r1 uintptr 481 | 482 | out = make([]string, 0) 483 | lpDevName := syscall.StringToUTF16Ptr(device) 484 | 485 | if device == "" { 486 | r1, _, err = queryDosDeviceW.Call( 487 | 0, 488 | uintptr(unsafe.Pointer(&targetPath)), 489 | uintptr(len(targetPath))) 490 | } else { 491 | r1, _, err = queryDosDeviceW.Call( 492 | uintptr(unsafe.Pointer(lpDevName)), 493 | uintptr(unsafe.Pointer(&targetPath)), 494 | uintptr(len(targetPath))) 495 | } 496 | 497 | if r1 == 0 { 498 | return 499 | } 500 | for i, k := 0, 0; i < int(r1) && i < len(targetPath); i++ { 501 | if targetPath[i] == 0 { 502 | dev := syscall.UTF16ToString(targetPath[k:i]) 503 | if dev != "" { 504 | out = append(out, dev) 505 | } 506 | k = i + 1 507 | } 508 | } 509 | return out, nil 510 | } 511 | -------------------------------------------------------------------------------- /win32/kernel32/test/kernel32_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "syscall" 7 | "testing" 8 | "time" 9 | "win32" 10 | "win32/kernel32" 11 | 12 | "github.com/0xrawsec/golang-utils/log" 13 | ) 14 | 15 | var ( 16 | NULL = win32.NULL 17 | ) 18 | 19 | func ToJSON(data interface{}) string { 20 | b, err := json.Marshal(data) 21 | if err != nil { 22 | panic(err) 23 | } 24 | return string(b) 25 | } 26 | 27 | func init() { 28 | log.InitLogger(log.LDebug) 29 | } 30 | 31 | func TestGetThreadContext(t *testing.T) { 32 | t.Log("Entering test") 33 | //name, err := syscall.UTF16PtrFromString(os.Args[0]) 34 | name, err := syscall.UTF16PtrFromString("C:\\Windows\\System32\\cmd.exe") 35 | if err != nil { 36 | panic(err) 37 | } 38 | si := new(syscall.StartupInfo) 39 | pi := new(syscall.ProcessInformation) 40 | t.Logf("Creating new process: %s", os.Args[0]) 41 | syscall.CreateProcess(name, nil, nil, nil, false, win32.CREATE_SUSPENDED|win32.CREATE_NEW_CONSOLE, nil, nil, si, pi) 42 | defer func() { 43 | syscall.TerminateProcess(pi.Process, 0) 44 | }() 45 | 46 | ctx := new(win32.CONTEXT) 47 | ctx.ContextFlags = win32.CONTEXT_FULL 48 | t.Log(ToJSON(ctx)) 49 | err = kernel32.GetThreadContext(win32.HANDLE(pi.Thread), ctx) 50 | if err != nil { 51 | panic(err) 52 | } 53 | t.Logf("Thread context: %s", string(ToJSON(ctx))) 54 | 55 | if err = kernel32.SetThreadContext(win32.HANDLE(pi.Thread), ctx); err != nil { 56 | panic(err) 57 | } 58 | 59 | if _, err = kernel32.ResumeThread(win32.HANDLE(pi.Thread)); err != nil { 60 | panic(err) 61 | } 62 | log.Debug("Sleeping") 63 | time.Sleep(10 * time.Second) 64 | t.Log(ToJSON(ctx)) 65 | } 66 | 67 | func TestVirtualQueryEx(t *testing.T) { 68 | hProcess, _ := kernel32.GetCurrentProcess() 69 | mbi, err := kernel32.VirtualQueryEx(hProcess, win32.LPCVOID(0)) 70 | if err != nil { 71 | panic(err) 72 | } 73 | t.Log(ToJSON(mbi)) 74 | } 75 | 76 | func TestAllVirtualQueryEx(t *testing.T) { 77 | hProcess, _ := kernel32.GetCurrentProcess() 78 | for mbi := range kernel32.AllVirtualQueryEx(hProcess) { 79 | t.Log(ToJSON(mbi)) 80 | } 81 | } 82 | 83 | func TestReadProcessMemory(t *testing.T) { 84 | name, err := syscall.UTF16PtrFromString(os.Args[0]) 85 | if err != nil { 86 | panic(err) 87 | } 88 | si := new(syscall.StartupInfo) 89 | pi := new(syscall.ProcessInformation) 90 | t.Logf("Creating new process: %s", os.Args[0]) 91 | syscall.CreateProcess(name, nil, nil, nil, false, win32.CREATE_SUSPENDED, nil, nil, si, pi) 92 | defer func() { 93 | syscall.TerminateProcess(pi.Process, 0) 94 | }() 95 | 96 | //hProcess, _ := kernel32.GetCurrentProcess() 97 | /*hProcess := win32.HANDLE(pi.Process) 98 | for mbi := range kernel32.AllVirtualQueryEx(hProcess) { 99 | log.Debugf("Attempting to read: %d", mbi.RegionSize) 100 | //mem := make([]byte, mbi.RegionSize, mbi.RegionSize) 101 | mem := make([]byte, 4096, 4096) 102 | //var buff [4096]byte 103 | //r, err := kernel32.ReadProcessMemory(hProcess, win32.LPCVOID(mbi.BaseAddress), buff[:]) 104 | r, err := kernel32.ReadProcessMemory(hProcess, win32.LPCVOID(mbi.BaseAddress), mem) 105 | //mem = append(mem, buff[:]...) 106 | log.Debugf("Read: %d", r) 107 | if err != nil { 108 | t.Logf("Read: %d, Err: %s", r, err.Error()) 109 | } else { 110 | t.Logf("Read: %d", r) 111 | } 112 | }*/ 113 | kernel32.ForceDumpAllMemory(int(pi.ProcessId), "memory.dmp") 114 | } 115 | 116 | func TestThreadFirst32(t *testing.T) { 117 | snap, err := kernel32.CreateToolhelp32Snapshot(win32.DWORD(kernel32.TH32CS_SNAPALL), win32.DWORD(0)) 118 | if err != nil { 119 | t.Error(err) 120 | return 121 | } 122 | defer kernel32.CloseHandle(snap) 123 | te := kernel32.NewThreadEntry32() 124 | ok, err := kernel32.Thread32First(snap, &te) 125 | if !ok { 126 | t.Error(err) 127 | return 128 | } 129 | for ok, _ := kernel32.Thread32Next(snap, &te); ok; { 130 | log.Debug(ToJSON(te)) 131 | ok, _ = kernel32.Thread32Next(snap, &te) 132 | } 133 | } 134 | func TestProcessFirst32(t *testing.T) { 135 | pid := 0 136 | snap, err := kernel32.CreateToolhelp32Snapshot(win32.DWORD(kernel32.TH32CS_SNAPALL), win32.DWORD(pid)) 137 | if err != nil { 138 | t.Error(err) 139 | return 140 | } 141 | defer kernel32.CloseHandle(snap) 142 | pe := kernel32.NewProcessEntry32W() 143 | ok, err := kernel32.Process32FirstW(snap, &pe) 144 | if !ok { 145 | t.Error(err) 146 | return 147 | } 148 | log.Debug(ToJSON(pe)) 149 | } 150 | 151 | func TestListThreads(t *testing.T) { 152 | for tid := range kernel32.ListThreads(os.Getpid()) { 153 | t.Log(tid) 154 | } 155 | } 156 | 157 | func TestSuspendResumeProcess(t *testing.T) { 158 | pid := 5552 159 | sleep := 10 * time.Second 160 | kernel32.SuspendProcess(pid) 161 | log.Infof("Process %d suspended for %s, try to interact with it", pid, sleep) 162 | time.Sleep(sleep) 163 | log.Infof("Resuming %d", pid) 164 | kernel32.ResumeProcess(pid) 165 | 166 | } 167 | 168 | func TestEnumProcessModules(t *testing.T) { 169 | hProcess, _ := kernel32.GetCurrentProcess() 170 | modules, err := kernel32.EnumProcessModules(hProcess) 171 | if err != nil { 172 | t.Log(err) 173 | t.FailNow() 174 | } 175 | t.Log(modules) 176 | for _, hMod := range modules { 177 | modName, err := kernel32.GetModuleFilenameExW(hProcess, hMod) 178 | if err != nil { 179 | t.Log(err) 180 | t.FailNow() 181 | } 182 | t.Log(modName) 183 | modInfo, err := kernel32.GetModuleInformation(hProcess, hMod) 184 | if err != nil { 185 | t.Log(err) 186 | t.FailNow() 187 | } 188 | t.Log(modInfo) 189 | } 190 | } 191 | 192 | func TestGetModuleInfoFromPid(t *testing.T) { 193 | image := "C:\\Windows\\System32\\calc.exe" 194 | kernel32.FindTextSectionFromImage(image) 195 | name, err := syscall.UTF16PtrFromString("C:\\Windows\\System32\\calc.exe") 196 | if err != nil { 197 | panic(err) 198 | } 199 | si := new(syscall.StartupInfo) 200 | pi := new(syscall.ProcessInformation) 201 | t.Logf("Creating process: %s", image) 202 | syscall.CreateProcess(name, nil, nil, nil, false, win32.CREATE_NEW_CONSOLE, nil, nil, si, pi) 203 | if !kernel32.WaitThreadRuns(win32.HANDLE(pi.Thread), time.Second*5, time.Millisecond*100) { 204 | t.Log("Main thread did not run in a decent amount of time") 205 | t.FailNow() 206 | } 207 | time.Sleep(time.Millisecond * 500) 208 | mi, err := kernel32.GetImageModuleInfoFromPID(pi.ProcessId) 209 | if err != nil { 210 | t.Logf("Cannot retrieve ModuleInfo from pid: %s", err) 211 | t.FailNow() 212 | } 213 | t.Logf("Module Information: %s", mi) 214 | text, err := kernel32.FindTextSection(win32.HANDLE(pi.Process), mi) 215 | if err != nil { 216 | t.Logf("Cannot get text section") 217 | t.FailNow() 218 | } 219 | t.Logf("Text section of binary: %s", text) 220 | bdiff, _, err := kernel32.CheckProcessIntegrity(win32.HANDLE(pi.Process)) 221 | if err != nil { 222 | t.Logf("Cannot check process integrity") 223 | t.FailNow() 224 | } 225 | t.Logf("Integrity check: %d", bdiff) 226 | if bdiff > 0 { 227 | t.FailNow() 228 | } 229 | kernel32.TerminateProcess(win32.HANDLE(pi.Process), 0) 230 | } 231 | 232 | func TestQueryDosDevice(t *testing.T) { 233 | devs, err := kernel32.QueryDosDevice("") 234 | if err != nil { 235 | t.Logf("Failed with error: %s", err) 236 | t.Fail() 237 | } 238 | for _, dev := range devs { 239 | d, _ := kernel32.QueryDosDevice(dev) 240 | t.Logf("%s: %v", dev, d) 241 | } 242 | 243 | } 244 | -------------------------------------------------------------------------------- /win32/net.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package win32 4 | 5 | /* 6 | typedef struct in6_addr { 7 | union { 8 | u_char Byte[16]; 9 | u_short Word[8]; 10 | #ifdef __INSIDE_CYGWIN__ 11 | uint32_t __s6_addr32[4]; 12 | #endif 13 | } u; 14 | } IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR; 15 | */ 16 | 17 | type IN6_ADDR [16]byte 18 | -------------------------------------------------------------------------------- /win32/ntdll/headers.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package ntdll 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/0xrawsec/golang-win32/win32" 9 | ) 10 | 11 | type PROCESS_BASIC_INFORMATION struct { 12 | ExitStatus win32.NTSTATUS 13 | PebBaseAddress win32.PPEB 14 | AffinityMask win32.KAFFINITY 15 | BasePriority win32.KPRIORITY 16 | UniqueProcessId win32.ULONG_PTR 17 | InheritedFromUniqueProcessId win32.ULONG_PTR 18 | } 19 | 20 | type UNICODE_STRING struct { 21 | Length win32.USHORT 22 | MaximumLength win32.USHORT 23 | Buffer win32.PWSTR 24 | } 25 | 26 | func (u *UNICODE_STRING) String() string { 27 | return fmt.Sprintf("Length: %d MaximumLength: %d", u.Length, u.MaximumLength) 28 | } 29 | 30 | type OBJECT_ATTRIBUTES struct { 31 | Length win32.ULONG 32 | RootDirectory win32.HANDLE 33 | ObjectName *UNICODE_STRING 34 | Attributes win32.ULONG 35 | SecurityDescriptor win32.PVOID 36 | SecurityQualityOfService win32.PVOID 37 | } 38 | 39 | type IO_STATUS_BLOCK struct { 40 | Union win32.PVOID 41 | Information win32.ULONG_PTR 42 | } 43 | 44 | func (i *IO_STATUS_BLOCK) Status() win32.NTSTATUS { 45 | return win32.NTSTATUS(i.Union) 46 | } 47 | 48 | func (i *IO_STATUS_BLOCK) Pointer() win32.PVOID { 49 | return win32.PVOID(i.Union) 50 | } 51 | 52 | type FILE_LINK_INFORMATION struct { 53 | ReplaceIfExists win32.BOOLEAN 54 | RootDirectory win32.HANDLE 55 | FileNameLength win32.ULONG 56 | FileName win32.WCHAR 57 | } 58 | 59 | const ( 60 | OBJ_INHERIT = 0x00000002 61 | OBJ_PERMANENT = 0x00000010 62 | OBJ_EXCLUSIVE = 0x00000020 63 | OBJ_CASE_INSENSITIVE = 0x00000040 64 | OBJ_OPENIF = 0x00000080 65 | OBJ_OPENLINK = 0x00000100 66 | OBJ_KERNEL_HANDLE = 0x00000200 67 | OBJ_FORCE_ACCESS_CHECK = 0x00000400 68 | OBJ_VALID_ATTRIBUTES = 0x000007F2 69 | 70 | FileDirectoryInformation = iota + 1 71 | FileFullDirectoryInformation 72 | FileBothDirectoryInformation 73 | FileBasicInformation 74 | FileStandardInformation 75 | FileInternalInformation 76 | FileEaInformation 77 | FileAccessInformation 78 | FileNameInformation 79 | FileRenameInformation 80 | FileLinkInformation 81 | FileNamesInformation 82 | FileDispositionInformation 83 | FilePositionInformation 84 | FileFullEaInformation 85 | FileModeInformation 86 | FileAlignmentInformation 87 | FileAllInformation 88 | FileAllocationInformation 89 | FileEndOfFileInformation 90 | FileAlternateNameInformation 91 | FileStreamInformation 92 | FilePipeInformation 93 | FilePipeLocalInformation 94 | FilePipeRemoteInformation 95 | FileMailslotQueryInformation 96 | FileMailslotSetInformation 97 | FileCompressionInformation 98 | FileObjectIdInformation 99 | FileCompletionInformation 100 | FileMoveClusterInformation 101 | FileQuotaInformation 102 | FileReparsePointInformation 103 | FileNetworkOpenInformatio 104 | FileAttributeTagInformation 105 | FileTrackingInformation 106 | FileIdBothDirectoryInformation 107 | FileIdFullDirectoryInformation 108 | FileValidDataLengthInformation 109 | 110 | FileShortNameInformation = 40 111 | FileSfioReserveInformation = 44 112 | FileSfioVolumeInformation = 45 113 | FileHardLinkInformation = 46 114 | FileNormalizedNameInformation = 48 115 | FileIdGlobalTxDirectoryInformation = 50 116 | FileStandardLinkInformation = 54 117 | 118 | FileMaximumInformation 119 | 120 | DELETE = 0x00010000 121 | READ_CONTROL = 0x00020000 122 | WRITE_DAC = 0x00040000 123 | WRITE_OWNER = 0x00080000 124 | SYNCHRONIZE = 0x00100000 125 | 126 | STANDARD_RIGHTS_REQUIRED = 0x000F0000 127 | 128 | STANDARD_RIGHTS_READ = READ_CONTROL 129 | STANDARD_RIGHTS_WRITE = READ_CONTROL 130 | STANDARD_RIGHTS_EXECUTE = READ_CONTROL 131 | 132 | STANDARD_RIGHTS_ALL = 0x001F0000 133 | 134 | SPECIFIC_RIGHTS_ALL = 0x0000FFFF 135 | 136 | ACCESS_SYSTEM_SECURITY = 0x01000000 137 | MAXIMUM_ALLOWED = 0x02000000 138 | 139 | GENERIC_READ = 0x80000000 140 | GENERIC_WRITE = 0x40000000 141 | GENERIC_EXECUTE = 0x20000000 142 | GENERIC_ALL = 0x10000000 143 | 144 | FILE_SHARE_READ = 0x00000001 145 | FILE_SHARE_WRITE = 0x00000002 146 | FILE_SHARE_DELETE = 0x00000004 147 | FILE_SHARE_VALID_FLAGS = 0x00000007 148 | FILE_ATTRIBUTE_READONLY = 0x00000001 149 | FILE_ATTRIBUTE_HIDDEN = 0x00000002 150 | FILE_ATTRIBUTE_SYSTEM = 0x00000004 151 | FILE_ATTRIBUTE_DIRECTORY = 0x00000010 152 | FILE_ATTRIBUTE_ARCHIVE = 0x00000020 153 | FILE_ATTRIBUTE_DEVICE = 0x00000040 154 | FILE_ATTRIBUTE_NORMAL = 0x00000080 155 | FILE_ATTRIBUTE_TEMPORARY = 0x00000100 156 | FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200 157 | FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 158 | FILE_ATTRIBUTE_COMPRESSED = 0x00000800 159 | FILE_ATTRIBUTE_OFFLINE = 0x00001000 160 | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000 161 | FILE_ATTRIBUTE_ENCRYPTED = 0x00004000 162 | FILE_ATTRIBUTE_VIRTUAL = 0x00010000 163 | FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001 164 | FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002 165 | FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004 166 | FILE_NOTIFY_CHANGE_SIZE = 0x00000008 167 | FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010 168 | FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020 169 | FILE_NOTIFY_CHANGE_CREATION = 0x00000040 170 | FILE_NOTIFY_CHANGE_SECURITY = 0x00000100 171 | FILE_ACTION_ADDED = 0x00000001 172 | FILE_ACTION_REMOVED = 0x00000002 173 | FILE_ACTION_MODIFIED = 0x00000003 174 | FILE_ACTION_RENAMED_OLD_NAME = 0x00000004 175 | FILE_ACTION_RENAMED_NEW_NAME = 0x00000005 176 | // Not sure about this one 177 | MAILSLOT_NO_MESSAGE = -1 178 | // Not sure about this one 179 | MAILSLOT_WAIT_FOREVER = -1 180 | FILE_CASE_SENSITIVE_SEARCH = 0x00000001 181 | FILE_CASE_PRESERVED_NAMES = 0x00000002 182 | FILE_UNICODE_ON_DISK = 0x00000004 183 | FILE_PERSISTENT_ACLS = 0x00000008 184 | FILE_FILE_COMPRESSION = 0x00000010 185 | FILE_VOLUME_QUOTAS = 0x00000020 186 | FILE_SUPPORTS_SPARSE_FILES = 0x00000040 187 | FILE_SUPPORTS_REPARSE_POINTS = 0x00000080 188 | FILE_SUPPORTS_REMOTE_STORAGE = 0x00000100 189 | FILE_VOLUME_IS_COMPRESSED = 0x00008000 190 | FILE_SUPPORTS_OBJECT_IDS = 0x00010000 191 | FILE_SUPPORTS_ENCRYPTION = 0x00020000 192 | FILE_NAMED_STREAMS = 0x00040000 193 | FILE_READ_ONLY_VOLUME = 0x00080000 194 | FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000 195 | FILE_SUPPORTS_TRANSACTIONS = 0x00200000 196 | FILE_SUPPORTS_HARD_LINKS = 0x00400000 197 | FILE_SUPPORTS_EXTENDED_ATTRIBUTES = 0x00800000 198 | FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000 199 | FILE_SUPPORTS_USN_JOURNAL = 0x02000000 200 | FILE_SUPPORTS_INTEGRITY_STREAMS = 0x04000000 201 | ) 202 | 203 | /* 204 | typedef struct in6_addr { 205 | union { 206 | UCHAR Byte[16]; 207 | USHORT Word[8]; 208 | } u; 209 | } IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR; 210 | */ 211 | 212 | type In6Addr struct { 213 | u [16]byte 214 | } 215 | -------------------------------------------------------------------------------- /win32/ntdll/ntdll.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package ntdll 4 | 5 | import ( 6 | "syscall" 7 | "unsafe" 8 | 9 | "github.com/0xrawsec/golang-win32/win32" 10 | ) 11 | 12 | // NtStatusToError convert an ntstatus error code to a Go error 13 | func NtStatusToError(ntstatus uintptr) error { 14 | if ntstatus == win32.STATUS_SUCCESS { 15 | return nil 16 | } 17 | return syscall.Errno(RtlNtStatusToDosError(ntstatus)) 18 | } 19 | 20 | // RtlNtStatusToDosError wrapper 21 | func RtlNtStatusToDosError(ntstatus uintptr) uint32 { 22 | r1, _, _ := rtlNtStatusToDosError.Call(ntstatus) 23 | return uint32(r1) 24 | } 25 | 26 | // InitializeObjectAttribute macro 27 | func InitializeObjectAttribute(name *UNICODE_STRING, attr win32.ULONG, root win32.HANDLE) (initializedAttributes *OBJECT_ATTRIBUTES) { 28 | /* VOID InitializeObjectAttributes( 29 | [out] POBJECT_ATTRIBUTES InitializedAttributes, 30 | [in] PUNICODE_STRING ObjectName, 31 | [in] ULONG Attributes, 32 | [in] HANDLE RootDirectory, 33 | [in, optional] PSECURITY_DESCRIPTOR SecurityDescriptor 34 | );*/ 35 | initializedAttributes = &OBJECT_ATTRIBUTES{} 36 | initializedAttributes.ObjectName = name 37 | initializedAttributes.Attributes = attr 38 | initializedAttributes.RootDirectory = root 39 | initializedAttributes.SecurityDescriptor = 0 40 | return initializedAttributes 41 | } 42 | 43 | // RtlInitUnicodeString wrapper 44 | func RtlInitUnicodeString(src string) (dest *UNICODE_STRING) { 45 | /* void RtlInitUnicodeString( 46 | PUNICODE_STRING DestinationString, 47 | PCWSTR SourceString 48 | ); */ 49 | dest = &UNICODE_STRING{} 50 | rtlInitUnicodeString.Call( 51 | uintptr(unsafe.Pointer(dest)), 52 | uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(src))), 53 | ) 54 | return dest 55 | } 56 | 57 | // NtOpenFile wrapper 58 | func NtOpenFile( 59 | accessMask win32.ACCESS_MASK, 60 | objectAttributes *OBJECT_ATTRIBUTES, 61 | ioStatusBlock *IO_STATUS_BLOCK, 62 | shareAccess win32.ULONG, 63 | openOptions win32.ULONG) (fileHandle win32.HANDLE, err error) { 64 | 65 | /*__kernel_entry NTSTATUS NtOpenFile( 66 | OUT PHANDLE FileHandle, 67 | IN ACCESS_MASK DesiredAccess, 68 | IN POBJECT_ATTRIBUTES ObjectAttributes, 69 | OUT PIO_STATUS_BLOCK IoStatusBlock, 70 | IN ULONG ShareAccess, 71 | IN ULONG OpenOptions 72 | );*/ 73 | 74 | ntstatus, _, _ := ntOpenFile.Call( 75 | uintptr(unsafe.Pointer(&fileHandle)), 76 | uintptr(accessMask), 77 | uintptr(unsafe.Pointer(objectAttributes)), 78 | uintptr(unsafe.Pointer(ioStatusBlock)), 79 | uintptr(shareAccess), 80 | uintptr(openOptions), 81 | ) 82 | 83 | err = NtStatusToError(ntstatus) 84 | return 85 | } 86 | 87 | // ZwSetInformationFile wrapper 88 | func ZwSetInformationFile(fileHandle win32.HANDLE, ioStatusBlock *IO_STATUS_BLOCK, fileInformation win32.PVOID, length win32.ULONG, fileInformationClass uintptr) error { 89 | /* __kernel_entry NTSYSCALLAPI NTSTATUS NtSetInformationFile( 90 | HANDLE FileHandle, 91 | PIO_STATUS_BLOCK IoStatusBlock, 92 | PVOID FileInformation, 93 | ULONG Length, 94 | FILE_INFORMATION_CLASS FileInformationClass 95 | );*/ 96 | 97 | ntstatus, _, _ := ntSetInformationFile.Call( 98 | uintptr(fileHandle), 99 | uintptr(unsafe.Pointer(ioStatusBlock)), 100 | uintptr(fileInformation), 101 | uintptr(length), 102 | fileInformationClass, 103 | ) 104 | return NtStatusToError(ntstatus) 105 | } 106 | 107 | // NtQueryInformationProcess Win32 API wrapper 108 | // TODO: test it 109 | func NtQueryInformationProcess(hProcess win32.HANDLE, 110 | processInfoClass win32.DWORD, 111 | processInfo win32.PVOID, 112 | processInfoLength win32.ULONG, 113 | returnLength win32.ULONG_PTR) error { 114 | r1, _, lastErr := ntQueryInformationProcess.Call( 115 | uintptr(hProcess), 116 | uintptr(processInfoClass), 117 | uintptr(processInfo), 118 | uintptr(processInfoLength), 119 | uintptr(returnLength)) 120 | if r1 == 0 { 121 | return nil 122 | } 123 | return lastErr 124 | } 125 | 126 | // NtUnmapViewOfSection Win32 API wrapper 127 | // https://msdn.microsoft.com/en-us/library/windows/hardware/ff567119(v=vs.85).aspx 128 | // TODO: test it 129 | func NtUnmapViewOfSection(hProcess win32.HANDLE, baseAddress win32.PVOID) error { 130 | r1, _, lastError := ntUnmapViewOfSection.Call(uintptr(hProcess), uintptr(baseAddress)) 131 | if r1 == 0 { 132 | return nil 133 | } 134 | return lastError 135 | } 136 | 137 | /* 138 | RtlIpv6AddressToStringW API wrapper generated from prototype 139 | NTSYSAPI PWSTR RtlIpv6AddressToStringW( 140 | const in6_addr *Addr, 141 | PWSTR S ); 142 | */ 143 | func RtlIpv6AddressToStringW( 144 | addr *In6Addr, 145 | s *uint16) *uint16 { 146 | r1, _, _ := rtlIpv6AddressToStringW.Call( 147 | uintptr(unsafe.Pointer(addr)), 148 | uintptr(unsafe.Pointer(s))) 149 | return (*uint16)(unsafe.Pointer(r1)) 150 | } 151 | 152 | /* 153 | RtlIpv6AddressToStringExW API wrapper generated from prototype 154 | NTSYSAPI NTSTATUS RtlIpv6AddressToStringExW( 155 | const in6_addr *Address, 156 | ULONG ScopeId, 157 | USHORT Port, 158 | PWSTR AddressString, 159 | PULONG AddressStringLength ); 160 | */ 161 | func RtlIpv6AddressToStringExW( 162 | address *In6Addr, 163 | scopeId uint32, 164 | port uint16, 165 | addressString *uint16, 166 | addressStringLength *uint32) error { 167 | ntstatus, _, _ := rtlIpv6AddressToStringExW.Call( 168 | uintptr(unsafe.Pointer(address)), 169 | uintptr(scopeId), 170 | uintptr(port), 171 | uintptr(unsafe.Pointer(addressString)), 172 | uintptr(unsafe.Pointer(addressStringLength))) 173 | return NtStatusToError(ntstatus) 174 | } 175 | -------------------------------------------------------------------------------- /win32/structs.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package win32 4 | 5 | import "fmt" 6 | 7 | /* 8 | typedef struct _GUID { 9 | DWORD Data1; 10 | WORD Data2; 11 | WORD Data3; 12 | BYTE Data4[8]; 13 | } GUID; 14 | */ 15 | 16 | // GUID structure manually ported 17 | type GUID struct { 18 | Data1 uint32 19 | Data2 uint16 20 | Data3 uint16 21 | Data4 [8]byte 22 | } 23 | 24 | func (g *GUID) String() string { 25 | return fmt.Sprintf("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", 26 | g.Data1, 27 | g.Data2, 28 | g.Data3, 29 | g.Data4[0], g.Data4[1], 30 | g.Data4[2], g.Data4[3], g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]) 31 | } 32 | -------------------------------------------------------------------------------- /win32/user32/test/user32_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | "win32/user32" 6 | ) 7 | 8 | func TestMessageBox(t *testing.T) { 9 | 10 | if rc, err := user32.MessageBox(0, "Message box popped\nfrom Golang", "Go user32.dll wrapper", 0); err != nil { 11 | t.Logf("rc:%d error:%s", rc, err) 12 | t.FailNow() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /win32/user32/user32.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package user32 4 | 5 | import ( 6 | "syscall" 7 | "unsafe" 8 | 9 | "github.com/0xrawsec/golang-win32/win32" 10 | ) 11 | 12 | func MessageBox(hWnd win32.HWND, text, caption string, uType win32.UINT) (int, error) { 13 | lpText := syscall.StringToUTF16Ptr(text) 14 | lpCaption := syscall.StringToUTF16Ptr(caption) 15 | rc, _, err := messageBoxW.Call( 16 | uintptr(hWnd), 17 | uintptr(unsafe.Pointer(lpText)), 18 | uintptr(unsafe.Pointer(lpCaption)), 19 | uintptr(uType)) 20 | if rc == 0 { 21 | return int(rc), err 22 | } 23 | return int(rc), nil 24 | } 25 | -------------------------------------------------------------------------------- /win32/wevtapi/exports.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package wevtapi 4 | 5 | import "syscall" 6 | 7 | var ( 8 | wevtapi = syscall.NewLazyDLL("wevtapi.dll") 9 | evtArchiveExportedLog = wevtapi.NewProc("EvtArchiveExportedLog") 10 | evtCancel = wevtapi.NewProc("EvtCancel") 11 | evtClearLog = wevtapi.NewProc("EvtClearLog") 12 | evtClose = wevtapi.NewProc("EvtClose") 13 | evtCreateBookmark = wevtapi.NewProc("EvtCreateBookmark") 14 | evtCreateRenderContext = wevtapi.NewProc("EvtCreateRenderContext") 15 | evtExportLog = wevtapi.NewProc("EvtExportLog") 16 | evtFormatMessage = wevtapi.NewProc("EvtFormatMessage") 17 | evtGetChannelConfigProperty = wevtapi.NewProc("EvtGetChannelConfigProperty") 18 | evtGetEventInfo = wevtapi.NewProc("EvtGetEventInfo") 19 | evtGetEventMetadataProperty = wevtapi.NewProc("EvtGetEventMetadataProperty") 20 | evtGetExtendedStatus = wevtapi.NewProc("EvtGetExtendedStatus") 21 | evtGetLogInfo = wevtapi.NewProc("EvtGetLogInfo") 22 | evtGetObjectArrayProperty = wevtapi.NewProc("EvtGetObjectArrayProperty") 23 | evtGetObjectArraySize = wevtapi.NewProc("EvtGetObjectArraySize") 24 | evtGetPublisherMetadataProperty = wevtapi.NewProc("EvtGetPublisherMetadataProperty") 25 | evtGetQueryInfo = wevtapi.NewProc("EvtGetQueryInfo") 26 | evtIntAssertConfig = wevtapi.NewProc("EvtIntAssertConfig") 27 | evtIntCreateBinXMLFromCustomXML = wevtapi.NewProc("EvtIntCreateBinXMLFromCustomXML") 28 | evtIntCreateLocalLogfile = wevtapi.NewProc("EvtIntCreateLocalLogfile") 29 | evtIntGetClassicLogDisplayName = wevtapi.NewProc("EvtIntGetClassicLogDisplayName") 30 | evtIntRenderResourceEventTemplate = wevtapi.NewProc("EvtIntRenderResourceEventTemplate") 31 | evtIntReportAuthzEventAndSourceAsync = wevtapi.NewProc("EvtIntReportAuthzEventAndSourceAsync") 32 | evtIntReportEventAndSourceAsync = wevtapi.NewProc("EvtIntReportEventAndSourceAsync") 33 | evtIntRetractConfig = wevtapi.NewProc("EvtIntRetractConfig") 34 | evtIntSysprepCleanup = wevtapi.NewProc("EvtIntSysprepCleanup") 35 | evtIntWriteXmlEventToLocalLogfile = wevtapi.NewProc("EvtIntWriteXmlEventToLocalLogfile") 36 | evtNextChannelPath = wevtapi.NewProc("EvtNextChannelPath") 37 | evtNextEventMetadata = wevtapi.NewProc("EvtNextEventMetadata") 38 | evtNextPublisherId = wevtapi.NewProc("EvtNextPublisherId") 39 | evtNext = wevtapi.NewProc("EvtNext") 40 | evtOpenChannelConfig = wevtapi.NewProc("EvtOpenChannelConfig") 41 | evtOpenChannelEnum = wevtapi.NewProc("EvtOpenChannelEnum") 42 | evtOpenEventMetadataEnum = wevtapi.NewProc("EvtOpenEventMetadataEnum") 43 | evtOpenLog = wevtapi.NewProc("EvtOpenLog") 44 | evtOpenPublisherEnum = wevtapi.NewProc("EvtOpenPublisherEnum") 45 | evtOpenPublisherMetadata = wevtapi.NewProc("EvtOpenPublisherMetadata") 46 | evtOpenSession = wevtapi.NewProc("EvtOpenSession") 47 | evtQuery = wevtapi.NewProc("EvtQuery") 48 | evtRender = wevtapi.NewProc("EvtRender") 49 | evtSaveChannelConfig = wevtapi.NewProc("EvtSaveChannelConfig") 50 | evtSeek = wevtapi.NewProc("EvtSeek") 51 | evtSetChannelConfigProperty = wevtapi.NewProc("EvtSetChannelConfigProperty") 52 | evtSetObjectArrayProperty = wevtapi.NewProc("EvtSetObjectArrayProperty") 53 | evtSubscribe = wevtapi.NewProc("EvtSubscribe") 54 | evtUpdateBookmark = wevtapi.NewProc("EvtUpdateBookmark") 55 | ) 56 | -------------------------------------------------------------------------------- /win32/wevtapi/headers.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package wevtapi 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/0xrawsec/golang-utils/log" 9 | "github.com/0xrawsec/golang-win32/win32" 10 | ) 11 | 12 | // Should be an enum _EVT_SUBSCRIBE_NOTIFY_ACTION 13 | type EVT_SUBSCRIBE_NOTIFY_ACTION int 14 | 15 | const ( 16 | // EVT_SUBSCRIBE_NOTIFY_ACTION enum: https://msdn.microsoft.com/en-us/library/windows/desktop/aa385596(v=vs.85).aspx 17 | //typedef enum _EVT_SUBSCRIBE_NOTIFY_ACTION { 18 | EvtSubscribeActionError = 0 19 | EvtSubscribeActionDeliver = 1 20 | //} EVT_SUBSCRIBE_NOTIFY_ACTION; 21 | 22 | // EVT_RENDER_FLAGS enum: https://msdn.microsoft.com/en-us/library/windows/desktop/aa385563(v=vs.85).aspx 23 | //typedef enum _EVT_RENDER_FLAGS { 24 | EvtRenderEventValues = 0 25 | EvtRenderEventXml = 1 26 | EvtRenderBookmark = 2 27 | //} EVT_RENDER_FLAGS; 28 | 29 | // EVT_SUBSCRIBE_FLAGS enum: https://msdn.microsoft.com/en-us/library/windows/desktop/aa385588(v=vs.85).aspx 30 | //typedef enum _EVT_SUBSCRIBE_FLAGS { 31 | EvtSubscribeToFutureEvents = 1 32 | EvtSubscribeStartAtOldestRecord = 2 33 | EvtSubscribeStartAfterBookmark = 3 34 | EvtSubscribeOriginMask = 0x3 35 | EvtSubscribeTolerateQueryErrors = 0x1000 36 | EvtSubscribeStrict = 0x10000 37 | //} EVT_SUBSCRIBE_FLAGS; 38 | ) 39 | 40 | const ( 41 | ERROR_EVT_INVALID_CHANNEL_PATH = 15000 42 | ERROR_EVT_INVALID_QUERY = 15001 43 | ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND = 15002 44 | ERROR_EVT_EVENT_TEMPLATE_NOT_FOUND = 15003 45 | ERROR_EVT_INVALID_PUBLISHER_NAME = 15004 46 | ERROR_EVT_INVALID_EVENT_DATA = 15005 47 | ERROR_EVT_CHANNEL_NOT_FOUND = 15007 48 | ERROR_EVT_MALFORMED_XML_TEXT = 15008 49 | ERROR_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL = 15009 50 | ERROR_EVT_CONFIGURATION_ERROR = 15010 51 | ERROR_EVT_QUERY_RESULT_STALE = 15011 52 | ERROR_EVT_QUERY_RESULT_INVALID_POSITION = 15012 53 | ERROR_EVT_NON_VALIDATING_MSXML = 15013 54 | ERROR_EVT_FILTER_ALREADYSCOPED = 15014 55 | ERROR_EVT_FILTER_NOTELTSET = 15015 56 | ERROR_EVT_FILTER_INVARG = 15016 57 | ERROR_EVT_FILTER_INVTEST = 15017 58 | ERROR_EVT_FILTER_INVTYPE = 15018 59 | ERROR_EVT_FILTER_PARSEERR = 15019 60 | ERROR_EVT_FILTER_UNSUPPORTEDOP = 15020 61 | ERROR_EVT_FILTER_UNEXPECTEDTOKEN = 15021 62 | ERROR_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL = 15022 63 | ERROR_EVT_INVALID_CHANNEL_PROPERTY_VALUE = 15023 64 | ERROR_EVT_INVALID_PUBLISHER_PROPERTY_VALUE = 15024 65 | ERROR_EVT_CHANNEL_CANNOT_ACTIVATE = 15025 66 | ERROR_EVT_FILTER_TOO_COMPLEX = 15026 67 | ERROR_EVT_MESSAGE_NOT_FOUND = 15027 68 | ERROR_EVT_MESSAGE_ID_NOT_FOUND = 15028 69 | ERROR_EVT_UNRESOLVED_VALUE_INSERT = 15029 70 | ERROR_EVT_UNRESOLVED_PARAMETER_INSERT = 15030 71 | ERROR_EVT_MAX_INSERTS_REACHED = 15031 72 | ERROR_EVT_EVENT_DEFINITION_NOT_FOUND = 15032 73 | ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND = 15033 74 | ERROR_EVT_VERSION_TOO_OLD = 15034 75 | ERROR_EVT_VERSION_TOO_NEW = 15035 76 | ERROR_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY = 15036 77 | ERROR_EVT_PUBLISHER_DISABLED = 15037 78 | ERROR_EVT_FILTER_OUT_OF_RANGE = 15038 79 | ) 80 | 81 | type EVT_SUBSCRIBE_CALLBACK func(Action EVT_SUBSCRIBE_NOTIFY_ACTION, UserContext win32.PVOID, Event EVT_HANDLE) uintptr 82 | type EVT_HANDLE win32.HANDLE 83 | 84 | func TestCallback(Action EVT_SUBSCRIBE_NOTIFY_ACTION, UserContext win32.PVOID, Event EVT_HANDLE) uintptr { 85 | log.Info("In TestCallback") 86 | fmt.Printf("Super it works\n") 87 | return uintptr(0) 88 | } 89 | -------------------------------------------------------------------------------- /win32/wevtapi/helpers.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package wevtapi 4 | 5 | import ( 6 | "bytes" 7 | "encoding/xml" 8 | "fmt" 9 | "io" 10 | "syscall" 11 | "unsafe" 12 | 13 | "github.com/0xrawsec/golang-utils/log" 14 | "github.com/0xrawsec/golang-win32/win32" 15 | "github.com/0xrawsec/golang-win32/win32/kernel32" 16 | ) 17 | 18 | ///////////////////////////////// XMLMap /////////////////////////////////////// 19 | // Code adapted from source 20 | // Source: https://stackoverflow.com/questions/30928770/marshall-map-to-xml-in-go#33110881 21 | // Source: https://play.golang.org/p/4Z2C-GF0E7 22 | 23 | type XMLMap map[string]interface{} 24 | 25 | type xmlMapEntry struct { 26 | XMLName xml.Name 27 | Value string `xml:",chardata"` 28 | InnerXML string `xml:",innerxml"` 29 | } 30 | 31 | // MarshalXML marshals the map to XML, with each key in the map being a 32 | // tag and it's corresponding value being it's contents. 33 | /*func (m XMLMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 34 | if len(m) == 0 { 35 | return nil 36 | } 37 | 38 | err := e.EncodeToken(start) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | for k, v := range m { 44 | e.Encode(xmlMapEntry{XMLName: xml.Name{Local: k}, Value: v}) 45 | } 46 | 47 | return e.EncodeToken(start.End()) 48 | }*/ 49 | 50 | // UnmarshalXML unmarshals the XML into a map of string to strings, 51 | // creating a key in the map for each tag and setting it's value to the 52 | // tags contents. 53 | // 54 | // The fact this function is on the pointer of Map is important, so that 55 | // if m is nil it can be initialized, which is often the case if m is 56 | // nested in another xml structurel. This is also why the first thing done 57 | // on the first line is initialize it. 58 | func (m *XMLMap) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 59 | *m = XMLMap{} 60 | for { 61 | var e xmlMapEntry 62 | 63 | err := d.Decode(&e) 64 | if err == io.EOF { 65 | break 66 | } else if err != nil { 67 | return err 68 | } 69 | if e.InnerXML != "" { 70 | var sm XMLMap 71 | r := bytes.NewBuffer([]byte(e.InnerXML)) 72 | dec := xml.NewDecoder(r) 73 | err := sm.UnmarshalXML(dec, xml.StartElement{}) 74 | 75 | if err == io.EOF { 76 | break 77 | } else if err != nil { 78 | return err 79 | } 80 | (*m)[e.XMLName.Local] = sm 81 | } 82 | if e.Value != "" { 83 | (*m)[e.XMLName.Local] = e.Value 84 | } 85 | } 86 | return nil 87 | } 88 | 89 | ///////////////////////////////// XMLEvent ///////////////////////////////////// 90 | 91 | type Data struct { 92 | Name string `xml:"Name,attr"` 93 | Value string `xml:",innerxml"` 94 | } //`xml:"Data"` 95 | 96 | type XMLEvent struct { 97 | // seems to always have the same format 98 | // if not consider using XMLMap 99 | EventData struct { 100 | Data []Data 101 | } `xml:"EventData,omitempty"` 102 | // Using XMLMap type because we don't know what is inside (a priori) 103 | UserData XMLMap 104 | System struct { 105 | Provider struct { 106 | Name string `xml:"Name,attr"` 107 | Guid string `xml:"Guid,attr"` 108 | } `xml:"Provider"` 109 | EventID string `xml:"EventID"` 110 | Version string `xml:"Version"` 111 | Level string `xml:"Level"` 112 | Task string `xml:"Task"` 113 | Opcode string `xml:"Opcode"` 114 | Keywords string `xml:"Keywords"` 115 | TimeCreated struct { 116 | SystemTime string `xml:"SystemTime,attr"` 117 | } `xml:"TimeCreated"` 118 | EventRecordID string `xml:"EventRecordID"` 119 | Correlation struct { 120 | } `xml:"Correlation"` 121 | Execution struct { 122 | ProcessID string `xml:"ProcessID,attr"` 123 | ThreadID string `xml:"ThreadID,attr"` 124 | } `xml:"Execution"` 125 | Channel string `xml:"Channel"` 126 | Computer string `xml:"Computer"` 127 | Security struct { 128 | UserID string `xml:"UserID,attr"` 129 | } `xml:"Security"` 130 | } `xml:"System"` 131 | } 132 | 133 | // ToMap converts an XMLEvent to an accurate structure to be serialized 134 | // where EventData / UserData does not appear if empty 135 | func (xe *XMLEvent) ToMap() *map[string]interface{} { 136 | m := make(map[string]interface{}) 137 | m["Event"] = make(map[string]interface{}) 138 | if len(xe.EventData.Data) > 0 { 139 | m["Event"].(map[string]interface{})["EventData"] = make(map[string]interface{}) 140 | for _, d := range xe.EventData.Data { 141 | m["Event"].(map[string]interface{})["EventData"].(map[string]interface{})[d.Name] = d.Value 142 | } 143 | } 144 | if len(xe.UserData) > 0 { 145 | m["Event"].(map[string]interface{})["UserData"] = xe.UserData 146 | } 147 | m["Event"].(map[string]interface{})["System"] = xe.System 148 | return &m 149 | } 150 | 151 | func (xe *XMLEvent) ToJSONEvent() *JSONEvent { 152 | je := NewJSONEvent() 153 | for _, d := range xe.EventData.Data { 154 | je.Event.EventData[d.Name] = d.Value 155 | } 156 | je.Event.UserData = xe.UserData 157 | // System 158 | je.Event.System.Provider.Name = xe.System.Provider.Name 159 | je.Event.System.Provider.Guid = xe.System.Provider.Guid 160 | je.Event.System.EventID = xe.System.EventID 161 | je.Event.System.Version = xe.System.Version 162 | je.Event.System.Level = xe.System.Level 163 | je.Event.System.Task = xe.System.Task 164 | je.Event.System.Opcode = xe.System.Opcode 165 | je.Event.System.Keywords = xe.System.Keywords 166 | je.Event.System.TimeCreated.SystemTime = xe.System.TimeCreated.SystemTime 167 | je.Event.System.EventRecordID = xe.System.EventRecordID 168 | je.Event.System.Correlation = xe.System.Correlation 169 | je.Event.System.Execution.ProcessID = xe.System.Execution.ProcessID 170 | je.Event.System.Execution.ThreadID = xe.System.Execution.ThreadID 171 | je.Event.System.Channel = xe.System.Channel 172 | je.Event.System.Computer = xe.System.Computer 173 | je.Event.System.Security.UserID = xe.System.Security.UserID 174 | return &je 175 | } 176 | 177 | //////////////////////////////// JSONEvent ///////////////////////////////////// 178 | 179 | //JSONEvent structure definition 180 | type JSONEvent struct { 181 | Event struct { 182 | EventData map[string]string `xml:"EventData" json:",omitempty"` 183 | UserData map[string]interface{} `json:",omitempty"` 184 | System struct { 185 | Provider struct { 186 | Name string `xml:"Name,attr"` 187 | Guid string `xml:"Guid,attr"` 188 | } `xml:"Provider"` 189 | EventID string `xml:"EventID"` 190 | Version string `xml:"Version"` 191 | Level string `xml:"Level"` 192 | Task string `xml:"Task"` 193 | Opcode string `xml:"Opcode"` 194 | Keywords string `xml:"Keywords"` 195 | TimeCreated struct { 196 | SystemTime string `xml:"SystemTime,attr"` 197 | } `xml:"TimeCreated"` 198 | EventRecordID string `xml:"EventRecordID"` 199 | Correlation struct { 200 | } `xml:"Correlation"` 201 | Execution struct { 202 | ProcessID string `xml:"ProcessID,attr"` 203 | ThreadID string `xml:"ThreadID,attr"` 204 | } `xml:"Execution"` 205 | Channel string `xml:"Channel"` 206 | Computer string `xml:"Computer"` 207 | Security struct { 208 | UserID string `xml:"UserID,attr"` 209 | } `xml:"Security"` 210 | } `xml:"System"` 211 | } 212 | } 213 | 214 | // NewJSONEvent creates a new JSONEvent structure 215 | func NewJSONEvent() (je JSONEvent) { 216 | je.Event.EventData = make(map[string]string) 217 | return je 218 | } 219 | 220 | /////////////////////////// Interface definition ////////////////////////////// 221 | 222 | // EventProvider interface definition 223 | type EventProvider interface { 224 | FetchEvents(channels []string, flag int) (c chan *XMLEvent) 225 | Stop() 226 | } 227 | 228 | /////////////////////////// PullEventProvider ////////////////////////////////// 229 | 230 | func GotSignal(signals chan bool) (signal bool, gotsig bool) { 231 | select { 232 | case sig := <-signals: 233 | return sig, true 234 | default: 235 | } 236 | return false, false 237 | } 238 | 239 | func enumerateEvents(sub EVT_HANDLE, channel string, out chan *XMLEvent) (err error) { 240 | for { 241 | // Try to get events 242 | events, err := EvtNext(sub, win32.INFINITE) 243 | if err != nil { 244 | log.Debugf("EvtNext cannot get events (Channel:%s Errno: %d): %s", channel, err.(syscall.Errno), err) 245 | return err 246 | } 247 | 248 | // Looping over the events retrieved 249 | for _, evt := range events { 250 | 251 | // Render event to XML 252 | data, err := EvtRenderXML(evt) 253 | if err != nil { 254 | log.Errorf("Cannot Render event to XML: %s", err) 255 | log.Debugf("Partial Event: %s", data) 256 | } 257 | 258 | // Convert event to UTF8 before being processed by xml.Unmarshal 259 | dataUTF8 := win32.UTF16BytesToString(data) 260 | e := XMLEvent{} 261 | err = xml.Unmarshal([]byte(dataUTF8), &e) 262 | if err != nil { 263 | log.Errorf("Cannot unmarshal event: %s", err) 264 | log.Debugf("Event unmarshal failure: %s", dataUTF8) 265 | } 266 | // Pushing reference to XMLEvent into the channel 267 | out <- &e 268 | 269 | // Close the event anyway 270 | // Recommended: https://msdn.microsoft.com/en-us/library/windows/desktop/aa385344(v=vs.85).aspx 271 | EvtClose(evt) 272 | } 273 | } 274 | } 275 | 276 | // PullEventProvider structure definition. Windows event provider using the 277 | // "Pull" design pattern (i.e. not using callback function from EvtSubscribe). 278 | type PullEventProvider struct { 279 | stop bool 280 | } 281 | 282 | // NewPullEventProvider PullEventProvider constructor 283 | func NewPullEventProvider() *PullEventProvider { 284 | return &PullEventProvider{} 285 | } 286 | 287 | // FetchEvents implements EventProvider interface 288 | func (e *PullEventProvider) FetchEvents(channels []string, flag int) (c chan *XMLEvent) { 289 | // Prep the chan 290 | c = make(chan *XMLEvent, 242) 291 | events := make([]win32.HANDLE, len(channels)) 292 | subs := make([]EVT_HANDLE, len(channels)) 293 | 294 | // Initializing all the events to listen to 295 | for i, channel := range channels { 296 | // Creating event 297 | // If we reuse name, we reuse event, even across processes 298 | eUUID, err := win32.UUID() 299 | if err != nil { 300 | log.Abort(1, fmt.Errorf("Cannot generate UUID: %s", err)) 301 | } 302 | 303 | log.Debugf("Windows Event UUID (Channel:%s): %s", channel, eUUID) 304 | events[i], err = kernel32.CreateEvent(0, win32.TRUE, win32.TRUE, eUUID) 305 | if err != nil { 306 | log.Errorf("Cannot create event: %s", err) 307 | close(c) 308 | return 309 | } 310 | 311 | subs[i], err = EvtPullSubscribe( 312 | EVT_HANDLE(win32.NULL), 313 | events[i], 314 | channel, 315 | "*", 316 | EVT_HANDLE(win32.NULL), 317 | win32.PVOID(win32.NULL), 318 | win32.DWORD(flag)) 319 | 320 | if err != nil { 321 | log.Errorf("Failed to subscribe to channel \"%s\": %s", channel, err) 322 | close(c) 323 | return 324 | } 325 | } 326 | 327 | // Go routine returning the events 328 | go func() { 329 | // Closing output channel 330 | defer close(c) 331 | // Closing the subscriptions 332 | defer func() { 333 | for _, sub := range subs { 334 | EvtClose(sub) 335 | } 336 | }() 337 | // Closing events 338 | defer func() { 339 | for _, event := range events { 340 | kernel32.CloseHandle(event) 341 | } 342 | }() 343 | 344 | PollLoop: 345 | for !e.stop { 346 | rc := kernel32.WaitForMultipleObjects(events, win32.FALSE, 500) 347 | switch { 348 | case rc == win32.WAIT_TIMEOUT: 349 | if e.stop { 350 | return 351 | } 352 | 353 | case rc >= win32.WAIT_OBJECT_0 && rc < win32.MAXIMUM_WAIT_OBJECTS: 354 | log.Debugf("Events are ready, (Channel: %s): 0x%08x", channels[rc], rc) 355 | // We need to ResetEvent asap 356 | // My theory why MS code does not work for high freq events: 357 | // If we reset after enumerating, the event might get into a signalled state (by the publisher) 358 | // between enumerateEvents and ResetEvent. This means that Resetting events 359 | // creates a deadlock (publisher will not put in a signalled state because it thinks 360 | // it did it already and we reset the event) so WaitForSingleObject will return 361 | // only timeouts. Took a while to find this explaination ... 362 | kernel32.ResetEvent(events[rc]) 363 | if err := enumerateEvents(subs[rc], channels[rc], c); err.(syscall.Errno) != win32.ERROR_NO_MORE_ITEMS { 364 | // If != of Exit Success 365 | if err.(syscall.Errno) != 0 { 366 | log.Errorf("Failed to enumerate events for channel %s: %s", channels[rc], err) 367 | } 368 | break PollLoop 369 | } 370 | default: 371 | log.Errorf("Wait failed: %s", syscall.GetLastError()) 372 | break PollLoop 373 | } 374 | } 375 | }() 376 | return 377 | } 378 | 379 | // Stop implements EventProvider interface 380 | func (e *PullEventProvider) Stop() { 381 | e.stop = true 382 | } 383 | 384 | /////////////////////////// PushEventProvider ////////////////////////////////// 385 | 386 | const ( 387 | pushProviderChanSize = 42 388 | ) 389 | 390 | // PushEventProvider relies on push EventSubscribe design pattern (i.e. using a callback) 391 | // function when calling EventSubscribe API 392 | type PushEventProvider struct { 393 | subscriptions []EVT_HANDLE 394 | ctx *pepContext 395 | } 396 | 397 | type pepContext struct { 398 | xmlRenderedEvents chan []byte 399 | lastError error 400 | } 401 | 402 | func pepCallback(Action EVT_SUBSCRIBE_NOTIFY_ACTION, UserContext win32.PVOID, Event EVT_HANDLE) uintptr { 403 | ctx := (*pepContext)(unsafe.Pointer(UserContext)) 404 | switch Action { 405 | case EvtSubscribeActionDeliver: 406 | data, err := EvtRenderXML(Event) 407 | if err != nil { 408 | ctx.lastError = err 409 | log.Errorf("Callback cannot Render event to XML: %s", err) 410 | log.Debugf("Partial Event: %s", data) 411 | } 412 | ctx.xmlRenderedEvents <- data 413 | case EvtSubscribeActionError: 414 | if Event == ERROR_EVT_QUERY_RESULT_STALE { 415 | ctx.lastError = fmt.Errorf("Event record is missing") 416 | log.Error(ctx.lastError) 417 | } else { 418 | ctx.lastError = syscall.Errno(Event) 419 | log.Errorf("Callback received error: %s", ctx.lastError) 420 | } 421 | } 422 | return uintptr(0) 423 | } 424 | 425 | // NewPushEventProvider constructs a new PushEventProvider 426 | func NewPushEventProvider() *PushEventProvider { 427 | return &PushEventProvider{ 428 | make([]EVT_HANDLE, 0), 429 | &pepContext{make(chan []byte, pushProviderChanSize), nil}} 430 | } 431 | 432 | // FetchEvents implements EventProvider interface 433 | func (p *PushEventProvider) FetchEvents(channels []string, flag int) (c chan *XMLEvent) { 434 | c = make(chan *XMLEvent, pushProviderChanSize) 435 | 436 | // Initializing all the events to listen to 437 | for _, channel := range channels { 438 | sub, err := EvtSubscribe( 439 | EVT_HANDLE(win32.NULL), 440 | win32.HANDLE(win32.NULL), 441 | channel, 442 | "*", 443 | EVT_HANDLE(win32.NULL), 444 | win32.PVOID(unsafe.Pointer(p.ctx)), 445 | pepCallback, 446 | win32.DWORD(flag)) 447 | 448 | if err != nil { 449 | log.Errorf("Failed to subscribe to channel \"%s\": %s", channel, err) 450 | close(c) 451 | return 452 | } 453 | p.subscriptions = append(p.subscriptions, sub) 454 | } 455 | 456 | go func() { 457 | defer close(c) 458 | for dataXML := range p.ctx.xmlRenderedEvents { 459 | dataUTF8 := win32.UTF16BytesToString(dataXML) 460 | e := XMLEvent{} 461 | err := xml.Unmarshal([]byte(dataUTF8), &e) 462 | if err != nil { 463 | log.Errorf("Cannot unmarshal event: %s", err) 464 | log.Debugf("Event unmarshal failure: %s", dataUTF8) 465 | } 466 | c <- &e 467 | } 468 | }() 469 | return c 470 | } 471 | 472 | // Stop implements EventProvider interface 473 | func (p *PushEventProvider) Stop() { 474 | for _, sub := range p.subscriptions { 475 | EvtClose(sub) 476 | } 477 | close(p.ctx.xmlRenderedEvents) 478 | } 479 | -------------------------------------------------------------------------------- /win32/wevtapi/wevtapi.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package wevtapi 4 | 5 | import ( 6 | "syscall" 7 | "unsafe" 8 | 9 | "github.com/0xrawsec/golang-win32/win32" 10 | ) 11 | 12 | // EvtClose wrapper 13 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa385344(v=vs.85).aspx 14 | func EvtClose(Object EVT_HANDLE) error { 15 | r1, _, lastErr := evtClose.Call(uintptr(Object)) 16 | if win32.BOOL(r1) == win32.FALSE { 17 | return lastErr 18 | } 19 | return nil 20 | } 21 | 22 | func EvtSubscribe( 23 | Session EVT_HANDLE, 24 | SignalEvent win32.HANDLE, 25 | ChannelPath string, 26 | Query string, 27 | Bookmark EVT_HANDLE, 28 | context win32.PVOID, 29 | Callback EVT_SUBSCRIBE_CALLBACK, 30 | Flags win32.DWORD) (EVT_HANDLE, error) { 31 | channelPath, err := syscall.UTF16PtrFromString(ChannelPath) 32 | if err != nil { 33 | return EVT_HANDLE(0), err 34 | } 35 | query, err := syscall.UTF16PtrFromString(Query) 36 | if err != nil { 37 | return EVT_HANDLE(0), err 38 | } 39 | r1, _, lastErr := evtSubscribe.Call( 40 | uintptr(Session), 41 | uintptr(SignalEvent), 42 | uintptr(unsafe.Pointer(channelPath)), 43 | uintptr(unsafe.Pointer(query)), 44 | uintptr(Bookmark), 45 | uintptr(context), 46 | syscall.NewCallback(Callback), 47 | uintptr(Flags)) 48 | if r1 == win32.NULL { 49 | return EVT_HANDLE(r1), lastErr 50 | } 51 | return EVT_HANDLE(r1), nil 52 | } 53 | 54 | func EvtPullSubscribe( 55 | Session EVT_HANDLE, 56 | SignalEvent win32.HANDLE, 57 | ChannelPath string, 58 | Query string, 59 | Bookmark EVT_HANDLE, 60 | context win32.PVOID, 61 | Flags win32.DWORD) (EVT_HANDLE, error) { 62 | channelPath, err := syscall.UTF16PtrFromString(ChannelPath) 63 | if err != nil { 64 | return EVT_HANDLE(0), err 65 | } 66 | query, err := syscall.UTF16PtrFromString(Query) 67 | if err != nil { 68 | return EVT_HANDLE(0), err 69 | } 70 | r1, _, lastErr := evtSubscribe.Call( 71 | uintptr(Session), 72 | uintptr(SignalEvent), 73 | uintptr(unsafe.Pointer(channelPath)), 74 | uintptr(unsafe.Pointer(query)), 75 | uintptr(Bookmark), 76 | uintptr(context), 77 | win32.NULL, 78 | uintptr(Flags)) 79 | if r1 == win32.NULL { 80 | return EVT_HANDLE(r1), lastErr 81 | } 82 | return EVT_HANDLE(r1), nil 83 | } 84 | 85 | func EvtNext(ResultSet EVT_HANDLE, Timeout win32.DWORD) ([]EVT_HANDLE, error) { 86 | /* 87 | BOOL WINAPI EvtNext( 88 | _In_ EVT_HANDLE ResultSet, 89 | _In_ DWORD EventArraySize, 90 | _In_ EVT_HANDLE* EventArray, 91 | _In_ DWORD Timeout, 92 | _In_ DWORD Flags, // Must be NULL 93 | _Out_ PDWORD Returned 94 | ); 95 | */ 96 | // ArraySize could not be too big 4096 (not more than 600 ???) 97 | // Weird handles at the end of array if we put higher than 64 98 | const EventArraySize = 10 99 | var EventArray [EventArraySize]EVT_HANDLE 100 | var Returned win32.DWORD 101 | 102 | // log.Debugf("ResultSet = 0x%08x", uintptr(ResultSet)) 103 | // log.Debugf("EventArraySize = %d", EventArraySize) 104 | // log.Debugf("Timeout = 0x%08x", Timeout) 105 | r1, _, lastErr := evtNext.Call( 106 | uintptr(ResultSet), 107 | uintptr(win32.DWORD(EventArraySize)), 108 | uintptr(unsafe.Pointer(&EventArray)), 109 | uintptr(Timeout), 110 | uintptr(0), 111 | uintptr(unsafe.Pointer(&Returned))) 112 | // log.Debugf("Returned = %d", Returned) 113 | // log.Debugf("EventArray = %v", EventArray) 114 | 115 | if win32.BOOL(r1) == win32.FALSE { 116 | return EventArray[:Returned], lastErr 117 | } 118 | return EventArray[:Returned], nil 119 | } 120 | 121 | func EvtRenderXML(Context EVT_HANDLE) ([]byte, error) { 122 | // 65536 buffsize 123 | const buffSize = 0x1 << 16 124 | var buffer [buffSize]byte 125 | var BufferUsed win32.DWORD 126 | var PropertyCount win32.DWORD 127 | 128 | r1, _, lastErr := evtRender.Call( 129 | uintptr(0), 130 | uintptr(Context), 131 | uintptr(EvtRenderEventXml), 132 | uintptr(buffSize), 133 | uintptr(unsafe.Pointer(&buffer[0])), 134 | uintptr(unsafe.Pointer(&BufferUsed)), 135 | uintptr(unsafe.Pointer(&PropertyCount))) 136 | // log.Debugf("BufferUsed = %d", BufferUsed) 137 | if win32.BOOL(r1) == win32.FALSE { 138 | return buffer[:], lastErr 139 | } 140 | return buffer[:BufferUsed], nil 141 | } 142 | -------------------------------------------------------------------------------- /win32/wevtapi/winevtapi_test.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package wevtapi 4 | 5 | import ( 6 | "encoding/json" 7 | "encoding/xml" 8 | "fmt" 9 | "os" 10 | "os/exec" 11 | "strings" 12 | "sync" 13 | "testing" 14 | "time" 15 | "unsafe" 16 | 17 | "github.com/0xrawsec/golang-utils/log" 18 | "github.com/0xrawsec/golang-win32/win32" 19 | "github.com/0xrawsec/golang-win32/win32/kernel32" 20 | ) 21 | 22 | const ( 23 | SysmonChannel = "Microsoft-Windows-Sysmon/Operational" 24 | SecurityChannel = "Security" 25 | XMLFile = "applocker.xml.2" 26 | nCalls = 1000 27 | ) 28 | 29 | func init() { 30 | //log.InitLogger(log.LDebug) 31 | } 32 | 33 | func callWhoami(count int) { 34 | for i := 0; i < count; i++ { 35 | exec.Command("whoami.exe").Start() 36 | } 37 | } 38 | 39 | type CallbackContext struct { 40 | t *testing.T 41 | Counter uint64 42 | xmlRenderedEvents chan string 43 | } 44 | 45 | func (c *CallbackContext) String() string { 46 | 47 | return fmt.Sprintf("Counter: %d", c.Counter) 48 | } 49 | 50 | func CallbackTest(Action EVT_SUBSCRIBE_NOTIFY_ACTION, UserContext win32.PVOID, Event EVT_HANDLE) uintptr { 51 | ctx := (*CallbackContext)(unsafe.Pointer(UserContext)) 52 | switch Action { 53 | case EvtSubscribeActionDeliver: 54 | data, err := EvtRenderXML(Event) 55 | if err != nil { 56 | ctx.t.Errorf("Error converting event to XML: %s", err) 57 | } 58 | dataUTF8 := win32.UTF16BytesToString(data) 59 | ctx.xmlRenderedEvents <- dataUTF8 60 | ctx.t.Log(dataUTF8) 61 | ctx.Counter++ 62 | case EvtSubscribeActionError: 63 | ctx.t.Errorf("Error") 64 | } 65 | return uintptr(0) 66 | } 67 | 68 | func TestPushSubscribe(t *testing.T) { 69 | ctx := &CallbackContext{t, 0, make(chan string)} 70 | sub, err := EvtSubscribe( 71 | EVT_HANDLE(win32.NULL), 72 | 73 | win32.HANDLE(win32.NULL), 74 | "Microsoft-Windows-Sysmon/Operational", 75 | "*", 76 | EVT_HANDLE(win32.NULL), 77 | win32.PVOID(unsafe.Pointer(ctx)), 78 | CallbackTest, 79 | EvtSubscribeToFutureEvents) 80 | if err != nil { 81 | t.Log(err) 82 | t.Fail() 83 | } 84 | 85 | go func() { 86 | for range ctx.xmlRenderedEvents { 87 | } 88 | }() 89 | 90 | time.Sleep(15 * time.Second) 91 | EvtClose(sub) 92 | t.Log(ctx) 93 | } 94 | 95 | func TestUnmarshalXML(t *testing.T) { 96 | f, err := os.Open(XMLFile) 97 | if err != nil { 98 | t.Log(err) 99 | t.FailNow() 100 | } 101 | dec := xml.NewDecoder(f) 102 | for { 103 | xe := XMLEvent{} 104 | 105 | if err := dec.Decode(&xe); err != nil { 106 | t.Log(err) 107 | break 108 | } 109 | //t.Logf("UserData: %v", xe.UserData) 110 | //t.Logf("EventData: %v", xe.EventData) 111 | 112 | b, err := json.Marshal(xe.ToMap()) 113 | if err != nil { 114 | t.Log(err) 115 | t.FailNow() 116 | } 117 | t.Log(string(b)) 118 | } 119 | } 120 | 121 | func TestPullSubscribe(t *testing.T) { 122 | event, err := kernel32.CreateEvent(0, win32.TRUE, win32.TRUE, "") 123 | if err != nil { 124 | t.Log(err) 125 | t.Fail() 126 | } 127 | /* hSubscription = EvtSubscribe(NULL, 128 | aWaitHandles[1], pwsPath, pwsQuery, NULL, NULL, NULL, EvtSubscribeStartAtOldestRecord); */ 129 | sub, err := EvtPullSubscribe( 130 | EVT_HANDLE(win32.NULL), 131 | event, 132 | "Microsoft-Windows-Sysmon/Operational", 133 | "*", 134 | EVT_HANDLE(win32.NULL), 135 | win32.PVOID(win32.NULL), 136 | EvtSubscribeToFutureEvents) 137 | 138 | if err != nil { 139 | t.Log(err) 140 | t.Fail() 141 | } 142 | rc := kernel32.WaitForSingleObject(event, win32.INFINITE) 143 | t.Log(fmt.Sprintf("0x%08x", rc)) 144 | log.Info("Got Signal") 145 | 146 | //for i := 0; i < 3; i++ { 147 | for { 148 | events, err := EvtNext(sub, win32.INFINITE) 149 | if err != nil { 150 | t.Log(err) 151 | t.Fail() 152 | } 153 | log.Infof("Got %d events", len(events)) 154 | for _, event := range events { 155 | data, err := EvtRenderXML(event) 156 | if err != nil { 157 | t.Log(err) 158 | } 159 | dataUTF8 := win32.UTF16BytesToString(data) 160 | log.Info(string(dataUTF8)) 161 | e := XMLEvent{} 162 | err = xml.Unmarshal([]byte(dataUTF8), &e) 163 | if err != nil { 164 | log.Error(err) 165 | } 166 | bytes, err := json.Marshal(&e) 167 | if err != nil { 168 | log.Error(err) 169 | } 170 | log.Info(string(bytes)) 171 | EvtClose(event) 172 | } 173 | } 174 | 175 | err = kernel32.ResetEvent(event) 176 | if err != nil { 177 | t.Log(err) 178 | t.Fail() 179 | } 180 | } 181 | func TestPullProviderPassive(t *testing.T) { 182 | countEvents := 0 183 | wg := sync.WaitGroup{} 184 | ep := NewPullEventProvider() 185 | d := 60 * time.Second 186 | 187 | wg.Add(1) 188 | go func() { 189 | for e := range ep.FetchEvents([]string{SysmonChannel, SecurityChannel}, 190 | EvtSubscribeToFutureEvents) { 191 | // Do conversion to json 192 | e.ToJSONEvent() 193 | countEvents++ 194 | } 195 | wg.Done() 196 | }() 197 | 198 | time.Sleep(d) 199 | ep.Stop() 200 | t.Logf("Received %.2f EPS", float64(countEvents)/d.Seconds()) 201 | } 202 | 203 | func TestPullProviderFetchEvents(t *testing.T) { 204 | //signal := make(chan bool) 205 | sysmonCounter := make(map[string]int) 206 | securityCounter := make(map[string]int) 207 | countEvents := 0 208 | wg := sync.WaitGroup{} 209 | 210 | ep := NewPullEventProvider() 211 | 212 | wg.Add(1) 213 | go func() { 214 | for e := range ep.FetchEvents([]string{SysmonChannel, SecurityChannel}, 215 | EvtSubscribeToFutureEvents) { 216 | j := e.ToJSONEvent() 217 | channel := j.Event.System.Channel 218 | switch channel { 219 | case SecurityChannel: 220 | if j.Event.System.EventID == "4688" { 221 | image := j.Event.EventData["NewProcessName"] 222 | securityCounter[image]++ 223 | } 224 | case SysmonChannel: 225 | if j.Event.System.EventID == "1" { 226 | image := j.Event.EventData["Image"] 227 | sysmonCounter[image]++ 228 | } 229 | } 230 | countEvents++ 231 | } 232 | wg.Done() 233 | }() 234 | 235 | log.Infof("Calling x%d whoami.exe", nCalls) 236 | callWhoami(nCalls) 237 | log.Infof("Sleeping") 238 | time.Sleep(5 * time.Second) 239 | // Stopping EventProvider 240 | ep.Stop() 241 | wg.Wait() 242 | 243 | for image, count := range sysmonCounter { 244 | if strings.HasSuffix(image, ".test.exe") { 245 | continue 246 | } 247 | secCount, ok := securityCounter[image] 248 | if ok { 249 | t.Logf("%s: %d", image, count) 250 | } else { 251 | t.Errorf("Image: %s Sysmon: %d Security: %d", image, count, secCount) 252 | } 253 | } 254 | t.Logf("Total Events Retrieved: %d", countEvents) 255 | } 256 | 257 | func TestPushProviderPassive(t *testing.T) { 258 | countEvents := 0 259 | wg := sync.WaitGroup{} 260 | ep := NewPushEventProvider() 261 | d := 60 * time.Second 262 | 263 | wg.Add(1) 264 | go func() { 265 | for e := range ep.FetchEvents([]string{SysmonChannel, SecurityChannel}, 266 | EvtSubscribeToFutureEvents) { 267 | // Do conversion to json 268 | e.ToJSONEvent() 269 | countEvents++ 270 | } 271 | wg.Done() 272 | }() 273 | 274 | time.Sleep(d) 275 | ep.Stop() 276 | t.Logf("Received %.2f EPS", float64(countEvents)/d.Seconds()) 277 | } 278 | 279 | func TestPushProviderFetchEvents(t *testing.T) { 280 | //signal := make(chan bool) 281 | sysmonCounter := make(map[string]int) 282 | securityCounter := make(map[string]int) 283 | countEvents := 0 284 | wg := sync.WaitGroup{} 285 | 286 | ep := NewPushEventProvider() 287 | if err := exec.Command("auditpol", "/set", `/subcategory:Process Creation`, "/success:enable", "/failure:enable").Run(); err != nil { 288 | t.Error("Failed to set audit policy") 289 | t.FailNow() 290 | } 291 | 292 | wg.Add(1) 293 | go func() { 294 | for e := range ep.FetchEvents([]string{SysmonChannel, SecurityChannel}, 295 | EvtSubscribeToFutureEvents) { 296 | j := e.ToJSONEvent() 297 | channel := j.Event.System.Channel 298 | switch channel { 299 | case SecurityChannel: 300 | if j.Event.System.EventID == "4688" { 301 | image := j.Event.EventData["NewProcessName"] 302 | securityCounter[image]++ 303 | } 304 | case SysmonChannel: 305 | if j.Event.System.EventID == "1" { 306 | image := j.Event.EventData["Image"] 307 | sysmonCounter[image]++ 308 | } 309 | } 310 | countEvents++ 311 | } 312 | wg.Done() 313 | }() 314 | 315 | log.Infof("Calling x%d whoami.exe", nCalls) 316 | callWhoami(nCalls) 317 | log.Infof("Sleeping") 318 | time.Sleep(5 * time.Second) 319 | // Stopping EventProvider 320 | log.Infof("Stopping event provider") 321 | ep.Stop() 322 | wg.Wait() 323 | 324 | for image, count := range sysmonCounter { 325 | if strings.HasSuffix(image, ".test.exe") { 326 | continue 327 | } 328 | secCount, ok := securityCounter[image] 329 | if ok { 330 | t.Logf("%s: %d", image, count) 331 | } else { 332 | t.Errorf("Image: %s Sysmon: %d Security: %d", image, count, secCount) 333 | } 334 | } 335 | t.Logf("Total Events Retrieved: %d", countEvents) 336 | } 337 | -------------------------------------------------------------------------------- /win32/win32_test.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package win32 4 | 5 | import ( 6 | "syscall" 7 | "testing" 8 | ) 9 | 10 | func TestUTF16PtrToString(t *testing.T) { 11 | ts := "This is just a test string" 12 | tsUtf16Ptr := syscall.StringToUTF16Ptr(ts) 13 | 14 | if UTF16PtrToString(tsUtf16Ptr) != ts { 15 | t.Fail() 16 | } 17 | t.Logf("UTF16 Ptr converted back: %s", UTF16PtrToString(tsUtf16Ptr)) 18 | 19 | } 20 | -------------------------------------------------------------------------------- /win32/winbase.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package win32 4 | 5 | var ( 6 | NULL = uintptr(0) 7 | FALSE = BOOL(0) 8 | TRUE = BOOL(1) 9 | ) 10 | 11 | type BOOL int 12 | type BOOLEAN BYTE 13 | type BYTE byte 14 | type CCHAR byte 15 | type CHAR byte 16 | type COLORREF DWORD 17 | type DWORDLONG uint64 18 | type DWORD uint32 19 | type DWORD32 uint32 20 | type DWORD64 uint64 21 | type HANDLE PVOID 22 | type HWND HANDLE 23 | type WORD uint16 24 | type SHORT int16 25 | type USHORT uint16 26 | type LONG int32 27 | type ULONG uint32 28 | type LONGLONG int64 29 | type ULONGLONG uint64 30 | type SIZE_T ULONG_PTR 31 | type ULONG_PTR uintptr 32 | type LONG_PTR int 33 | type PVOID uintptr 34 | type LPVOID uintptr 35 | type LPCVOID uintptr 36 | type LVOID uintptr 37 | type NTSTATUS LONG 38 | type KAFFINITY ULONG_PTR 39 | type KPRIORITY LONG 40 | type PPEB uintptr //not sure 41 | type UINT uint 42 | type WCHAR uint16 43 | type PWSTR *WCHAR 44 | type ACCESS_MASK ULONG 45 | 46 | // 47 | const ( 48 | INVALID_HANDLE = LONG_PTR(-1) 49 | ) 50 | 51 | const ( 52 | MAX_PATH = 260 53 | ) 54 | 55 | // winbase.h 56 | const ( 57 | DEBUG_PROCESS = 0x1 58 | DEBUG_ONLY_THIS_PROCESS = 0x2 59 | CREATE_SUSPENDED = 0x4 60 | DETACHED_PROCESS = 0x8 61 | CREATE_NEW_CONSOLE = 0x10 62 | NORMAL_PRIORITY_CLASS = 0x20 63 | IDLE_PRIORITY_CLASS = 0x40 64 | HIGH_PRIORITY_CLASS = 0x80 65 | REALTIME_PRIORITY_CLASS = 0x100 66 | CREATE_NEW_PROCESS_GROUP = 0x200 67 | CREATE_UNICODE_ENVIRONMENT = 0x400 68 | CREATE_SEPARATE_WOW_VDM = 0x800 69 | CREATE_SHARED_WOW_VDM = 0x1000 70 | CREATE_FORCEDOS = 0x2000 71 | BELOW_NORMAL_PRIORITY_CLASS = 0x4000 72 | ABOVE_NORMAL_PRIORITY_CLASS = 0x8000 73 | INHERIT_PARENT_AFFINITY = 0x10000 74 | INHERIT_CALLER_PRIORITY = 0x20000 75 | CREATE_PROTECTED_PROCESS = 0x40000 76 | EXTENDED_STARTUPINFO_PRESENT = 0x80000 77 | PROCESS_MODE_BACKGROUND_BEGIN = 0x100000 78 | PROCESS_MODE_BACKGROUND_END = 0x200000 79 | CREATE_BREAKAWAY_FROM_JOB = 0x1000000 80 | CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x2000000 81 | CREATE_DEFAULT_ERROR_MODE = 0x4000000 82 | CREATE_NO_WINDOW = 0x8000000 83 | PROFILE_USER = 0x10000000 84 | PROFILE_KERNEL = 0x20000000 85 | PROFILE_SERVER = 0x40000000 86 | CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000 87 | 88 | // Thread Priorities 89 | THREAD_PRIORITY_LOWEST = THREAD_BASE_PRIORITY_MIN 90 | THREAD_PRIORITY_BELOW_NORMAL = (THREAD_PRIORITY_LOWEST + 1) 91 | THREAD_PRIORITY_NORMAL = 0 92 | THREAD_PRIORITY_HIGHEST = THREAD_BASE_PRIORITY_MAX 93 | THREAD_PRIORITY_ABOVE_NORMAL = (THREAD_PRIORITY_HIGHEST - 1) 94 | THREAD_PRIORITY_ERROR_RETURN = (MAXLONG) 95 | THREAD_PRIORITY_TIME_CRITICAL = THREAD_BASE_PRIORITY_LOWRT 96 | THREAD_PRIORITY_IDLE = THREAD_BASE_PRIORITY_IDLE 97 | ) 98 | 99 | // Memory Allocation Types 100 | const ( 101 | MEM_COMMIT = 0x1000 102 | MEM_RESERVE = 0x2000 103 | MEM_DECOMMIT = 0x4000 104 | MEM_RELEASE = 0x8000 105 | MEM_FREE = 0x10000 106 | MEM_PRIVATE = 0x20000 107 | MEM_MAPPED = 0x40000 108 | MEM_RESET = 0x80000 109 | MEM_TOP_DOWN = 0x100000 110 | MEM_WRITE_WATCH = 0x200000 111 | MEM_PHYSICAL = 0x400000 112 | MEM_ROTATE = 0x800000 113 | MEM_LARGE_PAGES = 0x20000000 114 | MEM_4MB_PAGES = 0x80000000 115 | ) 116 | 117 | // Memory Protections 118 | const ( 119 | PAGE_NOACCESS = 0x01 120 | PAGE_READONLY = 0x02 121 | PAGE_READWRITE = 0x04 122 | PAGE_WRITECOPY = 0x08 123 | PAGE_EXECUTE = 0x10 124 | PAGE_EXECUTE_READ = 0x20 125 | PAGE_EXECUTE_READWRITE = 0x40 126 | PAGE_EXECUTE_WRITECOPY = 0x80 127 | PAGE_GUARD = 0x100 128 | PAGE_NOCACHE = 0x200 129 | PAGE_WRITECOMBINE = 0x400 130 | ) 131 | 132 | const ( 133 | IGNORE = 0 134 | INFINITE = 0xffffffff 135 | ) 136 | 137 | // Winerror.h 138 | const ( 139 | //ERROR_NO_MORE_ITEMS = 259 140 | //ERROR_INVALID_OPERATION = 4317 141 | 142 | WAIT_ABANDONED = 0x80 143 | WAIT_OBJECT_0 = 0x0 144 | WAIT_TIMEOUT = 0x102 145 | WAIT_FAILED = 0xFFFFFFFF 146 | MAXIMUM_WAIT_OBJECTS = 64 147 | ) 148 | 149 | // ntstatus.h 150 | const ( 151 | STATUS_SUCCESS = 0x0 152 | STATUS_PENDING = 0x00000103 153 | ) 154 | 155 | // minwinbase.h 156 | const ( 157 | STILL_ACTIVE = STATUS_PENDING 158 | ) 159 | 160 | const ( 161 | SERVICE_KERNEL_DRIVER = 0x00000001 162 | SERVICE_FILE_SYSTEM_DRIVER = 0x00000002 163 | SERVICE_ADAPTER = 0x00000004 164 | SERVICE_RECOGNIZER_DRIVER = 0x00000008 165 | 166 | SERVICE_DRIVER = (SERVICE_KERNEL_DRIVER | 167 | SERVICE_FILE_SYSTEM_DRIVER | 168 | SERVICE_RECOGNIZER_DRIVER) 169 | 170 | SERVICE_WIN32_OWN_PROCESS = 0x00000010 171 | SERVICE_WIN32_SHARE_PROCESS = 0x00000020 172 | SERVICE_WIN32 = (SERVICE_WIN32_OWN_PROCESS | 173 | SERVICE_WIN32_SHARE_PROCESS) 174 | 175 | SERVICE_INTERACTIVE_PROCESS = 0x00000100 176 | 177 | SERVICE_TYPE_ALL = (SERVICE_WIN32 | 178 | SERVICE_ADAPTER | 179 | SERVICE_DRIVER | 180 | SERVICE_INTERACTIVE_PROCESS) 181 | ) 182 | 183 | const ( 184 | DELETE = 0x00010000 185 | READ_CONTROL = 0x00020000 186 | WRITE_DAC = 0x00040000 187 | WRITE_OWNER = 0x00080000 188 | SYNCHRONIZE = 0x00100000 189 | STANDARD_RIGHTS_REQUIRED = 0x000F0000 190 | STANDARD_RIGHTS_READ = READ_CONTROL 191 | STANDARD_RIGHTS_WRITE = READ_CONTROL 192 | STANDARD_RIGHTS_EXECUTE = READ_CONTROL 193 | STANDARD_RIGHTS_ALL = 0x001F0000 194 | SPECIFIC_RIGHTS_ALL = 0x0000FFFF 195 | ACCESS_SYSTEM_SECURITY = 0x01000000 196 | MAXIMUM_ALLOWED = 0x02000000 197 | GENERIC_READ = 0x80000000 198 | GENERIC_WRITE = 0x40000000 199 | GENERIC_EXECUTE = 0x20000000 200 | GENERIC_ALL = 0x10000000 201 | ) 202 | 203 | const ( 204 | KEY_QUERY_VALUE = 0x0001 205 | KEY_SET_VALUE = 0x0002 206 | KEY_CREATE_SUB_KEY = 0x0004 207 | KEY_ENUMERATE_SUB_KEYS = 0x0008 208 | KEY_NOTIFY = 0x0010 209 | KEY_CREATE_LINK = 0x0020 210 | KEY_WOW64_64KEY = 0x0100 211 | KEY_WOW64_32KEY = 0x0200 212 | KEY_WOW64_RES = 0x0300 213 | KEY_READ = (STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY&(^SYNCHRONIZE)) 214 | KEY_WRITE = (STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY&(^SYNCHRONIZE)) 215 | KEY_EXECUTE = (KEY_READ & (^SYNCHRONIZE)) 216 | KEY_ALL_ACCESS = (STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK&(^SYNCHRONIZE)) 217 | ) 218 | 219 | // Winnt.h 220 | const ( 221 | // Thread base priorities 222 | THREAD_BASE_PRIORITY_LOWRT = 15 223 | THREAD_BASE_PRIORITY_MAX = 2 224 | THREAD_BASE_PRIORITY_MIN = -2 225 | THREAD_BASE_PRIORITY_IDLE = -15 226 | ) 227 | 228 | // ntdef.h 229 | const ( 230 | MAXLONG = 0x7fffffff 231 | ) 232 | -------------------------------------------------------------------------------- /win32/winbase32.go: -------------------------------------------------------------------------------- 1 | // +build windows,386 2 | 3 | package win32 4 | 5 | const ( 6 | SIZE_OF_80387_REGISTERS = 80 7 | MAXIMUM_SUPPORTED_EXTENSION = 512 8 | 9 | CONTEXT_i386 = 0x00010000 10 | CONTEXT_i486 = 0x00010000 11 | 12 | CONTEXT_CONTROL = (CONTEXT_i386 | 0x00000001) 13 | CONTEXT_INTEGER = (CONTEXT_i386 | 0x00000002) 14 | CONTEXT_SEGMENTS = (CONTEXT_i386 | 0x00000004) 15 | CONTEXT_FLOATING_POINT = (CONTEXT_i386 | 0x00000008) 16 | CONTEXT_DEBUG_REGISTERS = (CONTEXT_i386 | 0x00000010) 17 | CONTEXT_EXTENDED_REGISTERS = (CONTEXT_i386 | 0x00000020) 18 | 19 | CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) 20 | 21 | CONTEXT_ALL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS) 22 | ) 23 | 24 | type PCONTEXT *CONTEXT 25 | type LPCONTEXT PCONTEXT 26 | 27 | type MemoryBasicInformation struct { 28 | BaseAddress PVOID 29 | AllocationBase PVOID 30 | AllocationProtect DWORD 31 | RegionSize SIZE_T 32 | State DWORD 33 | Protect DWORD 34 | Type DWORD 35 | } 36 | 37 | type FLOATING_SAVE_AREA struct { 38 | ControlWord DWORD 39 | StatusWord DWORD 40 | TagWord DWORD 41 | ErrorOffset DWORD 42 | ErrorSelector DWORD 43 | DataOffset DWORD 44 | DataSelector DWORD 45 | RegisterArea [SIZE_OF_80387_REGISTERS]byte 46 | Cr0NpxState DWORD 47 | } 48 | 49 | type CONTEXT struct { 50 | ContextFlags DWORD 51 | Dr0 DWORD 52 | Dr1 DWORD 53 | Dr2 DWORD 54 | Dr3 DWORD 55 | Dr6 DWORD 56 | Dr7 DWORD 57 | FloatSave FLOATING_SAVE_AREA 58 | SegGs DWORD 59 | SegFs DWORD 60 | SegEs DWORD 61 | SegDs DWORD 62 | Edi DWORD 63 | Esi DWORD 64 | Ebx DWORD 65 | Edx DWORD 66 | Ecx DWORD 67 | Eax DWORD 68 | Ebp DWORD 69 | Eip DWORD 70 | SegCs DWORD 71 | EFlags DWORD 72 | Esp DWORD 73 | SegSs DWORD 74 | ExtendedRegisters [MAXIMUM_SUPPORTED_EXTENSION]byte 75 | } 76 | -------------------------------------------------------------------------------- /win32/winbase64.go: -------------------------------------------------------------------------------- 1 | // +build windows,amd64 2 | 3 | package win32 4 | 5 | import "fmt" 6 | 7 | const ( 8 | CONTEXT_AMD64 = 0x100000 9 | 10 | CONTEXT_CONTROL = (CONTEXT_AMD64 | 0x1) 11 | CONTEXT_INTEGER = (CONTEXT_AMD64 | 0x2) 12 | CONTEXT_SEGMENTS = (CONTEXT_AMD64 | 0x4) 13 | CONTEXT_FLOATING_POINT = (CONTEXT_AMD64 | 0x8) 14 | CONTEXT_DEBUG_REGISTERS = (CONTEXT_AMD64 | 0x10) 15 | 16 | CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) 17 | CONTEXT_ALL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS) 18 | 19 | CONTEXT_EXCEPTION_ACTIVE = 0x8000000 20 | CONTEXT_SERVICE_ACTIVE = 0x10000000 21 | CONTEXT_EXCEPTION_REQUEST = 0x40000000 22 | CONTEXT_EXCEPTION_REPORTING = 0x80000000 23 | ) 24 | 25 | type PCONTEXT *CONTEXT 26 | type LPCONTEXT PCONTEXT 27 | 28 | type MemoryBasicInformation struct { 29 | BaseAddress ULONGLONG 30 | AllocationBase ULONGLONG 31 | AllocationProtect DWORD 32 | Alignment1 DWORD 33 | RegionSize ULONGLONG 34 | State DWORD 35 | Protect DWORD 36 | Type DWORD 37 | Alignment2 DWORD 38 | } 39 | 40 | func (mbi MemoryBasicInformation) String() string { 41 | return fmt.Sprintf("BaseAddress: 0x%016x\n AllocationBase: 0x%016x\n AllocationProtect: 0x%08x\n Alignment1: 0x%08x\n RegionSize: %d\n State: 0x%08x\n Protect: 0x%08x\n Type: 0x%08x", 42 | mbi.BaseAddress, mbi.AllocationBase, mbi.AllocationProtect, mbi.Alignment1, mbi.RegionSize, mbi.State, mbi.Protect, mbi.Type) 43 | } 44 | 45 | type M128A struct { 46 | Low ULONGLONG 47 | High LONGLONG 48 | } 49 | 50 | type XMM_SAVE_AREA32 struct { 51 | ControlWord WORD 52 | StatusWord WORD 53 | TagWord BYTE 54 | Reserved1 BYTE 55 | ErrorOpcode WORD 56 | ErrorOffset DWORD 57 | ErrorSelector WORD 58 | Reserved2 WORD 59 | DataOffset DWORD 60 | DataSelector WORD 61 | Reserved3 WORD 62 | MxCsr DWORD 63 | MxCsr_Mask DWORD 64 | FloatRegisters [8]M128A 65 | XmmRegisters [16]M128A 66 | Reserved4 [96]BYTE 67 | } 68 | 69 | type CONTEXT struct { 70 | P1Home DWORD64 71 | P2Home DWORD64 72 | P3Home DWORD64 73 | P4Home DWORD64 74 | P5Home DWORD64 75 | P6Home DWORD64 76 | ContextFlags DWORD 77 | MxCsr DWORD 78 | SegCs WORD 79 | SegDs WORD 80 | SegEs WORD 81 | SegFs WORD 82 | SegGs WORD 83 | SegSs WORD 84 | EFlags DWORD 85 | Dr0 DWORD64 86 | Dr1 DWORD64 87 | Dr2 DWORD64 88 | Dr3 DWORD64 89 | Dr6 DWORD64 90 | Dr7 DWORD64 91 | Rax DWORD64 92 | Rcx DWORD64 93 | Rdx DWORD64 94 | Rbx DWORD64 95 | Rsp DWORD64 96 | Rbp DWORD64 97 | Rsi DWORD64 98 | Rdi DWORD64 99 | R8 DWORD64 100 | R9 DWORD64 101 | R10 DWORD64 102 | R11 DWORD64 103 | R12 DWORD64 104 | R13 DWORD64 105 | R14 DWORD64 106 | R15 DWORD64 107 | Rip DWORD64 108 | FloatSave XMM_SAVE_AREA32 // Is a union normaly I kept only the biggest struct in it since it is supposed to work 109 | VectorRegister [26]M128A 110 | VectorControl DWORD64 111 | DebugControl DWORD64 112 | LastBranchToRip DWORD64 113 | LastBranchFromRip DWORD64 114 | LastExceptionToRip DWORD64 115 | LastExceptionFromRip DWORD64 116 | } 117 | --------------------------------------------------------------------------------