mirror of
https://github.com/golang/sys.git
synced 2026-02-08 03:36:03 +03: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 (
|
||||
errorspkg "errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"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 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 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)
|
||||
//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 {
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/pe"
|
||||
"errors"
|
||||
"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)
|
||||
}
|
||||
}
|
||||
|
||||
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_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")
|
||||
procFindNextVolumeMountPointW = modkernel32.NewProc("FindNextVolumeMountPointW")
|
||||
procFindNextVolumeW = modkernel32.NewProc("FindNextVolumeW")
|
||||
procFindResourceW = modkernel32.NewProc("FindResourceW")
|
||||
procFindVolumeClose = modkernel32.NewProc("FindVolumeClose")
|
||||
procFindVolumeMountPointClose = modkernel32.NewProc("FindVolumeMountPointClose")
|
||||
procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
|
||||
@@ -277,9 +278,11 @@ var (
|
||||
procIsWow64Process2 = modkernel32.NewProc("IsWow64Process2")
|
||||
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
|
||||
procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
|
||||
procLoadResource = modkernel32.NewProc("LoadResource")
|
||||
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
|
||||
procLocalFree = modkernel32.NewProc("LocalFree")
|
||||
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
||||
procLockResource = modkernel32.NewProc("LockResource")
|
||||
procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
|
||||
procMoveFileExW = modkernel32.NewProc("MoveFileExW")
|
||||
procMoveFileW = modkernel32.NewProc("MoveFileW")
|
||||
@@ -326,6 +329,7 @@ var (
|
||||
procSetStdHandle = modkernel32.NewProc("SetStdHandle")
|
||||
procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW")
|
||||
procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW")
|
||||
procSizeofResource = modkernel32.NewProc("SizeofResource")
|
||||
procSleepEx = modkernel32.NewProc("SleepEx")
|
||||
procTerminateJobObject = modkernel32.NewProc("TerminateJobObject")
|
||||
procTerminateProcess = modkernel32.NewProc("TerminateProcess")
|
||||
@@ -1747,6 +1751,15 @@ func FindNextVolume(findVolume Handle, volumeName *uint16, bufferLength uint32)
|
||||
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) {
|
||||
r1, _, e1 := syscall.Syscall(procFindVolumeClose.Addr(), 1, uintptr(findVolume), 0, 0)
|
||||
if r1 == 0 {
|
||||
@@ -2371,6 +2384,15 @@ func _LoadLibrary(libname *uint16) (handle Handle, err error) {
|
||||
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) {
|
||||
r0, _, e1 := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(length), 0)
|
||||
ptr = uintptr(r0)
|
||||
@@ -2397,6 +2419,15 @@ func LockFileEx(file Handle, flags uint32, reserved uint32, bytesLow uint32, byt
|
||||
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) {
|
||||
r0, _, e1 := syscall.Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
|
||||
addr = uintptr(r0)
|
||||
@@ -2810,6 +2841,15 @@ func SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err erro
|
||||
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) {
|
||||
var _p0 uint32
|
||||
if alertable {
|
||||
|
||||
Reference in New Issue
Block a user