github.com/iDigitalFlame/xmt@v0.5.4/device/winapi/calls.go (about) 1 //go:build windows 2 // +build windows 3 4 // Copyright (C) 2020 - 2023 iDigitalFlame 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 // 19 20 package winapi 21 22 import ( 23 "syscall" 24 "unsafe" 25 26 "github.com/iDigitalFlame/xmt/util/bugtrack" 27 ) 28 29 // RevertToSelf Windows API Call 30 // 31 // The RevertToSelf function terminates the impersonation of a client application. 32 // 33 // https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-revqerttoself 34 // 35 // Alias of 'SetAllThreadsToken(0)' 36 // 37 // NOTE(dij): This only clears the token on all the Golang Threads. Same as 38 // 39 // 'device.RevertToSelf'. 40 func RevertToSelf() error { 41 return SetAllThreadsToken(0) 42 } 43 44 // BlockInput Windows API Call 45 // 46 // Blocks keyboard and mouse input events from reaching applications. 47 // 48 // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-blockinput 49 func BlockInput(e bool) error { 50 var v uint32 51 if e { 52 v = 1 53 } 54 r, _, err := syscallN(funcBlockInput.address(), uintptr(v)) 55 if r == 0 { 56 return unboxError(err) 57 } 58 return nil 59 } 60 61 // SetEvent Windows API Call 62 // 63 // Sets the specified event object to the signaled state. 64 // 65 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setevent 66 // 67 // Re-targeted to use 'NtSetEvent' instead. 68 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwsetevent 69 func SetEvent(h uintptr) error { 70 if r, _, _ := syscallN(funcNtSetEvent.address(), h, 0); r > 0 { 71 return formatNtError(r) 72 } 73 return nil 74 } 75 76 // CloseHandle Windows API Call 77 // 78 // Closes an open object handle. 79 // 80 // https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle 81 // 82 // Re-targeted to use 'NtClose' instead. 83 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntclose 84 func CloseHandle(h uintptr) error { 85 // NOTE(dij): Uncomment to track empty handles 86 // if h == 0 { 87 // panic("invalid") 88 // } 89 r, _, _ := syscallN(funcNtClose.address(), h) 90 if bugtrack.Enabled { // Trace Bad Handles 91 bugtrack.Track("winapi.CloseHandle() h=0x%X, r=0x%X", h, r) 92 } 93 if r > 0 { 94 return formatNtError(r) 95 } 96 return nil 97 } 98 99 // GetCurrentProcessID Windows API Call 100 // 101 // Retrieves the process identifier of the calling process. 102 // 103 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessid 104 func GetCurrentProcessID() uint32 { 105 r, _, _ := syscallN(funcGetCurrentProcessID.address()) 106 return uint32(r) 107 } 108 109 // RegFlushKey Windows API Call 110 // 111 // Writes all the attributes of the specified open registry key into the registry. 112 // 113 // https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regflushkey 114 func RegFlushKey(h uintptr) error { 115 r, _, err := syscallN(funcRegFlushKey.address(), h) 116 if r > 0 { 117 return unboxError(err) 118 } 119 return nil 120 } 121 122 // NtResumeProcess Windows API Call 123 // 124 // Resumes a process and all it's threads. 125 // 126 // http://www.pinvoke.net/default.aspx/ntdll/NtResumeProcess.html 127 func NtResumeProcess(h uintptr) error { 128 if r, _, _ := syscallN(funcNtResumeProcess.address(), h); r > 0 { 129 return formatNtError(r) 130 } 131 return nil 132 } 133 134 // NtSuspendProcess Windows API Call 135 // 136 // Suspends a process and all it's threads. 137 // 138 // http://www.pinvoke.net/default.aspx/ntdll/NtSuspendProcess.html 139 func NtSuspendProcess(h uintptr) error { 140 if r, _, _ := syscallN(funcNtSuspendProcess.address(), h); r > 0 { 141 return formatNtError(r) 142 } 143 return nil 144 } 145 146 // GetLogicalDrives Windows API Call 147 // 148 // Retrieves a bitmask representing the currently available disk drives. 149 // 150 // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives 151 func GetLogicalDrives() (uint32, error) { 152 // NOTE(dij): This is a super UNDOCUMENTED call to NtQueryInformationProcess 153 // that somehow returns a bitmask of the current drives connected? 154 // It's something to do with IRQ information? 155 // Also the input blob size is 34b on x64 and 56b on x86? The 56b 156 // works on both as long as we report 36b for both. 157 var ( 158 n uint32 159 b [14]uint32 160 r, _, _ = syscallN(funcNtQueryInformationProcess.address(), CurrentProcess, 0x17, uintptr(unsafe.Pointer(&b[0])), 0x24, uintptr(unsafe.Pointer(&n))) 161 ) 162 if r > 0 { 163 return 0, formatNtError(r) 164 } 165 return b[0], nil 166 } 167 168 // DisconnectNamedPipe Windows API Call 169 // 170 // Disconnects the server end of a named pipe instance from a client process. 171 // 172 // https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-disconnectnamedpipe 173 func DisconnectNamedPipe(h uintptr) error { 174 r, _, err := syscallN(funcDisconnectNamedPipe.address(), h) 175 if r == 0 { 176 return unboxError(err) 177 } 178 return nil 179 } 180 181 // ResumeThread Windows API Call 182 // 183 // Decrements a thread's suspend count. When the suspend count is decremented 184 // to zero, the execution of the thread is resumed. 185 // 186 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-resumethread 187 // 188 // Re-targeted to use 'NtResumeThread' instead. 189 // https://docs.rs/ntapi/0.3.1/ntapi/ntpsapi/type.NtResumeThread.html 190 func ResumeThread(h uintptr) (uint32, error) { 191 var c uint32 192 if r, _, _ := syscallN(funcNtResumeThread.address(), h, uintptr(unsafe.Pointer(&c))); r > 0 { 193 return 0, formatNtError(r) 194 } 195 return c, nil 196 } 197 198 // GetProcessID Windows API Call 199 // 200 // Retrieves the process identifier of the specified process. 201 // 202 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocessid 203 // 204 // Calls 'NtQueryInformationProcess' instead under the hood. 205 func GetProcessID(h uintptr) (uint32, error) { 206 var ( 207 p processBasicInfo 208 r, _, _ = syscallN(funcNtQueryInformationProcess.address(), h, 0, uintptr(unsafe.Pointer(&p)), unsafe.Sizeof(p), 0) 209 ) 210 if r > 0 { 211 return 0, formatNtError(r) 212 } 213 return uint32(p.UniqueProcessID), nil 214 } 215 216 // SuspendThread Windows API Call 217 // 218 // Suspends the specified thread. 219 // 220 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread 221 // 222 // Re-targeted to use 'NtSuspendThread' instead. 223 // https://docs.rs/ntapi/0.3.1/ntapi/ntpsapi/type.NtSuspendThread.html 224 func SuspendThread(h uintptr) (uint32, error) { 225 var c uint32 226 if r, _, _ := syscallN(funcNtSuspendThread.address(), h, uintptr(unsafe.Pointer(&c))); r > 0 { 227 return 0, formatNtError(r) 228 } 229 return c, nil 230 } 231 232 // TerminateThread Windows API Call 233 // 234 // Terminates a thread. 235 // 236 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminatethread 237 // 238 // Re-targeted to use 'NtTerminateThread' instead. 239 // http://pinvoke.net/default.aspx/ntdll/NtTerminateThread.html 240 func TerminateThread(h uintptr, e uint32) error { 241 if h == 0 { 242 // Helper to prevent deadlocks. 243 return nil 244 } 245 if r, _, _ := syscallN(funcNtTerminateThread.address(), h, uintptr(e)); r > 0 { 246 return formatNtError(r) 247 } 248 return nil 249 } 250 251 // RegDeleteKey Windows API Call 252 // 253 // Deletes a subkey and its values. Note that key names are not case sensitive. 254 // ONLY DELETES EMPTY SUBKEYS. (invalid argument if non-empty) 255 // 256 // https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regdeletekeyw 257 func RegDeleteKey(h uintptr, path string) error { 258 return RegDeleteKeyEx(h, path, 0) 259 } 260 261 // SetProcessIsCritical Windows API Call 262 // 263 // Set process system critical status. 264 // Returns the last Critical status. 265 // 266 // https://www.codeproject.com/articles/43405/protecting-your-process-with-rtlsetprocessiscriti 267 func SetProcessIsCritical(c bool) (bool, error) { 268 var s, o byte 269 if c { 270 s = 1 271 } 272 r, _, err := syscallN(funcRtlSetProcessIsCritical.address(), uintptr(s), uintptr(unsafe.Pointer(&o)), 0) 273 if r > 0 { 274 return false, unboxError(err) 275 } 276 return o == 1, nil 277 } 278 279 // SetThreadToken Windows API Call 280 // 281 // The SetThreadToken function assigns an impersonation token to a thread. The 282 // function can also cause a thread to stop using an impersonation token. 283 // 284 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadtoken 285 // 286 // Calls 'NtSetInformationThread' under the hood. 287 func SetThreadToken(h uintptr, t uintptr) error { 288 // 0x5 - ThreadImpersonationToken 289 if r, _, _ := syscallN(funcNtSetInformationThread.address(), h, 0x5, uintptr(unsafe.Pointer(&t)), ptrSize); r > 0 { 290 return formatNtError(r) 291 } 292 return nil 293 } 294 295 // TerminateProcess Windows API Call 296 // 297 // Terminates the specified process and all of its threads. 298 // 299 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess 300 // 301 // Re-targeted to use 'NtTerminateProcess' instead. 302 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-zwterminateprocess 303 func TerminateProcess(h uintptr, e uint32) error { 304 if h == 0 { 305 // Helper to prevent deadlocks. 306 return nil 307 } 308 if r, _, _ := syscallN(funcNtTerminateProcess.address(), h, uintptr(e)); r > 0 { 309 return formatNtError(r) 310 } 311 return nil 312 } 313 314 // ImpersonateNamedPipeClient Windows API Call 315 // 316 // The ImpersonateNamedPipeClient function impersonates a named-pipe client 317 // application. 318 // 319 // https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient 320 func ImpersonateNamedPipeClient(h uintptr) error { 321 r, _, err := syscallN(funcImpersonateNamedPipeClient.address(), h) 322 if r == 0 { 323 return unboxError(err) 324 } 325 return nil 326 } 327 328 // RegDeleteValue Windows API Call 329 // 330 // Removes a named value from the specified registry key. Note that value names 331 // are not case sensitive. 332 // 333 // https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regdeletevaluew 334 func RegDeleteValue(h uintptr, path string) error { 335 p, err := UTF16PtrFromString(path) 336 if err != nil { 337 return err 338 } 339 r, _, err1 := syscallN(funcRegDeleteValue.address(), h, uintptr(unsafe.Pointer(p))) 340 if r > 0 { 341 return unboxError(err1) 342 } 343 return nil 344 } 345 346 // GetExitCodeThread Windows API Call 347 // 348 // Retrieves the termination status of the specified thread. 349 // 350 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodethread 351 // 352 // Calls 'NtQueryInformationThread' under the hood. 353 func GetExitCodeThread(h uintptr, e *uint32) error { 354 var ( 355 t threadBasicInfo 356 r, _, _ = syscallN(funcNtQueryInformationThread.address(), h, 0, uintptr(unsafe.Pointer(&t)), unsafe.Sizeof(t), 0) 357 ) 358 if r > 0 { 359 return formatNtError(r) 360 } 361 *e = t.ExitStatus 362 return nil 363 } 364 365 // GetExitCodeProcess Windows API Call 366 // 367 // Retrieves the termination status of the specified process. 368 // 369 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess 370 // 371 // Calls 'NtQueryInformationProcess' under the hood. 372 func GetExitCodeProcess(h uintptr, e *uint32) error { 373 var ( 374 p processBasicInfo 375 r, _, _ = syscallN(funcNtQueryInformationProcess.address(), h, 0, uintptr(unsafe.Pointer(&p)), unsafe.Sizeof(p), 0) 376 ) 377 if r > 0 { 378 return formatNtError(r) 379 } 380 *e = p.ExitStatus 381 return nil 382 } 383 384 // WaitNamedPipe Windows API Call 385 // 386 // Waits until either a time-out interval elapses or an instance of the 387 // specified named pipe is available for connection (that is, the pipe's server 388 // process has a pending ConnectNamedPipe operation on the pipe). 389 // 390 // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-waitnamedpipea 391 func WaitNamedPipe(name string, timeout uint32) error { 392 n, err := UTF16PtrFromString(name) 393 if err != nil { 394 return err 395 } 396 r, _, err1 := syscallN(funcWaitNamedPipe.address(), uintptr(unsafe.Pointer(n)), uintptr(timeout)) 397 if r == 0 { 398 return unboxError(err1) 399 } 400 return nil 401 } 402 403 // ConnectNamedPipe Windows API Call 404 // 405 // Enables a named pipe server process to wait for a client process to connect 406 // to an instance of a named pipe. A client process connects by calling either 407 // the CreateFile or CallNamedPipe function. 408 // 409 // https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-connectnamedpipe 410 func ConnectNamedPipe(h uintptr, o *Overlapped) error { 411 r, _, err := syscallN(funcConnectNamedPipe.address(), h, uintptr(unsafe.Pointer(o))) 412 if r == 0 { 413 return unboxError(err) 414 } 415 return nil 416 } 417 418 // NtUnmapViewOfSection Windows API Call 419 // 420 // The NtUnmapViewOfSection routine un-maps a view of a section from the virtual 421 // address space of a subject process. 422 // 423 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwunmapviewofsection 424 func NtUnmapViewOfSection(proc, section uintptr) error { 425 if r, _, _ := syscallN(funcNtUnmapViewOfSection.address(), proc, section); r > 0 { 426 return formatNtError(r) 427 } 428 return nil 429 } 430 431 // NtFreeVirtualMemory Windows API Call 432 // 433 // The NtFreeVirtualMemory routine releases, decommits, or both releases and 434 // decommits, a region of pages within the virtual address space of a specified 435 // process. 436 // 437 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntfreevirtualmemory 438 func NtFreeVirtualMemory(h, address, size uintptr) error { 439 var ( 440 s uintptr = size 441 r, _, _ = syscallN( 442 funcNtFreeVirtualMemory.address(), h, uintptr(unsafe.Pointer(&address)), uintptr(unsafe.Pointer(&s)), 443 0x8000, 444 ) 445 // 0x8000 - MEM_RELEASE 446 ) 447 if r > 0 { 448 return formatNtError(r) 449 } 450 return nil 451 } 452 453 // SetServiceStatus Windows API Call 454 // 455 // Contains status information for a service. The ControlService, EnumDependentServices, 456 // EnumServicesStatus, and QueryServiceStatus functions use this structure. A 457 // service uses this structure in the SetServiceStatus function to report its 458 // current status to the service control manager. 459 // 460 // https://docs.microsoft.com/en-us/windows/win32/api/winsvc/ns-winsvc-service_status 461 func SetServiceStatus(h uintptr, s *ServiceStatus) error { 462 r, _, err := syscallN(funcSetServiceStatus.address(), h, uintptr(unsafe.Pointer(s))) 463 if r == 0 { 464 return unboxError(err) 465 } 466 return nil 467 } 468 469 // CheckRemoteDebuggerPresent Windows API Call 470 // 471 // Determines whether the specified process is being debugged. 472 // 473 // https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-checkremotedebuggerpresent 474 // 475 // Calls 'NtQueryInformationProcess' under the hood. 476 func CheckRemoteDebuggerPresent(h uintptr, b *bool) error { 477 var ( 478 p uintptr 479 r, _, _ = syscallN(funcNtQueryInformationProcess.address(), h, 0x7, uintptr(unsafe.Pointer(&p)), ptrSize, 0) 480 // 0x7 - ProcessDebugPort 481 ) 482 if r > 0 { 483 return formatNtError(r) 484 } 485 *b = p > 0 486 return nil 487 } 488 489 // StartServiceCtrlDispatcher Windows API Call 490 // 491 // Connects the main thread of a service process to the service control manager, 492 // which causes the thread to be the service control dispatcher thread for the 493 // calling process. 494 // 495 // https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-startservicectrldispatcherw 496 func StartServiceCtrlDispatcher(t *ServiceTableEntry) error { 497 r, _, err := syscallN(funcStartServiceCtrlDispatcher.address(), uintptr(unsafe.Pointer(t))) 498 if r == 0 { 499 return unboxError(err) 500 } 501 return nil 502 } 503 504 // LoadLibraryEx Windows API Call 505 // 506 // Loads the specified module into the address space of the calling process. 507 // The specified module may cause other modules to be loaded. 508 // 509 // https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw 510 func LoadLibraryEx(s string, flags uintptr) (uintptr, error) { 511 n, err := UTF16PtrFromString(s) 512 if err != nil { 513 return 0, err 514 } 515 r, _, e := syscallN(funcLoadLibraryEx.address(), uintptr(unsafe.Pointer(n)), 0, flags) 516 if r == 0 { 517 return 0, unboxError(e) 518 } 519 return r, nil 520 } 521 522 // LookupPrivilegeValue Windows API Call 523 // 524 // The LookupPrivilegeValue function retrieves the locally unique identifier 525 // (LUID) used on a specified system to locally represent the specified privilege 526 // name. 527 // 528 // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupprivilegevaluew 529 func LookupPrivilegeValue(system, name string, l *LUID) error { 530 var ( 531 s, n *uint16 532 err error 533 ) 534 if len(system) > 0 { 535 if s, err = UTF16PtrFromString(system); err != nil { 536 return err 537 } 538 } 539 if n, err = UTF16PtrFromString(name); err != nil { 540 return err 541 } 542 r, _, err1 := syscallN( 543 funcLookupPrivilegeValue.address(), uintptr(unsafe.Pointer(s)), uintptr(unsafe.Pointer(n)), 544 uintptr(unsafe.Pointer(l)), 545 ) 546 if r == 0 { 547 return unboxError(err1) 548 } 549 return nil 550 } 551 552 // WaitForSingleObject Windows API Call 553 // 554 // Waits until the specified object is in the signaled state or the time-out 555 // interval elapses. 556 // 557 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject 558 func WaitForSingleObject(h uintptr, timeout int32) (uint32, error) { 559 if v := int64(h); v >= -12 && v <= -10 { 560 if p, err := getProcessPeb(); err == nil { 561 switch v { 562 case -10: // STD_INPUT_HANDLE 563 h = p.ProcessParameters.StandardInput 564 case -11: // STD_OUTPUT_HANDLE 565 h = p.ProcessParameters.StandardOutput 566 case -12: // STD_ERROR_HANDLE 567 h = p.ProcessParameters.StandardError 568 } 569 } 570 } 571 var t *uint64 572 if timeout != -1 { 573 n := uint64(timeout * -10000) 574 t = &n 575 } 576 r, _, _ := syscallN(funcNtWaitForSingleObject.address(), h, 0, uintptr(unsafe.Pointer(t))) 577 switch r { 578 case 0, 0x000000C0, 0x00000101, 0x00000102: 579 return uint32(r), nil 580 } 581 return 0, formatNtError(r) 582 } 583 584 // ReadFile Windows API Call 585 // 586 // Reads data from the specified file or input/output (I/O) device. Reads 587 // occur at the position specified by the file pointer if supported by the device. 588 // 589 // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile 590 func ReadFile(h uintptr, b []byte, n *uint32, o *Overlapped) error { 591 var v *byte 592 if len(b) > 0 { 593 v = &b[0] 594 } 595 r, _, err := syscallN( 596 funcReadFile.address(), h, uintptr(unsafe.Pointer(v)), uintptr(len(b)), uintptr(unsafe.Pointer(n)), 597 uintptr(unsafe.Pointer(o)), 598 ) 599 if r == 0 { 600 return unboxError(err) 601 } 602 return nil 603 } 604 605 // WriteFile Windows API Call 606 // 607 // Writes data to the specified file or input/output (I/O) device. 608 // 609 // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile 610 func WriteFile(h uintptr, b []byte, n *uint32, o *Overlapped) error { 611 var v *byte 612 if len(b) > 0 { 613 v = &b[0] 614 } 615 r, _, err := syscallN( 616 funcWriteFile.address(), h, uintptr(unsafe.Pointer(v)), uintptr(len(b)), uintptr(unsafe.Pointer(n)), 617 uintptr(unsafe.Pointer(o)), 618 ) 619 if r == 0 { 620 return unboxError(err) 621 } 622 return nil 623 } 624 625 // OpenProcessToken Windows API Call 626 // 627 // The OpenProcessToken function opens the access token associated with a process. 628 // 629 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken 630 // 631 // Re-targeted to use 'NtOpenProcessToken' instead. 632 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntopenprocesstoken 633 func OpenProcessToken(h uintptr, access uint32, res *uintptr) error { 634 if r, _, _ := syscallN(funcNtOpenProcessToken.address(), h, uintptr(access), uintptr(unsafe.Pointer(res))); r > 0 { 635 return formatNtError(r) 636 } 637 return nil 638 } 639 640 // NtWriteVirtualMemory Windows API Call 641 // 642 // This function copies the specified address range from the current process 643 // into the specified address range of the specified process. 644 // 645 // http://www.codewarrior.cn/ntdoc/winnt/mm/NtWriteVirtualMemory.htm 646 func NtWriteVirtualMemory(h, address uintptr, b []byte) (uint32, error) { 647 var ( 648 s uint32 649 r, _, _ = syscallN( 650 funcNtWriteVirtualMemory.address(), h, address, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), 651 uintptr(unsafe.Pointer(&s)), 652 ) 653 ) 654 if r > 0 { 655 return 0, formatNtError(r) 656 } 657 return s, nil 658 } 659 660 // SecurityDescriptorFromString converts an SDDL string describing a security 661 // descriptor into a self-relative security descriptor object allocated on the 662 // Go heap. 663 func SecurityDescriptorFromString(s string) (*SecurityDescriptor, error) { 664 var ( 665 h *SecurityDescriptor 666 err = securityDescriptorFromString(s, 1, &h, nil) 667 ) 668 if err != nil { 669 return nil, err 670 } 671 c := h.copyRelative() 672 localFree(uintptr(unsafe.Pointer(h))) 673 return c, nil 674 } 675 676 // QueryServiceDynamicInformation Windows API Call 677 // 678 // Retrieves dynamic information related to the current service start. 679 // 680 // https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryservicedynamicinformation 681 // 682 // This function is not avaliable to any systems older than Windows 8 (<= Win8). 683 func QueryServiceDynamicInformation(h uintptr, l uint32) (uint32, error) { 684 if funcQueryServiceDynamicInformation.find() != nil { 685 return 0, syscall.EINVAL 686 } 687 var ( 688 a *uint32 689 r, _, err = syscallN( 690 funcQueryServiceDynamicInformation.address(), h, uintptr(l), uintptr(unsafe.Pointer(&a)), 691 ) 692 ) 693 if r == 0 { 694 return 0, unboxError(err) 695 } 696 v := *a 697 localFree(uintptr(unsafe.Pointer(&a))) 698 return v, nil 699 } 700 701 // OpenThread Windows API Call 702 // 703 // Opens an existing thread object. 704 // 705 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread 706 // 707 // Re-targeted to use 'NtOpenThread' instead. 708 // https://learn.microsoft.com/en-us/windows/win32/devnotes/ntopenthread 709 func OpenThread(access uint32, inherit bool, tid uint32) (uintptr, error) { 710 var ( 711 o objAttrs 712 h uintptr 713 i clientID 714 ) 715 if i.Thread = uintptr(tid); inherit { 716 // 0x2 - OBJ_INHERIT 717 o.Attributes = 0x2 718 } 719 o.Length = uint32(unsafe.Sizeof(o)) 720 r, _, _ := syscallN( 721 funcNtOpenThread.address(), uintptr(unsafe.Pointer(&h)), uintptr(access), uintptr(unsafe.Pointer(&o)), 722 uintptr(unsafe.Pointer(&i)), 723 ) 724 if r > 0 { 725 return 0, formatNtError(r) 726 } 727 return h, nil 728 } 729 730 // OpenMutex Windows API Call 731 // 732 // Opens an existing named mutex object. 733 // 734 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-OpenMutexw 735 func OpenMutex(access uint32, inherit bool, name string) (uintptr, error) { 736 n, err := UTF16PtrFromString(name) 737 if err != nil { 738 return 0, err 739 } 740 var i uint32 741 if inherit { 742 i = 1 743 } 744 r, _, err1 := syscallN(funcOpenMutex.address(), uintptr(access), uintptr(i), uintptr(unsafe.Pointer(n))) 745 if r == 0 { 746 return 0, unboxError(err1) 747 } 748 return r, nil 749 } 750 751 // OpenEvent Windows API Call 752 // 753 // Opens an existing named event object. 754 // 755 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-openeventw 756 func OpenEvent(access uint32, inherit bool, name string) (uintptr, error) { 757 n, err := UTF16PtrFromString(name) 758 if err != nil { 759 return 0, err 760 } 761 var i uint32 762 if inherit { 763 i = 1 764 } 765 r, _, err1 := syscallN(funcOpenEvent.address(), uintptr(access), uintptr(i), uintptr(unsafe.Pointer(n))) 766 if r == 0 { 767 return 0, unboxError(err1) 768 } 769 return r, nil 770 } 771 772 // OpenProcess Windows API Call 773 // 774 // Opens an existing local process object. 775 // 776 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess 777 // 778 // Re-targeted to use 'NtOpenProcess' instead. 779 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-ntopenprocess 780 func OpenProcess(access uint32, inherit bool, pid uint32) (uintptr, error) { 781 var ( 782 o objAttrs 783 h uintptr 784 i clientID 785 ) 786 if i.Process = uintptr(pid); inherit { 787 // 0x2 - OBJ_INHERIT 788 o.Attributes = 0x2 789 } 790 o.Length = uint32(unsafe.Sizeof(o)) 791 r, _, _ := syscallN( 792 funcNtOpenProcess.address(), uintptr(unsafe.Pointer(&h)), uintptr(access), uintptr(unsafe.Pointer(&o)), 793 uintptr(unsafe.Pointer(&i)), 794 ) 795 if r > 0 { 796 return 0, formatNtError(r) 797 } 798 return h, nil 799 } 800 801 // GetOverlappedResult Windows API Call 802 // 803 // Retrieves the results of an overlapped operation on the specified file, 804 // named pipe, or communications device. To specify a timeout interval or wait 805 // on an alertable thread, use GetOverlappedResultEx. 806 // 807 // https://docs.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-getoverlappedresult 808 func GetOverlappedResult(h uintptr, o *Overlapped, n *uint32, w bool) error { 809 var z uint32 810 if w { 811 z = 1 812 } 813 r, _, err := syscallN( 814 funcGetOverlappedResult.address(), h, uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(n)), uintptr(z), 815 ) 816 if r == 0 { 817 return unboxError(err) 818 } 819 return nil 820 } 821 822 // OpenThreadToken Windows API Call 823 // 824 // The OpenThreadToken function opens the access token associated with a thread. 825 // 826 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthreadtoken 827 // 828 // Re-targeted to use 'NtOpenThreadToken' instead. 829 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntopenthreadtoken 830 func OpenThreadToken(h uintptr, access uint32, self bool, t *uintptr) error { 831 var s uint32 832 if self { 833 s = 1 834 } 835 r, _, _ := syscallN(funcNtOpenThreadToken.address(), h, uintptr(access), uintptr(s), uintptr(unsafe.Pointer(t))) 836 if r > 0 { 837 return formatNtError(r) 838 } 839 return nil 840 } 841 842 // OpenSemaphore Windows API Call 843 // 844 // Opens an existing named semaphore object. 845 // 846 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-OpenSemaphorew 847 func OpenSemaphore(access uint32, inherit bool, name string) (uintptr, error) { 848 n, err := UTF16PtrFromString(name) 849 if err != nil { 850 return 0, err 851 } 852 var i uint32 853 if inherit { 854 i = 1 855 } 856 r, _, err1 := syscallN(funcOpenSemaphore.address(), uintptr(access), uintptr(i), uintptr(unsafe.Pointer(n))) 857 if r == 0 { 858 return 0, unboxError(err1) 859 } 860 return r, nil 861 } 862 863 // NtAllocateVirtualMemory Windows API Call 864 // 865 // The NtAllocateVirtualMemory routine reserves, commits, or both, a region of 866 // pages within the user-mode virtual address space of a specified process. 867 // 868 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntallocatevirtualmemory 869 func NtAllocateVirtualMemory(h uintptr, size, access uint32) (uintptr, error) { 870 var ( 871 a uintptr 872 x = uintptr(size) 873 r, _, _ = syscallN( 874 funcNtAllocateVirtualMemory.address(), h, uintptr(unsafe.Pointer(&a)), 0, uintptr(unsafe.Pointer(&x)), 875 0x3000, uintptr(access), 876 ) 877 // 0x300 - MEM_COMMIT | MEM_RESERVE 878 ) 879 if r > 0 { 880 return 0, formatNtError(r) 881 } 882 return a, nil 883 } 884 885 // NtImpersonateThread Windows API Call 886 // 887 // This routine is used to cause the server thread to impersonate the client 888 // thread. The impersonation is done according to the specified quality 889 // of service parameters. 890 // 891 // http://web.archive.org/web/20190822133735/https://www.codewarrior.cn/ntdoc/winnt/ps/NtImpersonateThread.htm 892 // 893 // Thanks to: https://www.tiraniddo.dev/2017/08/the-art-of-becoming-trustedinstaller.html 894 func NtImpersonateThread(h, client uintptr, s *SecurityQualityOfService) error { 895 if r, _, _ := syscallN(funcNtImpersonateThread.address(), h, client, uintptr(unsafe.Pointer(s))); r > 0 { 896 return formatNtError(r) 897 } 898 return nil 899 } 900 901 // WaitForMultipleObjects Windows API Call 902 // 903 // Waits until one or all of the specified objects are in the signaled state or 904 // the time-out interval elapses. To enter an alertable wait state, use the 905 // WaitForMultipleObjectsEx function. 906 // 907 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects 908 // 909 // Calls 'WaitForMultipleObjectsEx' under the hood. 910 func WaitForMultipleObjects(h []uintptr, all bool, timeout int32) (uint32, error) { 911 n, a := uint32(len(h)), 1 912 if n <= 0 || n > 64 { 913 return 0, syscall.EINVAL 914 } 915 if all { 916 a = 0 917 } 918 var ( 919 p *processPeb 920 err error 921 ) 922 for i := range h { 923 v := int64(h[i]) 924 if v < -12 || v > -10 { 925 continue 926 } 927 if p == nil && err == nil { 928 p, err = getProcessPeb() 929 } 930 if p != nil { 931 switch v { 932 case -10: // STD_INPUT_HANDLE 933 h[i] = p.ProcessParameters.StandardInput 934 case -11: // STD_OUTPUT_HANDLE 935 h[i] = p.ProcessParameters.StandardOutput 936 case -12: // STD_ERROR_HANDLE 937 h[i] = p.ProcessParameters.StandardError 938 } 939 } 940 } 941 var t *uint64 942 if timeout != -1 { 943 n := uint64(timeout * -10000) 944 t = &n 945 } 946 r, _, _ := syscallN(funcNtWaitForMultipleObjects.address(), uintptr(n), uintptr(unsafe.Pointer(&h[0])), uintptr(a), 0, uintptr(unsafe.Pointer(t))) 947 switch r { 948 case 0, 0x000000C0, 0x00000101, 0x00000102: 949 return uint32(r), nil 950 } 951 if r <= 64 { 952 return uint32(r), nil 953 } 954 return 0, formatNtError(r) 955 } 956 957 // CreateMutex Windows API Call 958 // 959 // Creates or opens a named or unnamed mutex object. 960 // 961 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-CreateMutexw 962 func CreateMutex(sa *SecurityAttributes, initial bool, name string) (uintptr, error) { 963 var ( 964 n *uint16 965 err error 966 ) 967 if len(name) > 0 { 968 if n, err = UTF16PtrFromString(name); err != nil { 969 return 0, err 970 } 971 } 972 var i uint32 973 if initial { 974 i = 1 975 } 976 r, _, err1 := syscallN( 977 funcCreateMutex.address(), uintptr(unsafe.Pointer(sa)), uintptr(i), uintptr(unsafe.Pointer(n)), 978 ) 979 if r == 0 { 980 return 0, unboxError(err1) 981 } 982 if err1 == syscall.ERROR_ALREADY_EXISTS { 983 return r, unboxError(err1) 984 } 985 return r, nil 986 } 987 988 // NtProtectVirtualMemory Windows API Call 989 // 990 // Changes the protection on a region of committed pages in the virtual address 991 // space of a specified process. 992 // 993 // http://pinvoke.net/default.aspx/ntdll/NtProtectVirtualMemory.html 994 func NtProtectVirtualMemory(h, address uintptr, size, access uint32) (uint32, error) { 995 var ( 996 x, v uint32 = size, 0 997 r, _, _ = syscallN( 998 funcNtProtectVirtualMemory.address(), h, uintptr(unsafe.Pointer(&address)), uintptr(unsafe.Pointer(&x)), 999 uintptr(access), uintptr(unsafe.Pointer(&v)), 1000 ) 1001 ) 1002 if r > 0 { 1003 return 0, formatNtError(r) 1004 } 1005 return v, nil 1006 } 1007 1008 // LoginUser Windows API Call 1009 // 1010 // The LogonUser function attempts to log a user on to the local computer. The 1011 // local computer is the computer from which LogonUser was called. You cannot 1012 // use LogonUser to log on to a remote computer. You specify the user with a 1013 // user name and domain and authenticate the user with a plaintext password. 1014 // If the function succeeds, you receive a handle to a token that represents 1015 // the logged-on user. You can then use this token handle to impersonate the 1016 // specified user or, in most cases, to create a process that runs in the 1017 // context of the specified user. 1018 // 1019 // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-logonuserw 1020 func LoginUser(user, domain, pass string, logintype, provider uint32) (uintptr, error) { 1021 if len(domain) == 0 { 1022 domain = "." 1023 } 1024 u, err := UTF16PtrFromString(user) 1025 if err != nil { 1026 return 0, err 1027 } 1028 var p, d *uint16 1029 if d, err = UTF16PtrFromString(domain); err != nil { 1030 return 0, err 1031 } 1032 if len(pass) > 0 { 1033 if p, err = UTF16PtrFromString(pass); err != nil { 1034 return 0, err 1035 } 1036 } 1037 var ( 1038 t uintptr 1039 r, _, err1 = syscallN( 1040 funcLogonUser.address(), uintptr(unsafe.Pointer(u)), uintptr(unsafe.Pointer(d)), 1041 uintptr(unsafe.Pointer(p)), uintptr(logintype), uintptr(provider), uintptr(unsafe.Pointer(&t)), 1042 ) 1043 ) 1044 if r == 0 { 1045 return 0, unboxError(err1) 1046 } 1047 return t, nil 1048 } 1049 1050 // RegSetValueEx Windows API Call 1051 // 1052 // Sets the data and type of a specified value under a registry key. 1053 // 1054 // https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-RegSetValueExw 1055 func RegSetValueEx(h uintptr, path string, t uint32, data *byte, dataLen uint32) error { 1056 p, err := UTF16PtrFromString(path) 1057 if err != nil { 1058 return err 1059 } 1060 r, _, err1 := syscallN( 1061 funcRegSetValueEx.address(), h, uintptr(unsafe.Pointer(p)), 0, uintptr(t), uintptr(unsafe.Pointer(data)), 1062 uintptr(dataLen), 1063 ) 1064 if r > 0 { 1065 return unboxError(err1) 1066 } 1067 return nil 1068 } 1069 1070 // CreateEvent Windows API Call 1071 // 1072 // Creates or opens a named or unnamed event object. 1073 // 1074 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-CreateEventw 1075 func CreateEvent(sa *SecurityAttributes, manual, initial bool, name string) (uintptr, error) { 1076 var ( 1077 n *uint16 1078 err error 1079 ) 1080 if len(name) > 0 { 1081 if n, err = UTF16PtrFromString(name); err != nil { 1082 return 0, err 1083 } 1084 } 1085 var i, m uint32 1086 if initial { 1087 i = 1 1088 } 1089 if manual { 1090 m = 1 1091 } 1092 r, _, err1 := syscallN( 1093 funcCreateEvent.address(), uintptr(unsafe.Pointer(sa)), uintptr(m), uintptr(i), uintptr(unsafe.Pointer(n)), 1094 ) 1095 if r == 0 { 1096 return 0, unboxError(err1) 1097 } 1098 if err1 == syscall.ERROR_ALREADY_EXISTS { 1099 return r, unboxError(err1) 1100 } 1101 return r, nil 1102 } 1103 func securityDescriptorFromString(s string, v uint32, i **SecurityDescriptor, n *uint32) error { 1104 p, err := UTF16PtrFromString(s) 1105 if err != nil { 1106 return err 1107 } 1108 r, _, err2 := syscallN( 1109 funcConvertStringSecurityDescriptorToSecurityDescriptor.address(), uintptr(unsafe.Pointer(p)), uintptr(v), 1110 uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(n)), 1111 ) 1112 if r == 0 { 1113 return unboxError(err2) 1114 } 1115 return nil 1116 } 1117 1118 // RegisterServiceCtrlHandlerEx Windows API Call 1119 // 1120 // Registers a function to handle extended service control requests. 1121 // 1122 // https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-registerservicectrlhandlerexw 1123 func RegisterServiceCtrlHandlerEx(name string, handler uintptr, args uintptr) (uintptr, error) { 1124 n, err := UTF16PtrFromString(name) 1125 if err != nil { 1126 return 0, err 1127 } 1128 r, _, err1 := syscallN(funcRegisterServiceCtrlHandlerEx.address(), uintptr(unsafe.Pointer(n)), handler, args) 1129 if r == 0 { 1130 return 0, unboxError(err1) 1131 } 1132 return r, nil 1133 } 1134 1135 // CreateSemaphore Windows API Call 1136 // 1137 // Creates or opens a named or unnamed semaphore object. 1138 // 1139 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-CreateSemaphorew 1140 func CreateSemaphore(sa *SecurityAttributes, initial, max uint32, name string) (uintptr, error) { 1141 var ( 1142 n *uint16 1143 err error 1144 ) 1145 if len(name) > 0 { 1146 if n, err = UTF16PtrFromString(name); err != nil { 1147 return 0, err 1148 } 1149 } 1150 r, _, err1 := syscallN( 1151 funcCreateSemaphore.address(), uintptr(unsafe.Pointer(sa)), uintptr(initial), uintptr(max), 1152 uintptr(unsafe.Pointer(n)), 1153 ) 1154 if r == 0 { 1155 return 0, unboxError(err1) 1156 } 1157 if err1 == syscall.ERROR_ALREADY_EXISTS { 1158 return r, unboxError(err1) 1159 } 1160 return r, nil 1161 } 1162 1163 // GetTokenInformation Windows API Call 1164 // 1165 // The GetTokenInformation function retrieves a specified type of information 1166 // about an access token. The calling process must have appropriate access 1167 // rights to obtain the information. 1168 // 1169 // https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation 1170 // 1171 // Re-targeted to use 'NtQueryInformationToken' instead. 1172 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationtoken 1173 func GetTokenInformation(t uintptr, class uint32, info *byte, length uint32, ret *uint32) error { 1174 r, _, _ := syscallN( 1175 funcNtQueryInformationToken.address(), t, uintptr(class), uintptr(unsafe.Pointer(info)), 1176 uintptr(length), uintptr(unsafe.Pointer(ret)), 1177 ) 1178 if r > 0 { 1179 return formatNtError(r) 1180 } 1181 return nil 1182 } 1183 1184 // InitiateSystemShutdownEx Windows API Call 1185 // 1186 // Initiates a shutdown and optional restart of the specified computer, and 1187 // optionally records the reason for the shutdown. 1188 // 1189 // NOTE: The caller must have the "SeShutdownPrivilege" privilege enabled. This 1190 // 1191 // function does NOT automatically request it. 1192 // 1193 // https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-initiatesystemshutdownexa 1194 func InitiateSystemShutdownEx(t, msg string, secs uint32, force, reboot bool, reason uint32) error { 1195 var ( 1196 c, m *uint16 1197 err error 1198 ) 1199 if len(t) > 0 { 1200 if c, err = UTF16PtrFromString(t); err != nil { 1201 return err 1202 } 1203 } 1204 if len(msg) > 0 { 1205 if m, err = UTF16PtrFromString(msg); err != nil { 1206 return err 1207 } 1208 } 1209 var f, x uint32 1210 if force { 1211 f = 1 1212 } 1213 if reboot { 1214 x = 1 1215 } 1216 r, _, err1 := syscallN( 1217 funcInitiateSystemShutdownEx.address(), uintptr(unsafe.Pointer(c)), uintptr(unsafe.Pointer(m)), 1218 uintptr(secs), uintptr(f), uintptr(x), uintptr(reason), 1219 ) 1220 if r == 0 { 1221 return unboxError(err1) 1222 } 1223 return nil 1224 } 1225 1226 // NtCreateSection Windows API Call 1227 // 1228 // The NtCreateSection routine creates a section object. 1229 // 1230 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwcreatesection 1231 func NtCreateSection(access uint32, size uint64, protect, attrs uint32, file uintptr) (uintptr, error) { 1232 var ( 1233 x = size 1234 h uintptr 1235 ) 1236 r, _, _ := syscallN( 1237 funcNtCreateSection.address(), uintptr(unsafe.Pointer(&h)), uintptr(access), 0, uintptr(unsafe.Pointer(&x)), 1238 uintptr(protect), uintptr(attrs), file, 1239 ) 1240 if r > 0 { 1241 return 0, formatNtError(r) 1242 } 1243 return h, nil 1244 } 1245 1246 // CreateMailslot Windows API Call 1247 // 1248 // Creates a mailslot with the specified name and returns a handle that a 1249 // mailslot server can use to perform operations on the mailslot. The mailslot 1250 // is local to the computer that creates it. An error occurs if a mailslot 1251 // with the specified name already exists. 1252 // 1253 // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createmailslotw 1254 func CreateMailslot(name string, maxSize uint32, timeout int32, sa *SecurityAttributes) (uintptr, error) { 1255 n, err := UTF16PtrFromString(name) 1256 if err != nil { 1257 return 0, err 1258 } 1259 r, _, err1 := syscallN( 1260 funcCreateMailslot.address(), uintptr(unsafe.Pointer(n)), uintptr(maxSize), uintptr(uint32(timeout)), 1261 uintptr(unsafe.Pointer(sa)), 1262 ) 1263 if r == invalid { 1264 return 0, unboxError(err1) 1265 } 1266 if err1 == syscall.ERROR_ALREADY_EXISTS { 1267 return r, unboxError(err1) 1268 } 1269 return r, nil 1270 } 1271 1272 // DuplicateTokenEx Windows API Call 1273 // 1274 // The DuplicateTokenEx function creates a new access token that duplicates an 1275 // existing token. This function can create either a primary token or an 1276 // impersonation token. 1277 // 1278 // https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-duplicatetokenex 1279 // 1280 // Re-targeted to use 'NtDuplicateToken' instead. 1281 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntduplicatetoken 1282 func DuplicateTokenEx(h uintptr, access uint32, sa *SecurityAttributes, level, p uint32, new *uintptr) error { 1283 var ( 1284 o objAttrs 1285 q SecurityQualityOfService 1286 ) 1287 if q.ImpersonationLevel = level; sa != nil { 1288 if o.SecurityDescriptor = sa.SecurityDescriptor; sa.InheritHandle == 1 { 1289 o.Attributes |= 0x2 1290 } 1291 } 1292 o.Length = uint32(unsafe.Sizeof(o)) 1293 q.Length = uint32(unsafe.Sizeof(q)) 1294 o.SecurityQualityOfService = &q 1295 r, _, _ := syscallN( 1296 funcNtDuplicateToken.address(), h, uintptr(access), uintptr(unsafe.Pointer(&o)), 0, uintptr(p), uintptr(unsafe.Pointer(new)), 1297 ) 1298 if r > 0 { 1299 return formatNtError(r) 1300 } 1301 return nil 1302 } 1303 1304 // DuplicateHandle Windows API Call 1305 // 1306 // Duplicates an object handle. 1307 // 1308 // https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle 1309 // 1310 // Re-targeted to use 'NtDuplicateObject' instead. 1311 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-zwduplicateobject 1312 func DuplicateHandle(srcProc, src, dstProc uintptr, dst *uintptr, access uint32, inherit bool, options uint32) error { 1313 // NOTE(dij): This is to catch and emulate the actions that normally the 1314 // 'DuplicateHandle' function will do. This will catch any pusudo 1315 // handles for StdErr/StdOut/Stdin and grab the real ones from the 1316 // process PEB. 1317 // 1318 // I also think there's a bug in this function as 'DuplicateHandle' 1319 // does NOT check the 'srcProc' argument when attempting to resolve 1320 // pusudo handles and only resolves them for the current process. 1321 // 1322 // Handles constant source https://learn.microsoft.com/en-us/windows/console/getstdhandle 1323 if v := int64(src); v >= -12 && v <= -10 { 1324 if p, err := getProcessPeb(); err == nil { 1325 switch v { 1326 case -10: // STD_INPUT_HANDLE 1327 src = p.ProcessParameters.StandardInput 1328 case -11: // STD_OUTPUT_HANDLE 1329 src = p.ProcessParameters.StandardOutput 1330 case -12: // STD_ERROR_HANDLE 1331 src = p.ProcessParameters.StandardError 1332 } 1333 } 1334 } 1335 var i uint32 1336 if inherit { 1337 // 0x2 - OBJ_INHERIT 1338 i = 0x2 1339 } 1340 r, _, _ := syscallN( 1341 funcNtDuplicateObject.address(), srcProc, src, dstProc, uintptr(unsafe.Pointer(dst)), uintptr(access), uintptr(i), 1342 uintptr(options), 1343 ) 1344 if r > 0 { 1345 return formatNtError(r) 1346 } 1347 return nil 1348 } 1349 1350 // NtMapViewOfSection Windows API Call 1351 // 1352 // The NtMapViewOfSection routine maps a view of a section into the virtual 1353 // address space of a subject process. 1354 // 1355 // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwmapviewofsection 1356 func NtMapViewOfSection(section, proc uintptr, offset, size uint64, dis, allocType, protect uint32) (uintptr, error) { 1357 var ( 1358 a uintptr 1359 o, x = offset, size 1360 r, _, _ = syscallN( 1361 funcNtMapViewOfSection.address(), section, proc, uintptr(unsafe.Pointer(&a)), 0, 0, uintptr(unsafe.Pointer(&o)), 1362 uintptr(unsafe.Pointer(&x)), uintptr(dis), uintptr(allocType), uintptr(protect), 1363 ) 1364 ) 1365 if r > 0 { 1366 return 0, formatNtError(r) 1367 } 1368 return a, nil 1369 } 1370 1371 // RegEnumValue Windows API Call 1372 // 1373 // Enumerates the values for the specified open registry key. The function 1374 // copies one indexed value name and data block for the key each time it is 1375 // called. 1376 // 1377 // https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regenumvaluew 1378 func RegEnumValue(h uintptr, index uint32, path *uint16, pathLen, valType *uint32, data *byte, dataLen *uint32) error { 1379 r, _, err := syscallN( 1380 funcRegEnumValue.address(), h, uintptr(index), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(pathLen)), 1381 0, uintptr(unsafe.Pointer(valType)), uintptr(unsafe.Pointer(data)), uintptr(unsafe.Pointer(dataLen)), 1382 ) 1383 if r > 0 { 1384 return unboxError(err) 1385 } 1386 return nil 1387 } 1388 1389 // CreateNamedPipe Windows API Call 1390 // 1391 // Creates an instance of a named pipe and returns a handle for subsequent pipe 1392 // operations. A named pipe server process uses this function either to create 1393 // the first instance of a specific named pipe and establish its basic attributes 1394 // or to create a new instance of an existing named pipe. 1395 // 1396 // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createnamedpipea 1397 func CreateNamedPipe(name string, flags, mode, max, out, in, timeout uint32, sa *SecurityAttributes) (uintptr, error) { 1398 n, err := UTF16PtrFromString(name) 1399 if err != nil { 1400 return 0, err 1401 } 1402 r, _, err1 := syscallN( 1403 funcCreateNamedPipe.address(), uintptr(unsafe.Pointer(n)), uintptr(flags), uintptr(mode), uintptr(max), 1404 uintptr(out), uintptr(in), uintptr(timeout), uintptr(unsafe.Pointer(sa)), 1405 ) 1406 if r == invalid { 1407 return 0, unboxError(err1) 1408 } 1409 return r, nil 1410 } 1411 1412 // AdjustTokenPrivileges Windows API Call 1413 // 1414 // The AdjustTokenPrivileges function enables or disables privileges in the 1415 // specified access token. Enabling or disabling privileges in an access token 1416 // requires TOKEN_ADJUST_PRIVILEGES access. 1417 // 1418 // https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokenprivileges 1419 // 1420 // Re-targeted to use 'NtAdjustPrivilegesToken' instead. 1421 // https://docs.rs/ntapi/0.3.6/aarch64-pc-windows-msvc/ntapi/ntseapi/fn.NtAdjustPrivilegesToken.html 1422 func AdjustTokenPrivileges(h uintptr, disableAll bool, new unsafe.Pointer, newLen uint32, old unsafe.Pointer, oldLen *uint32) error { 1423 var d uint32 1424 if disableAll { 1425 d = 1 1426 } 1427 r, _, _ := syscallN( 1428 funcNtAdjustTokenPrivileges.address(), h, uintptr(d), uintptr(new), uintptr(newLen), uintptr(old), 1429 uintptr(unsafe.Pointer(oldLen)), 1430 ) 1431 if r > 0 { 1432 return formatNtError(r) 1433 } 1434 return nil 1435 } 1436 1437 // RegCreateKeyEx Windows API Call 1438 // 1439 // Creates the specified registry key. If the key already exists, the function 1440 // opens it. Note that key names are not case sensitive. 1441 // 1442 // https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regcreatekeyexw 1443 func RegCreateKeyEx(h uintptr, path, class string, options, access uint32, sa *SecurityAttributes, out *uintptr, result *uint32) error { 1444 var ( 1445 p, c *uint16 1446 err error 1447 ) 1448 if len(class) > 0 { 1449 if c, err = UTF16PtrFromString(class); err != nil { 1450 return err 1451 } 1452 } 1453 if p, err = UTF16PtrFromString(path); err != nil { 1454 return err 1455 } 1456 r, _, err1 := syscallN( 1457 funcRegCreateKeyEx.address(), h, uintptr(unsafe.Pointer(p)), 0, uintptr(unsafe.Pointer(c)), uintptr(options), 1458 uintptr(access), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(out)), uintptr(unsafe.Pointer(result)), 1459 ) 1460 if r > 0 { 1461 return unboxError(err1) 1462 } 1463 return nil 1464 } 1465 1466 // CreateFile Windows API Call 1467 // 1468 // Creates or opens a file or I/O device. The most commonly used I/O devices 1469 // are as follows: file, file stream, directory, physical disk, volume, console 1470 // buffer, tape drive, communications resource, mailslot, and pipe. The function 1471 // returns a handle that can be used to access the file or device for various 1472 // types of I/O depending on the file or device and the flags and attributes 1473 // specified. 1474 // 1475 // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew 1476 func CreateFile(name string, access, mode uint32, sa *SecurityAttributes, disposition, attrs uint32, template uintptr) (uintptr, error) { 1477 n, err := UTF16PtrFromString(name) 1478 if err != nil { 1479 return 0, err 1480 } 1481 r, _, err1 := syscallN( 1482 funcCreateFile.address(), uintptr(unsafe.Pointer(n)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), 1483 uintptr(disposition), uintptr(attrs), template, 1484 ) 1485 if r == invalid { 1486 return 0, unboxError(err1) 1487 } 1488 return r, nil 1489 } 1490 1491 // UpdateProcThreadAttribute Windows API Call 1492 // 1493 // Updates the specified attribute in a list of attributes for process and 1494 // thread creation. 1495 // 1496 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute 1497 func UpdateProcThreadAttribute(a *StartupAttributes, attr uintptr, val unsafe.Pointer, valLen uint64, old *StartupAttributes, oldLen *uint64) error { 1498 r, _, err := syscallN( 1499 funcUpdateProcThreadAttribute.address(), uintptr(unsafe.Pointer(a)), 0, attr, uintptr(val), uintptr(valLen), 1500 uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldLen)), 1501 ) 1502 if r == 0 { 1503 return unboxError(err) 1504 } 1505 return nil 1506 } 1507 1508 // CreateProcess Windows API Call 1509 // 1510 // Creates a new process and its primary thread. The new process runs in the 1511 // security context of the calling process. 1512 // 1513 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw 1514 func CreateProcess(name, cmd string, procSa, threadSa *SecurityAttributes, inherit bool, flags uint32, env []string, dir string, y *StartupInfo, x *StartupInfoEx, i *ProcessInformation) error { 1515 var ( 1516 z uint32 1517 n, c, d, e *uint16 1518 err error 1519 ) 1520 if inherit { 1521 z = 1 1522 } 1523 if len(name) > 0 { 1524 if n, err = UTF16PtrFromString(name); err != nil { 1525 return err 1526 } 1527 } 1528 if len(cmd) > 0 { 1529 if c, err = UTF16PtrFromString(cmd); err != nil { 1530 return err 1531 } 1532 } 1533 if len(dir) > 0 { 1534 if d, err = UTF16PtrFromString(dir); err != nil { 1535 return err 1536 } 1537 } 1538 if len(env) > 0 { 1539 if e, err = StringListToUTF16Block(env); err != nil { 1540 return err 1541 } 1542 // 0x400 - CREATE_UNICODE_ENVIRONMENT 1543 flags |= 0x400 1544 } 1545 var j unsafe.Pointer 1546 if y == nil && x != nil { 1547 flags |= 0x80000 1548 j = unsafe.Pointer(x) 1549 } else { 1550 j = unsafe.Pointer(y) 1551 } 1552 r, _, err1 := syscallN( 1553 funcCreateProcess.address(), uintptr(unsafe.Pointer(n)), uintptr(unsafe.Pointer(c)), uintptr(unsafe.Pointer(procSa)), 1554 uintptr(unsafe.Pointer(threadSa)), uintptr(z), uintptr(flags), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(d)), 1555 uintptr(j), uintptr(unsafe.Pointer(i)), 1556 ) 1557 if r == 0 { 1558 return unboxError(err1) 1559 } 1560 return nil 1561 } 1562 1563 // CreateProcessWithLogin Windows API Call 1564 // 1565 // Creates a new process and its primary thread. Then the new process runs the 1566 // specified executable file in the security context of the specified credentials 1567 // (user, domain, and password). It can optionally load the user profile for a 1568 // specified user. 1569 // 1570 // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithlogonw 1571 func CreateProcessWithLogin(user, domain, pass string, loginFlags uint32, name, cmd string, flags uint32, env []string, dir string, y *StartupInfo, x *StartupInfoEx, i *ProcessInformation) error { 1572 var n, c, d, e, p, do *uint16 1573 u, err := UTF16PtrFromString(user) 1574 if err != nil { 1575 return err 1576 } 1577 if len(domain) > 0 { 1578 if do, err = UTF16PtrFromString(domain); err != nil { 1579 return err 1580 } 1581 } 1582 if len(pass) > 0 { 1583 if p, err = UTF16PtrFromString(pass); err != nil { 1584 return err 1585 } 1586 } 1587 if len(name) > 0 { 1588 if n, err = UTF16PtrFromString(name); err != nil { 1589 return err 1590 } 1591 } 1592 if len(cmd) > 0 { 1593 if c, err = UTF16PtrFromString(cmd); err != nil { 1594 return err 1595 } 1596 } 1597 if len(dir) > 0 { 1598 if d, err = UTF16PtrFromString(dir); err != nil { 1599 return err 1600 } 1601 } 1602 if len(env) > 0 { 1603 if e, err = StringListToUTF16Block(env); err != nil { 1604 return err 1605 } 1606 // 0x400 - CREATE_UNICODE_ENVIRONMENT 1607 flags |= 0x400 1608 } 1609 var j unsafe.Pointer 1610 if y == nil && x != nil { 1611 // NOTE(dij): For some reason adding this flag causes the function 1612 // to return "invalid parameter", even this IS THE ACCEPTED 1613 // thing to do???! 1614 // 1615 // flags |= 0x80000 1616 j = unsafe.Pointer(x) 1617 } else { 1618 j = unsafe.Pointer(y) 1619 } 1620 r, _, err1 := syscallN( 1621 funcCreateProcessWithLogon.address(), uintptr(unsafe.Pointer(u)), uintptr(unsafe.Pointer(do)), uintptr(unsafe.Pointer(p)), 1622 uintptr(loginFlags), uintptr(unsafe.Pointer(n)), uintptr(unsafe.Pointer(c)), uintptr(flags), uintptr(unsafe.Pointer(e)), 1623 uintptr(unsafe.Pointer(d)), uintptr(j), uintptr(unsafe.Pointer(i)), 1624 ) 1625 if r == 0 { 1626 return unboxError(err1) 1627 } 1628 return nil 1629 }