mirror of
https://github.com/rwinkhart/sys.git
synced 2026-09-01 14:47:28 -04:00
windows: add resource extraction functions
These functions make it possible to read executable resource information at runtime. Change-Id: I00f260199ecda8daeb3417eaa9c02198663063b7 Reviewed-on: https://go-review.googlesource.com/c/sys/+/298173 Trust: Jason A. Donenfeld <Jason@zx2c4.com> Trust: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
@@ -9,6 +9,7 @@ package windows
|
|||||||
import (
|
import (
|
||||||
errorspkg "errors"
|
errorspkg "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@@ -384,6 +385,10 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
|||||||
//sys getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetThreadPreferredUILanguages
|
//sys getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetThreadPreferredUILanguages
|
||||||
//sys getUserPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetUserPreferredUILanguages
|
//sys getUserPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetUserPreferredUILanguages
|
||||||
//sys getSystemPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetSystemPreferredUILanguages
|
//sys getSystemPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetSystemPreferredUILanguages
|
||||||
|
//sys findResource(module Handle, name uintptr, resType uintptr) (resInfo Handle, err error) = kernel32.FindResourceW
|
||||||
|
//sys SizeofResource(module Handle, resInfo Handle) (size uint32, err error) = kernel32.SizeofResource
|
||||||
|
//sys LoadResource(module Handle, resInfo Handle) (resData Handle, err error) = kernel32.LoadResource
|
||||||
|
//sys LockResource(resData Handle) (addr uintptr, err error) = kernel32.LockResource
|
||||||
|
|
||||||
// Process Status API (PSAPI)
|
// Process Status API (PSAPI)
|
||||||
//sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
|
//sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
|
||||||
@@ -1578,3 +1583,55 @@ func (s *UNICODE_STRING) Slice() []uint16 {
|
|||||||
func (s *UNICODE_STRING) String() string {
|
func (s *UNICODE_STRING) String() string {
|
||||||
return UTF16ToString(s.Slice())
|
return UTF16ToString(s.Slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindResource resolves a resource of the given name and resource type.
|
||||||
|
func FindResource(module Handle, name, resType ResourceIDOrString) (Handle, error) {
|
||||||
|
var namePtr, resTypePtr uintptr
|
||||||
|
var name16, resType16 *uint16
|
||||||
|
var err error
|
||||||
|
resolvePtr := func(i interface{}, keep **uint16) (uintptr, error) {
|
||||||
|
switch v := i.(type) {
|
||||||
|
case string:
|
||||||
|
*keep, err = UTF16PtrFromString(v)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return uintptr(unsafe.Pointer(*keep)), nil
|
||||||
|
case ResourceID:
|
||||||
|
return uintptr(v), nil
|
||||||
|
}
|
||||||
|
return 0, errorspkg.New("parameter must be a ResourceID or a string")
|
||||||
|
}
|
||||||
|
namePtr, err = resolvePtr(name, &name16)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
resTypePtr, err = resolvePtr(resType, &resType16)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
resInfo, err := findResource(module, namePtr, resTypePtr)
|
||||||
|
runtime.KeepAlive(name16)
|
||||||
|
runtime.KeepAlive(resType16)
|
||||||
|
return resInfo, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadResourceData(module, resInfo Handle) (data []byte, err error) {
|
||||||
|
size, err := SizeofResource(module, resInfo)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resData, err := LoadResource(module, resInfo)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ptr, err := LockResource(resData)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h := (*unsafeheader.Slice)(unsafe.Pointer(&data))
|
||||||
|
h.Data = unsafe.Pointer(ptr)
|
||||||
|
h.Len = int(size)
|
||||||
|
h.Cap = int(size)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package windows_test
|
package windows_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"debug/pe"
|
"debug/pe"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -562,3 +563,26 @@ func TestPEBFilePath(t *testing.T) {
|
|||||||
t.Errorf("expected os.Executable() to return same value as peb.Ldr.{entry}.FullDllName - want %#q; got %#q", osPath, pebPath)
|
t.Errorf("expected os.Executable() to return same value as peb.Ldr.{entry}.FullDllName - want %#q; got %#q", osPath, pebPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResourceExtraction(t *testing.T) {
|
||||||
|
system32, err := windows.GetSystemDirectory()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to find system32 directory: %v", err)
|
||||||
|
}
|
||||||
|
cmd, err := windows.LoadLibrary(filepath.Join(system32, "cmd.exe"))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to load cmd.exe: %v", err)
|
||||||
|
}
|
||||||
|
defer windows.FreeLibrary(cmd)
|
||||||
|
rsrc, err := windows.FindResource(cmd, windows.CREATEPROCESS_MANIFEST_RESOURCE_ID, windows.RT_MANIFEST)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to find cmd.exe manifest resource: %v", err)
|
||||||
|
}
|
||||||
|
manifest, err := windows.LoadResourceData(cmd, rsrc)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to load cmd.exe manifest resource data: %v", err)
|
||||||
|
}
|
||||||
|
if !bytes.Contains(manifest, []byte("</assembly>")) {
|
||||||
|
t.Errorf("did not find </assembly> in manifest")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2600,3 +2600,45 @@ const (
|
|||||||
SECURITY_SQOS_PRESENT = 0x100000
|
SECURITY_SQOS_PRESENT = 0x100000
|
||||||
SECURITY_VALID_SQOS_FLAGS = 0x1f0000
|
SECURITY_VALID_SQOS_FLAGS = 0x1f0000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ResourceID represents a 16-bit resource identifier, traditionally created with the MAKEINTRESOURCE macro.
|
||||||
|
type ResourceID uint16
|
||||||
|
|
||||||
|
// ResourceIDOrString must be either a ResourceID, to specify a resource or resource type by ID,
|
||||||
|
// or a string, to specify a resource or resource type by name.
|
||||||
|
type ResourceIDOrString interface{}
|
||||||
|
|
||||||
|
// Predefined resource names and types.
|
||||||
|
var (
|
||||||
|
// Predefined names.
|
||||||
|
CREATEPROCESS_MANIFEST_RESOURCE_ID ResourceID = 1
|
||||||
|
ISOLATIONAWARE_MANIFEST_RESOURCE_ID ResourceID = 2
|
||||||
|
ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID ResourceID = 3
|
||||||
|
ISOLATIONPOLICY_MANIFEST_RESOURCE_ID ResourceID = 4
|
||||||
|
ISOLATIONPOLICY_BROWSER_MANIFEST_RESOURCE_ID ResourceID = 5
|
||||||
|
MINIMUM_RESERVED_MANIFEST_RESOURCE_ID ResourceID = 1 // inclusive
|
||||||
|
MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID ResourceID = 16 // inclusive
|
||||||
|
|
||||||
|
// Predefined types.
|
||||||
|
RT_CURSOR ResourceID = 1
|
||||||
|
RT_BITMAP ResourceID = 2
|
||||||
|
RT_ICON ResourceID = 3
|
||||||
|
RT_MENU ResourceID = 4
|
||||||
|
RT_DIALOG ResourceID = 5
|
||||||
|
RT_STRING ResourceID = 6
|
||||||
|
RT_FONTDIR ResourceID = 7
|
||||||
|
RT_FONT ResourceID = 8
|
||||||
|
RT_ACCELERATOR ResourceID = 9
|
||||||
|
RT_RCDATA ResourceID = 10
|
||||||
|
RT_MESSAGETABLE ResourceID = 11
|
||||||
|
RT_GROUP_CURSOR ResourceID = 12
|
||||||
|
RT_GROUP_ICON ResourceID = 14
|
||||||
|
RT_VERSION ResourceID = 16
|
||||||
|
RT_DLGINCLUDE ResourceID = 17
|
||||||
|
RT_PLUGPLAY ResourceID = 19
|
||||||
|
RT_VXD ResourceID = 20
|
||||||
|
RT_ANICURSOR ResourceID = 21
|
||||||
|
RT_ANIICON ResourceID = 22
|
||||||
|
RT_HTML ResourceID = 23
|
||||||
|
RT_MANIFEST ResourceID = 24
|
||||||
|
)
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ var (
|
|||||||
procFindNextFileW = modkernel32.NewProc("FindNextFileW")
|
procFindNextFileW = modkernel32.NewProc("FindNextFileW")
|
||||||
procFindNextVolumeMountPointW = modkernel32.NewProc("FindNextVolumeMountPointW")
|
procFindNextVolumeMountPointW = modkernel32.NewProc("FindNextVolumeMountPointW")
|
||||||
procFindNextVolumeW = modkernel32.NewProc("FindNextVolumeW")
|
procFindNextVolumeW = modkernel32.NewProc("FindNextVolumeW")
|
||||||
|
procFindResourceW = modkernel32.NewProc("FindResourceW")
|
||||||
procFindVolumeClose = modkernel32.NewProc("FindVolumeClose")
|
procFindVolumeClose = modkernel32.NewProc("FindVolumeClose")
|
||||||
procFindVolumeMountPointClose = modkernel32.NewProc("FindVolumeMountPointClose")
|
procFindVolumeMountPointClose = modkernel32.NewProc("FindVolumeMountPointClose")
|
||||||
procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
|
procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
|
||||||
@@ -277,9 +278,11 @@ var (
|
|||||||
procIsWow64Process2 = modkernel32.NewProc("IsWow64Process2")
|
procIsWow64Process2 = modkernel32.NewProc("IsWow64Process2")
|
||||||
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
|
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
|
||||||
procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
|
procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
|
||||||
|
procLoadResource = modkernel32.NewProc("LoadResource")
|
||||||
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
|
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
|
||||||
procLocalFree = modkernel32.NewProc("LocalFree")
|
procLocalFree = modkernel32.NewProc("LocalFree")
|
||||||
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
||||||
|
procLockResource = modkernel32.NewProc("LockResource")
|
||||||
procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
|
procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
|
||||||
procMoveFileExW = modkernel32.NewProc("MoveFileExW")
|
procMoveFileExW = modkernel32.NewProc("MoveFileExW")
|
||||||
procMoveFileW = modkernel32.NewProc("MoveFileW")
|
procMoveFileW = modkernel32.NewProc("MoveFileW")
|
||||||
@@ -326,6 +329,7 @@ var (
|
|||||||
procSetStdHandle = modkernel32.NewProc("SetStdHandle")
|
procSetStdHandle = modkernel32.NewProc("SetStdHandle")
|
||||||
procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW")
|
procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW")
|
||||||
procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW")
|
procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW")
|
||||||
|
procSizeofResource = modkernel32.NewProc("SizeofResource")
|
||||||
procSleepEx = modkernel32.NewProc("SleepEx")
|
procSleepEx = modkernel32.NewProc("SleepEx")
|
||||||
procTerminateJobObject = modkernel32.NewProc("TerminateJobObject")
|
procTerminateJobObject = modkernel32.NewProc("TerminateJobObject")
|
||||||
procTerminateProcess = modkernel32.NewProc("TerminateProcess")
|
procTerminateProcess = modkernel32.NewProc("TerminateProcess")
|
||||||
@@ -1747,6 +1751,15 @@ func FindNextVolume(findVolume Handle, volumeName *uint16, bufferLength uint32)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findResource(module Handle, name uintptr, resType uintptr) (resInfo Handle, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(procFindResourceW.Addr(), 3, uintptr(module), uintptr(name), uintptr(resType))
|
||||||
|
resInfo = Handle(r0)
|
||||||
|
if resInfo == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func FindVolumeClose(findVolume Handle) (err error) {
|
func FindVolumeClose(findVolume Handle) (err error) {
|
||||||
r1, _, e1 := syscall.Syscall(procFindVolumeClose.Addr(), 1, uintptr(findVolume), 0, 0)
|
r1, _, e1 := syscall.Syscall(procFindVolumeClose.Addr(), 1, uintptr(findVolume), 0, 0)
|
||||||
if r1 == 0 {
|
if r1 == 0 {
|
||||||
@@ -2371,6 +2384,15 @@ func _LoadLibrary(libname *uint16) (handle Handle, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadResource(module Handle, resInfo Handle) (resData Handle, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(procLoadResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0)
|
||||||
|
resData = Handle(r0)
|
||||||
|
if resData == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func LocalAlloc(flags uint32, length uint32) (ptr uintptr, err error) {
|
func LocalAlloc(flags uint32, length uint32) (ptr uintptr, err error) {
|
||||||
r0, _, e1 := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(length), 0)
|
r0, _, e1 := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(length), 0)
|
||||||
ptr = uintptr(r0)
|
ptr = uintptr(r0)
|
||||||
@@ -2397,6 +2419,15 @@ func LockFileEx(file Handle, flags uint32, reserved uint32, bytesLow uint32, byt
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LockResource(resData Handle) (addr uintptr, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(procLockResource.Addr(), 1, uintptr(resData), 0, 0)
|
||||||
|
addr = uintptr(r0)
|
||||||
|
if addr == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) {
|
func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) {
|
||||||
r0, _, e1 := syscall.Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
|
r0, _, e1 := syscall.Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
|
||||||
addr = uintptr(r0)
|
addr = uintptr(r0)
|
||||||
@@ -2810,6 +2841,15 @@ func SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err erro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SizeofResource(module Handle, resInfo Handle) (size uint32, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(procSizeofResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0)
|
||||||
|
size = uint32(r0)
|
||||||
|
if size == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func SleepEx(milliseconds uint32, alertable bool) (ret uint32) {
|
func SleepEx(milliseconds uint32, alertable bool) (ret uint32) {
|
||||||
var _p0 uint32
|
var _p0 uint32
|
||||||
if alertable {
|
if alertable {
|
||||||
|
|||||||
Reference in New Issue
Block a user