github.com/nibnait/go-learn@v0.0.0-20220227013611-dfa47ea6d2da/src/pkg/mod/golang.org/x/sys@v0.0.0-20210630005230-0f9fa26af87c/windows/syscall_windows_test.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package windows_test 6 7 import ( 8 "bytes" 9 "debug/pe" 10 "errors" 11 "fmt" 12 "io/ioutil" 13 "math/rand" 14 "os" 15 "path/filepath" 16 "runtime" 17 "strconv" 18 "strings" 19 "syscall" 20 "testing" 21 "unsafe" 22 23 "golang.org/x/sys/windows" 24 ) 25 26 func TestWin32finddata(t *testing.T) { 27 dir, err := ioutil.TempDir("", "go-build") 28 if err != nil { 29 t.Fatalf("failed to create temp directory: %v", err) 30 } 31 defer os.RemoveAll(dir) 32 33 path := filepath.Join(dir, "long_name.and_extension") 34 f, err := os.Create(path) 35 if err != nil { 36 t.Fatalf("failed to create %v: %v", path, err) 37 } 38 f.Close() 39 40 type X struct { 41 fd windows.Win32finddata 42 got byte 43 pad [10]byte // to protect ourselves 44 45 } 46 var want byte = 2 // it is unlikely to have this character in the filename 47 x := X{got: want} 48 49 pathp, _ := windows.UTF16PtrFromString(path) 50 h, err := windows.FindFirstFile(pathp, &(x.fd)) 51 if err != nil { 52 t.Fatalf("FindFirstFile failed: %v", err) 53 } 54 err = windows.FindClose(h) 55 if err != nil { 56 t.Fatalf("FindClose failed: %v", err) 57 } 58 59 if x.got != want { 60 t.Fatalf("memory corruption: want=%d got=%d", want, x.got) 61 } 62 } 63 64 func TestFormatMessage(t *testing.T) { 65 dll := windows.MustLoadDLL("netevent.dll") 66 67 const TITLE_SC_MESSAGE_BOX uint32 = 0xC0001B75 68 const flags uint32 = syscall.FORMAT_MESSAGE_FROM_HMODULE | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS 69 buf := make([]uint16, 300) 70 _, err := windows.FormatMessage(flags, uintptr(dll.Handle), TITLE_SC_MESSAGE_BOX, 0, buf, nil) 71 if err != nil { 72 t.Fatalf("FormatMessage for handle=%x and errno=%x failed: %v", dll.Handle, TITLE_SC_MESSAGE_BOX, err) 73 } 74 } 75 76 func abort(funcname string, err error) { 77 panic(funcname + " failed: " + err.Error()) 78 } 79 80 func ExampleLoadLibrary() { 81 h, err := windows.LoadLibrary("kernel32.dll") 82 if err != nil { 83 abort("LoadLibrary", err) 84 } 85 defer windows.FreeLibrary(h) 86 proc, err := windows.GetProcAddress(h, "GetVersion") 87 if err != nil { 88 abort("GetProcAddress", err) 89 } 90 r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0) 91 major := byte(r) 92 minor := uint8(r >> 8) 93 build := uint16(r >> 16) 94 print("windows version ", major, ".", minor, " (Build ", build, ")\n") 95 } 96 97 func TestTOKEN_ALL_ACCESS(t *testing.T) { 98 if windows.TOKEN_ALL_ACCESS != 0xF01FF { 99 t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", windows.TOKEN_ALL_ACCESS) 100 } 101 } 102 103 func TestCreateWellKnownSid(t *testing.T) { 104 sid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid) 105 if err != nil { 106 t.Fatalf("Unable to create well known sid for administrators: %v", err) 107 } 108 if got, want := sid.String(), "S-1-5-32-544"; got != want { 109 t.Fatalf("Builtin Administrators SID = %s, want %s", got, want) 110 } 111 } 112 113 func TestPseudoTokens(t *testing.T) { 114 version, err := windows.GetVersion() 115 if err != nil { 116 t.Fatal(err) 117 } 118 if ((version&0xffff)>>8)|((version&0xff)<<8) < 0x0602 { 119 return 120 } 121 122 realProcessToken, err := windows.OpenCurrentProcessToken() 123 if err != nil { 124 t.Fatal(err) 125 } 126 defer realProcessToken.Close() 127 realProcessUser, err := realProcessToken.GetTokenUser() 128 if err != nil { 129 t.Fatal(err) 130 } 131 132 pseudoProcessToken := windows.GetCurrentProcessToken() 133 pseudoProcessUser, err := pseudoProcessToken.GetTokenUser() 134 if err != nil { 135 t.Fatal(err) 136 } 137 if !windows.EqualSid(realProcessUser.User.Sid, pseudoProcessUser.User.Sid) { 138 t.Fatal("The real process token does not have the same as the pseudo process token") 139 } 140 141 runtime.LockOSThread() 142 defer runtime.UnlockOSThread() 143 144 err = windows.RevertToSelf() 145 if err != nil { 146 t.Fatal(err) 147 } 148 149 pseudoThreadToken := windows.GetCurrentThreadToken() 150 _, err = pseudoThreadToken.GetTokenUser() 151 if err != windows.ERROR_NO_TOKEN { 152 t.Fatal("Expected an empty thread token") 153 } 154 pseudoThreadEffectiveToken := windows.GetCurrentThreadEffectiveToken() 155 pseudoThreadEffectiveUser, err := pseudoThreadEffectiveToken.GetTokenUser() 156 if err != nil { 157 t.Fatal(nil) 158 } 159 if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadEffectiveUser.User.Sid) { 160 t.Fatal("The real process token does not have the same as the pseudo thread effective token, even though we aren't impersonating") 161 } 162 163 err = windows.ImpersonateSelf(windows.SecurityImpersonation) 164 if err != nil { 165 t.Fatal(err) 166 } 167 defer windows.RevertToSelf() 168 pseudoThreadUser, err := pseudoThreadToken.GetTokenUser() 169 if err != nil { 170 t.Fatal(err) 171 } 172 if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadUser.User.Sid) { 173 t.Fatal("The real process token does not have the same as the pseudo thread token after impersonating self") 174 } 175 } 176 177 func TestGUID(t *testing.T) { 178 guid, err := windows.GenerateGUID() 179 if err != nil { 180 t.Fatal(err) 181 } 182 if guid.Data1 == 0 && guid.Data2 == 0 && guid.Data3 == 0 && guid.Data4 == [8]byte{} { 183 t.Fatal("Got an all zero GUID, which is overwhelmingly unlikely") 184 } 185 want := fmt.Sprintf("{%08X-%04X-%04X-%04X-%012X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[:2], guid.Data4[2:]) 186 got := guid.String() 187 if got != want { 188 t.Fatalf("String = %q; want %q", got, want) 189 } 190 guid2, err := windows.GUIDFromString(got) 191 if err != nil { 192 t.Fatal(err) 193 } 194 if guid2 != guid { 195 t.Fatalf("Did not parse string back to original GUID = %q; want %q", guid2, guid) 196 } 197 _, err = windows.GUIDFromString("not-a-real-guid") 198 if err != syscall.Errno(windows.CO_E_CLASSSTRING) { 199 t.Fatalf("Bad GUID string error = %v; want CO_E_CLASSSTRING", err) 200 } 201 } 202 203 func TestKnownFolderPath(t *testing.T) { 204 token, err := windows.OpenCurrentProcessToken() 205 if err != nil { 206 t.Fatal(err) 207 } 208 defer token.Close() 209 profileDir, err := token.GetUserProfileDirectory() 210 if err != nil { 211 t.Fatal(err) 212 } 213 want := filepath.Join(profileDir, "Desktop") 214 got, err := windows.KnownFolderPath(windows.FOLDERID_Desktop, windows.KF_FLAG_DEFAULT) 215 if err != nil { 216 t.Fatal(err) 217 } 218 if want != got { 219 t.Fatalf("Path = %q; want %q", got, want) 220 } 221 } 222 223 func TestRtlGetVersion(t *testing.T) { 224 version := windows.RtlGetVersion() 225 major, minor, build := windows.RtlGetNtVersionNumbers() 226 // Go is not explictly added to the application compatibility database, so 227 // these two functions should return the same thing. 228 if version.MajorVersion != major || version.MinorVersion != minor || version.BuildNumber != build { 229 t.Fatalf("%d.%d.%d != %d.%d.%d", version.MajorVersion, version.MinorVersion, version.BuildNumber, major, minor, build) 230 } 231 } 232 233 func TestGetNamedSecurityInfo(t *testing.T) { 234 path, err := windows.GetSystemDirectory() 235 if err != nil { 236 t.Fatal(err) 237 } 238 sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION) 239 if err != nil { 240 t.Fatal(err) 241 } 242 if !sd.IsValid() { 243 t.Fatal("Invalid security descriptor") 244 } 245 sdOwner, _, err := sd.Owner() 246 if err != nil { 247 t.Fatal(err) 248 } 249 if !sdOwner.IsValid() { 250 t.Fatal("Invalid security descriptor owner") 251 } 252 } 253 254 func TestGetSecurityInfo(t *testing.T) { 255 sd, err := windows.GetSecurityInfo(windows.CurrentProcess(), windows.SE_KERNEL_OBJECT, windows.DACL_SECURITY_INFORMATION) 256 if err != nil { 257 t.Fatal(err) 258 } 259 if !sd.IsValid() { 260 t.Fatal("Invalid security descriptor") 261 } 262 sdStr := sd.String() 263 if !strings.HasPrefix(sdStr, "D:(A;") { 264 t.Fatalf("DACL = %q; want D:(A;...", sdStr) 265 } 266 } 267 268 func TestSddlConversion(t *testing.T) { 269 sd, err := windows.SecurityDescriptorFromString("O:BA") 270 if err != nil { 271 t.Fatal(err) 272 } 273 if !sd.IsValid() { 274 t.Fatal("Invalid security descriptor") 275 } 276 sdOwner, _, err := sd.Owner() 277 if err != nil { 278 t.Fatal(err) 279 } 280 if !sdOwner.IsValid() { 281 t.Fatal("Invalid security descriptor owner") 282 } 283 if !sdOwner.IsWellKnown(windows.WinBuiltinAdministratorsSid) { 284 t.Fatalf("Owner = %q; want S-1-5-32-544", sdOwner) 285 } 286 } 287 288 func TestBuildSecurityDescriptor(t *testing.T) { 289 const want = "O:SYD:(A;;GA;;;BA)" 290 291 adminSid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid) 292 if err != nil { 293 t.Fatal(err) 294 } 295 systemSid, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid) 296 if err != nil { 297 t.Fatal(err) 298 } 299 300 access := []windows.EXPLICIT_ACCESS{{ 301 AccessPermissions: windows.GENERIC_ALL, 302 AccessMode: windows.GRANT_ACCESS, 303 Trustee: windows.TRUSTEE{ 304 TrusteeForm: windows.TRUSTEE_IS_SID, 305 TrusteeType: windows.TRUSTEE_IS_GROUP, 306 TrusteeValue: windows.TrusteeValueFromSID(adminSid), 307 }, 308 }} 309 owner := &windows.TRUSTEE{ 310 TrusteeForm: windows.TRUSTEE_IS_SID, 311 TrusteeType: windows.TRUSTEE_IS_USER, 312 TrusteeValue: windows.TrusteeValueFromSID(systemSid), 313 } 314 315 sd, err := windows.BuildSecurityDescriptor(owner, nil, access, nil, nil) 316 if err != nil { 317 t.Fatal(err) 318 } 319 sd, err = sd.ToAbsolute() 320 if err != nil { 321 t.Fatal(err) 322 } 323 err = sd.SetSACL(nil, false, false) 324 if err != nil { 325 t.Fatal(err) 326 } 327 if got := sd.String(); got != want { 328 t.Fatalf("SD = %q; want %q", got, want) 329 } 330 sd, err = sd.ToSelfRelative() 331 if err != nil { 332 t.Fatal(err) 333 } 334 if got := sd.String(); got != want { 335 t.Fatalf("SD = %q; want %q", got, want) 336 } 337 338 sd, err = windows.NewSecurityDescriptor() 339 if err != nil { 340 t.Fatal(err) 341 } 342 acl, err := windows.ACLFromEntries(access, nil) 343 if err != nil { 344 t.Fatal(err) 345 } 346 err = sd.SetDACL(acl, true, false) 347 if err != nil { 348 t.Fatal(err) 349 } 350 err = sd.SetOwner(systemSid, false) 351 if err != nil { 352 t.Fatal(err) 353 } 354 if got := sd.String(); got != want { 355 t.Fatalf("SD = %q; want %q", got, want) 356 } 357 sd, err = sd.ToSelfRelative() 358 if err != nil { 359 t.Fatal(err) 360 } 361 if got := sd.String(); got != want { 362 t.Fatalf("SD = %q; want %q", got, want) 363 } 364 } 365 366 func TestGetDiskFreeSpaceEx(t *testing.T) { 367 cwd, err := windows.UTF16PtrFromString(".") 368 if err != nil { 369 t.Fatalf(`failed to call UTF16PtrFromString("."): %v`, err) 370 } 371 var freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes uint64 372 if err := windows.GetDiskFreeSpaceEx(cwd, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes); err != nil { 373 t.Fatalf("failed to call GetDiskFreeSpaceEx: %v", err) 374 } 375 376 if freeBytesAvailableToCaller == 0 { 377 t.Errorf("freeBytesAvailableToCaller: got 0; want > 0") 378 } 379 if totalNumberOfBytes == 0 { 380 t.Errorf("totalNumberOfBytes: got 0; want > 0") 381 } 382 if totalNumberOfFreeBytes == 0 { 383 t.Errorf("totalNumberOfFreeBytes: got 0; want > 0") 384 } 385 } 386 387 func TestGetPreferredUILanguages(t *testing.T) { 388 tab := map[string]func(flags uint32) ([]string, error){ 389 "GetProcessPreferredUILanguages": windows.GetProcessPreferredUILanguages, 390 "GetThreadPreferredUILanguages": windows.GetThreadPreferredUILanguages, 391 "GetUserPreferredUILanguages": windows.GetUserPreferredUILanguages, 392 "GetSystemPreferredUILanguages": windows.GetSystemPreferredUILanguages, 393 } 394 for fName, f := range tab { 395 lang, err := f(windows.MUI_LANGUAGE_ID) 396 if err != nil { 397 t.Errorf(`failed to call %v(MUI_LANGUAGE_ID): %v`, fName, err) 398 } 399 for _, l := range lang { 400 _, err := strconv.ParseUint(l, 16, 16) 401 if err != nil { 402 t.Errorf(`%v(MUI_LANGUAGE_ID) returned unexpected LANGID: %v`, fName, l) 403 } 404 } 405 406 lang, err = f(windows.MUI_LANGUAGE_NAME) 407 if err != nil { 408 t.Errorf(`failed to call %v(MUI_LANGUAGE_NAME): %v`, fName, err) 409 } 410 } 411 } 412 413 func TestProcessWorkingSetSizeEx(t *testing.T) { 414 // Grab a handle to the current process 415 hProcess := windows.CurrentProcess() 416 417 // Allocate memory to store the result of the query 418 var minimumWorkingSetSize, maximumWorkingSetSize uintptr 419 420 // Make the system-call 421 var flag uint32 422 windows.GetProcessWorkingSetSizeEx(hProcess, &minimumWorkingSetSize, &maximumWorkingSetSize, &flag) 423 424 // Set the new limits to the current ones 425 if err := windows.SetProcessWorkingSetSizeEx(hProcess, minimumWorkingSetSize, maximumWorkingSetSize, flag); err != nil { 426 t.Error(err) 427 } 428 } 429 430 func TestJobObjectInfo(t *testing.T) { 431 jo, err := windows.CreateJobObject(nil, nil) 432 if err != nil { 433 t.Fatalf("CreateJobObject failed: %v", err) 434 } 435 defer windows.CloseHandle(jo) 436 437 var info windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION 438 439 err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation, 440 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil) 441 if err != nil { 442 t.Fatalf("QueryInformationJobObject failed: %v", err) 443 } 444 445 const wantMemLimit = 4 * 1024 446 447 info.BasicLimitInformation.LimitFlags |= windows.JOB_OBJECT_LIMIT_PROCESS_MEMORY 448 info.ProcessMemoryLimit = wantMemLimit 449 _, err = windows.SetInformationJobObject(jo, windows.JobObjectExtendedLimitInformation, 450 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info))) 451 if err != nil { 452 t.Fatalf("SetInformationJobObject failed: %v", err) 453 } 454 455 err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation, 456 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil) 457 if err != nil { 458 t.Fatalf("QueryInformationJobObject failed: %v", err) 459 } 460 461 if have := info.ProcessMemoryLimit; wantMemLimit != have { 462 t.Errorf("ProcessMemoryLimit is wrong: want %v have %v", wantMemLimit, have) 463 } 464 } 465 466 func TestIsWow64Process2(t *testing.T) { 467 var processMachine, nativeMachine uint16 468 err := windows.IsWow64Process2(windows.CurrentProcess(), &processMachine, &nativeMachine) 469 if errors.Is(err, windows.ERROR_PROC_NOT_FOUND) { 470 maj, min, build := windows.RtlGetNtVersionNumbers() 471 if maj < 10 || (maj == 10 && min == 0 && build < 17763) { 472 t.Skip("not available on older versions of Windows") 473 return 474 } 475 } 476 if err != nil { 477 t.Fatalf("IsWow64Process2 failed: %v", err) 478 } 479 if processMachine == pe.IMAGE_FILE_MACHINE_UNKNOWN { 480 processMachine = nativeMachine 481 } 482 switch { 483 case processMachine == pe.IMAGE_FILE_MACHINE_AMD64 && runtime.GOARCH == "amd64": 484 case processMachine == pe.IMAGE_FILE_MACHINE_I386 && runtime.GOARCH == "386": 485 case processMachine == pe.IMAGE_FILE_MACHINE_ARMNT && runtime.GOARCH == "arm": 486 case processMachine == pe.IMAGE_FILE_MACHINE_ARM64 && runtime.GOARCH == "arm64": 487 default: 488 t.Errorf("IsWow64Process2 is wrong: want %v have %v", runtime.GOARCH, processMachine) 489 } 490 } 491 492 func TestNTStatusString(t *testing.T) { 493 want := "The name limit for the local computer network adapter card was exceeded." 494 got := windows.STATUS_TOO_MANY_NAMES.Error() 495 if want != got { 496 t.Errorf("NTStatus.Error did not return an expected error string - want %q; got %q", want, got) 497 } 498 } 499 500 func TestNTStatusConversion(t *testing.T) { 501 want := windows.ERROR_TOO_MANY_NAMES 502 got := windows.STATUS_TOO_MANY_NAMES.Errno() 503 if want != got { 504 t.Errorf("NTStatus.Errno = %q (0x%x); want %q (0x%x)", got.Error(), got, want.Error(), want) 505 } 506 } 507 508 func TestPEBFilePath(t *testing.T) { 509 peb := windows.RtlGetCurrentPeb() 510 if peb == nil || peb.Ldr == nil { 511 t.Error("unable to retrieve PEB with valid Ldr") 512 } 513 var entry *windows.LDR_DATA_TABLE_ENTRY 514 for cur := peb.Ldr.InMemoryOrderModuleList.Flink; cur != &peb.Ldr.InMemoryOrderModuleList; cur = cur.Flink { 515 e := (*windows.LDR_DATA_TABLE_ENTRY)(unsafe.Pointer(uintptr(unsafe.Pointer(cur)) - unsafe.Offsetof(windows.LDR_DATA_TABLE_ENTRY{}.InMemoryOrderLinks))) 516 if e.DllBase == peb.ImageBaseAddress { 517 entry = e 518 break 519 } 520 } 521 if entry == nil { 522 t.Error("unable to find Ldr entry for current process") 523 } 524 osPath, err := os.Executable() 525 if err != nil { 526 t.Errorf("unable to get path to current executable: %v", err) 527 } 528 pebPath := entry.FullDllName.String() 529 if osPath != pebPath { 530 t.Errorf("peb.Ldr.{entry}.FullDllName = %#q; want %#q", pebPath, osPath) 531 } 532 paramPath := peb.ProcessParameters.ImagePathName.String() 533 if osPath != paramPath { 534 t.Errorf("peb.ProcessParameters.ImagePathName.{entry}.ImagePathName = %#q; want %#q", paramPath, osPath) 535 } 536 osCwd, err := os.Getwd() 537 if err != nil { 538 t.Errorf("unable to get working directory: %v", err) 539 } 540 osCwd = filepath.Clean(osCwd) 541 paramCwd := filepath.Clean(peb.ProcessParameters.CurrentDirectory.DosPath.String()) 542 if paramCwd != osCwd { 543 t.Errorf("peb.ProcessParameters.CurrentDirectory.DosPath = %#q; want %#q", paramCwd, osCwd) 544 } 545 } 546 547 func TestResourceExtraction(t *testing.T) { 548 system32, err := windows.GetSystemDirectory() 549 if err != nil { 550 t.Errorf("unable to find system32 directory: %v", err) 551 } 552 cmd, err := windows.LoadLibrary(filepath.Join(system32, "cmd.exe")) 553 if err != nil { 554 t.Errorf("unable to load cmd.exe: %v", err) 555 } 556 defer windows.FreeLibrary(cmd) 557 rsrc, err := windows.FindResource(cmd, windows.CREATEPROCESS_MANIFEST_RESOURCE_ID, windows.RT_MANIFEST) 558 if err != nil { 559 t.Errorf("unable to find cmd.exe manifest resource: %v", err) 560 } 561 manifest, err := windows.LoadResourceData(cmd, rsrc) 562 if err != nil { 563 t.Errorf("unable to load cmd.exe manifest resource data: %v", err) 564 } 565 if !bytes.Contains(manifest, []byte("</assembly>")) { 566 t.Errorf("did not find </assembly> in manifest") 567 } 568 } 569 570 func TestCommandLineRecomposition(t *testing.T) { 571 const ( 572 maxCharsPerArg = 35 573 maxArgsPerTrial = 80 574 doubleQuoteProb = 4 575 singleQuoteProb = 1 576 backSlashProb = 3 577 spaceProb = 1 578 trials = 1000 579 ) 580 randString := func(l int) []rune { 581 s := make([]rune, l) 582 for i := range s { 583 s[i] = rand.Int31() 584 } 585 return s 586 } 587 mungeString := func(s []rune, char rune, timesInTen int) { 588 if timesInTen < rand.Intn(10)+1 || len(s) == 0 { 589 return 590 } 591 s[rand.Intn(len(s))] = char 592 } 593 argStorage := make([]string, maxArgsPerTrial+1) 594 for i := 0; i < trials; i++ { 595 args := argStorage[:rand.Intn(maxArgsPerTrial)+2] 596 args[0] = "valid-filename-for-arg0" 597 for j := 1; j < len(args); j++ { 598 arg := randString(rand.Intn(maxCharsPerArg + 1)) 599 mungeString(arg, '"', doubleQuoteProb) 600 mungeString(arg, '\'', singleQuoteProb) 601 mungeString(arg, '\\', backSlashProb) 602 mungeString(arg, ' ', spaceProb) 603 args[j] = string(arg) 604 } 605 commandLine := windows.ComposeCommandLine(args) 606 decomposedArgs, err := windows.DecomposeCommandLine(commandLine) 607 if err != nil { 608 t.Errorf("Unable to decompose %#q made from %v: %v", commandLine, args, err) 609 continue 610 } 611 if len(decomposedArgs) != len(args) { 612 t.Errorf("Incorrect decomposition length from %v to %#q to %v", args, commandLine, decomposedArgs) 613 continue 614 } 615 badMatches := make([]int, 0, len(args)) 616 for i := range args { 617 if args[i] != decomposedArgs[i] { 618 badMatches = append(badMatches, i) 619 } 620 } 621 if len(badMatches) != 0 { 622 t.Errorf("Incorrect decomposition at indices %v from %v to %#q to %v", badMatches, args, commandLine, decomposedArgs) 623 continue 624 } 625 } 626 } 627 628 func TestWinVerifyTrust(t *testing.T) { 629 system32, err := windows.GetSystemDirectory() 630 if err != nil { 631 t.Errorf("unable to find system32 directory: %v", err) 632 } 633 ntoskrnl := filepath.Join(system32, "ntoskrnl.exe") 634 ntoskrnl16, err := windows.UTF16PtrFromString(ntoskrnl) 635 if err != nil { 636 t.Fatalf("unable to get utf16 of ntoskrnl.exe: %v", err) 637 } 638 data := &windows.WinTrustData{ 639 Size: uint32(unsafe.Sizeof(windows.WinTrustData{})), 640 UIChoice: windows.WTD_UI_NONE, 641 RevocationChecks: windows.WTD_REVOKE_NONE, // No revocation checking, in case the tests don't have network connectivity. 642 UnionChoice: windows.WTD_CHOICE_FILE, 643 StateAction: windows.WTD_STATEACTION_VERIFY, 644 FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{ 645 Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})), 646 FilePath: ntoskrnl16, 647 }), 648 } 649 verifyErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) 650 data.StateAction = windows.WTD_STATEACTION_CLOSE 651 closeErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) 652 if verifyErr != nil { 653 t.Errorf("ntoskrnl.exe did not verify: %v", verifyErr) 654 } 655 if closeErr != nil { 656 t.Errorf("unable to free verification resources: %v", closeErr) 657 } 658 659 // Now that we've verified legitimate ntoskrnl.exe verifies, let's corrupt it and see if it correctly fails. 660 661 dir, err := ioutil.TempDir("", "go-build") 662 if err != nil { 663 t.Fatalf("failed to create temp directory: %v", err) 664 } 665 defer os.RemoveAll(dir) 666 corruptedNtoskrnl := filepath.Join(dir, "ntoskrnl.exe") 667 ntoskrnlBytes, err := ioutil.ReadFile(ntoskrnl) 668 if err != nil { 669 t.Fatalf("unable to read ntoskrnl.exe bytes: %v", err) 670 } 671 if len(ntoskrnlBytes) > 0 { 672 ntoskrnlBytes[len(ntoskrnlBytes)/2-1]++ 673 } 674 err = ioutil.WriteFile(corruptedNtoskrnl, ntoskrnlBytes, 0755) 675 if err != nil { 676 t.Fatalf("unable to write corrupted ntoskrnl.exe bytes: %v", err) 677 } 678 ntoskrnl16, err = windows.UTF16PtrFromString(corruptedNtoskrnl) 679 if err != nil { 680 t.Fatalf("unable to get utf16 of ntoskrnl.exe: %v", err) 681 } 682 data = &windows.WinTrustData{ 683 Size: uint32(unsafe.Sizeof(windows.WinTrustData{})), 684 UIChoice: windows.WTD_UI_NONE, 685 RevocationChecks: windows.WTD_REVOKE_NONE, // No revocation checking, in case the tests don't have network connectivity. 686 UnionChoice: windows.WTD_CHOICE_FILE, 687 StateAction: windows.WTD_STATEACTION_VERIFY, 688 FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{ 689 Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})), 690 FilePath: ntoskrnl16, 691 }), 692 } 693 verifyErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) 694 data.StateAction = windows.WTD_STATEACTION_CLOSE 695 closeErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) 696 if verifyErr != windows.Errno(windows.TRUST_E_BAD_DIGEST) { 697 t.Errorf("ntoskrnl.exe did not fail to verify as expected: %v", verifyErr) 698 } 699 if closeErr != nil { 700 t.Errorf("unable to free verification resources: %v", closeErr) 701 } 702 703 }