Add SetupAPI direct device node driver install method to test tool
Method 3 uses SetupDiGetClassDevs + SetupDiEnumDeviceInfo to find the exact device node, then SetupDiBuildDriverInfoList + DIF_SELECTBESTCOMPATDRV + DIF_INSTALLDEVICE to install driver directly on the device, bypassing the catalog signature check that blocks Methods 1 and 2. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
17110a1606
commit
0c45e77911
@ -12,6 +12,66 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
setupapi = syscall.MustLoadDLL("setupapi.dll")
|
||||
newdev = syscall.MustLoadDLL("newdev.dll")
|
||||
|
||||
procSetupDiGetClassDevsW = setupapi.MustFindProc("SetupDiGetClassDevsW")
|
||||
procSetupDiEnumDeviceInfo = setupapi.MustFindProc("SetupDiEnumDeviceInfo")
|
||||
procSetupDiGetDeviceRegistryPropW = setupapi.MustFindProc("SetupDiGetDeviceRegistryPropertyW")
|
||||
procSetupDiSetDeviceRegistryPropW = setupapi.MustFindProc("SetupDiSetDeviceRegistryPropertyW")
|
||||
procSetupDiSetDevInstallParamsW = setupapi.MustFindProc("SetupDiSetDeviceInstallParamsW")
|
||||
procSetupDiGetDevInstallParamsW = setupapi.MustFindProc("SetupDiGetDeviceInstallParamsW")
|
||||
procSetupDiCallClassInstaller = setupapi.MustFindProc("SetupDiCallClassInstaller")
|
||||
procSetupDiDestroyDevInfoList = setupapi.MustFindProc("SetupDiDestroyDeviceInfoList")
|
||||
procSetupDiBuildDriverInfoList = setupapi.MustFindProc("SetupDiBuildDriverInfoList")
|
||||
|
||||
procUpdateDriverForPlugAndPlayDevicesW = newdev.MustFindProc("UpdateDriverForPlugAndPlayDevicesW")
|
||||
procDiInstallDriverW = newdev.MustFindProc("DiInstallDriverW")
|
||||
)
|
||||
|
||||
const (
|
||||
DIGCF_PRESENT = 0x00000002
|
||||
DIGCF_ALLCLASSES = 0x00000004
|
||||
|
||||
SPDRP_HARDWAREID = 0x00000001
|
||||
|
||||
DIF_SELECTBESTCOMPATDRV = 0x00000017
|
||||
DIF_INSTALLDEVICE = 0x00000002
|
||||
|
||||
DI_FLAGSEX_ALLOWEXCLUDEDDRVS = 0x00000800
|
||||
DI_ENUMSINGLEINF = 0x00010000
|
||||
DI_DONOTCALLCONFIGMG = 0x00000002
|
||||
|
||||
INSTALLFLAG_FORCE = 0x00000001
|
||||
DIIRFLAG_FORCE_INF = 0x00000002
|
||||
SPDIT_COMPATDRIVER = 0x00000002
|
||||
|
||||
INVALID_HANDLE_VALUE = ^uintptr(0)
|
||||
)
|
||||
|
||||
// SP_DEVINFO_DATA
|
||||
type SP_DEVINFO_DATA struct {
|
||||
cbSize uint32
|
||||
ClassGuid [16]byte
|
||||
DevInst uint32
|
||||
Reserved uintptr
|
||||
}
|
||||
|
||||
// SP_DEVINSTALL_PARAMS_W (size depends on arch: 584 bytes on amd64)
|
||||
type SP_DEVINSTALL_PARAMS_W struct {
|
||||
cbSize uint32
|
||||
Flags uint32
|
||||
FlagsEx uint32
|
||||
hwndParent uintptr
|
||||
InstallMsgHandler uintptr
|
||||
InstallMsgHandlerContext uintptr
|
||||
FileQueue uintptr
|
||||
ClassInstallReserved uintptr
|
||||
Reserved uint32
|
||||
DriverPath [260]uint16
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Println("Usage: test_driver_install.exe <path-to-inf>")
|
||||
@ -26,7 +86,6 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Hardware ID for Kneron KL520
|
||||
hardwareID := "USB\\VID_3231&PID_0100"
|
||||
|
||||
fmt.Println("")
|
||||
@ -36,34 +95,23 @@ func main() {
|
||||
fmt.Println("")
|
||||
fmt.Println("=== Method 2: DiInstallDriverW ===")
|
||||
tryDiInstallDriver(infPath)
|
||||
|
||||
fmt.Println("")
|
||||
fmt.Println("=== Method 3: SetupAPI direct device node install ===")
|
||||
trySetupAPIInstall(infPath, hardwareID)
|
||||
}
|
||||
|
||||
func tryUpdateDriver(infPath, hardwareID string) {
|
||||
newdev, err := syscall.LoadDLL("newdev.dll")
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: LoadDLL: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer newdev.Release()
|
||||
|
||||
proc, err := newdev.FindProc("UpdateDriverForPlugAndPlayDevicesW")
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: FindProc: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
infUTF16, _ := syscall.UTF16PtrFromString(infPath)
|
||||
hwIDUTF16, _ := syscall.UTF16PtrFromString(hardwareID)
|
||||
|
||||
const INSTALLFLAG_FORCE = 0x00000001
|
||||
var needReboot int32
|
||||
|
||||
fmt.Printf("Hardware ID: %s\n", hardwareID)
|
||||
fmt.Println("Calling UpdateDriverForPlugAndPlayDevicesW...")
|
||||
fmt.Println("(If a Windows Security dialog appears, click 'Install this driver software anyway')")
|
||||
|
||||
ret, _, lastErr := proc.Call(
|
||||
0, // hwndParent = NULL
|
||||
ret, _, lastErr := procUpdateDriverForPlugAndPlayDevicesW.Call(
|
||||
0,
|
||||
uintptr(unsafe.Pointer(hwIDUTF16)),
|
||||
uintptr(unsafe.Pointer(infUTF16)),
|
||||
INSTALLFLAG_FORCE,
|
||||
@ -71,51 +119,176 @@ func tryUpdateDriver(infPath, hardwareID string) {
|
||||
)
|
||||
|
||||
fmt.Printf("Return value: %d\n", ret)
|
||||
fmt.Printf("NeedReboot: %d\n", needReboot)
|
||||
|
||||
if ret == 0 {
|
||||
errno := lastErr.(syscall.Errno)
|
||||
fmt.Printf("FAILED - error: %v (code: %d / 0x%08X)\n", lastErr, uint32(errno), uint32(errno))
|
||||
} else {
|
||||
fmt.Println("SUCCESS - driver installed!")
|
||||
fmt.Println("SUCCESS!")
|
||||
}
|
||||
}
|
||||
|
||||
func tryDiInstallDriver(infPath string) {
|
||||
newdev, err := syscall.LoadDLL("newdev.dll")
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: LoadDLL: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer newdev.Release()
|
||||
|
||||
proc, err := newdev.FindProc("DiInstallDriverW")
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: FindProc: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
infUTF16, _ := syscall.UTF16PtrFromString(infPath)
|
||||
|
||||
const DIIRFLAG_FORCE_INF = 0x00000002
|
||||
var needReboot int32
|
||||
|
||||
fmt.Println("Calling DiInstallDriverW (DIIRFLAG_FORCE_INF)...")
|
||||
fmt.Println("Calling DiInstallDriverW...")
|
||||
|
||||
ret, _, lastErr := proc.Call(
|
||||
0, // hwndParent = NULL
|
||||
ret, _, lastErr := procDiInstallDriverW.Call(
|
||||
0,
|
||||
uintptr(unsafe.Pointer(infUTF16)),
|
||||
DIIRFLAG_FORCE_INF,
|
||||
uintptr(unsafe.Pointer(&needReboot)),
|
||||
)
|
||||
|
||||
fmt.Printf("Return value: %d\n", ret)
|
||||
fmt.Printf("NeedReboot: %d\n", needReboot)
|
||||
|
||||
if ret == 0 {
|
||||
errno := lastErr.(syscall.Errno)
|
||||
fmt.Printf("FAILED - error: %v (code: %d / 0x%08X)\n", lastErr, uint32(errno), uint32(errno))
|
||||
} else {
|
||||
fmt.Println("SUCCESS - driver installed!")
|
||||
fmt.Println("SUCCESS!")
|
||||
}
|
||||
}
|
||||
|
||||
func trySetupAPIInstall(infPath, targetHWID string) {
|
||||
fmt.Println("Enumerating all present USB devices...")
|
||||
|
||||
// Get all present devices
|
||||
hDevInfo, _, err := procSetupDiGetClassDevsW.Call(
|
||||
0, // NULL = all classes
|
||||
0, // no enumerator
|
||||
0, // no hwnd
|
||||
DIGCF_PRESENT|DIGCF_ALLCLASSES,
|
||||
)
|
||||
if hDevInfo == INVALID_HANDLE_VALUE {
|
||||
fmt.Printf("ERROR: SetupDiGetClassDevsW failed: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer procSetupDiDestroyDevInfoList.Call(hDevInfo)
|
||||
|
||||
var devInfoData SP_DEVINFO_DATA
|
||||
devInfoData.cbSize = uint32(unsafe.Sizeof(devInfoData))
|
||||
|
||||
found := false
|
||||
for i := uint32(0); ; i++ {
|
||||
ret, _, _ := procSetupDiEnumDeviceInfo.Call(
|
||||
hDevInfo,
|
||||
uintptr(i),
|
||||
uintptr(unsafe.Pointer(&devInfoData)),
|
||||
)
|
||||
if ret == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Get hardware ID
|
||||
var buf [1024]uint16
|
||||
var dataType, reqSize uint32
|
||||
ret, _, _ = procSetupDiGetDeviceRegistryPropW.Call(
|
||||
hDevInfo,
|
||||
uintptr(unsafe.Pointer(&devInfoData)),
|
||||
SPDRP_HARDWAREID,
|
||||
uintptr(unsafe.Pointer(&dataType)),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(len(buf)*2),
|
||||
uintptr(unsafe.Pointer(&reqSize)),
|
||||
)
|
||||
if ret == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// MULTI_SZ: check each string
|
||||
hwid := syscall.UTF16ToString(buf[:])
|
||||
if hwid == targetHWID {
|
||||
fmt.Printf("FOUND device: %s (DevInst: %d)\n", hwid, devInfoData.DevInst)
|
||||
found = true
|
||||
|
||||
// Now try to install driver on this specific device
|
||||
installOnDevice(hDevInfo, &devInfoData, infPath)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
fmt.Printf("Device with Hardware ID '%s' not found among present devices.\n", targetHWID)
|
||||
}
|
||||
}
|
||||
|
||||
func installOnDevice(hDevInfo uintptr, devInfoData *SP_DEVINFO_DATA, infPath string) {
|
||||
fmt.Println("Setting up driver install params...")
|
||||
|
||||
// Get current install params
|
||||
var installParams SP_DEVINSTALL_PARAMS_W
|
||||
installParams.cbSize = uint32(unsafe.Sizeof(installParams))
|
||||
|
||||
ret, _, err := procSetupDiGetDevInstallParamsW.Call(
|
||||
hDevInfo,
|
||||
uintptr(unsafe.Pointer(devInfoData)),
|
||||
uintptr(unsafe.Pointer(&installParams)),
|
||||
)
|
||||
if ret == 0 {
|
||||
fmt.Printf("ERROR: GetDeviceInstallParams failed: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Current Flags: 0x%08X, FlagsEx: 0x%08X\n", installParams.Flags, installParams.FlagsEx)
|
||||
|
||||
// Set DriverPath to our INF and enable DI_ENUMSINGLEINF
|
||||
infUTF16, _ := syscall.UTF16FromString(infPath)
|
||||
copy(installParams.DriverPath[:], infUTF16)
|
||||
installParams.Flags |= DI_ENUMSINGLEINF
|
||||
installParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS
|
||||
|
||||
ret, _, err = procSetupDiSetDevInstallParamsW.Call(
|
||||
hDevInfo,
|
||||
uintptr(unsafe.Pointer(devInfoData)),
|
||||
uintptr(unsafe.Pointer(&installParams)),
|
||||
)
|
||||
if ret == 0 {
|
||||
fmt.Printf("ERROR: SetDeviceInstallParams failed: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Install params set (DI_ENUMSINGLEINF, DriverPath set)")
|
||||
|
||||
// Build driver info list from our specific INF
|
||||
fmt.Println("Building driver info list from INF...")
|
||||
ret, _, err = procSetupDiBuildDriverInfoList.Call(
|
||||
hDevInfo,
|
||||
uintptr(unsafe.Pointer(devInfoData)),
|
||||
SPDIT_COMPATDRIVER,
|
||||
)
|
||||
if ret == 0 {
|
||||
errno := err.(syscall.Errno)
|
||||
fmt.Printf("ERROR: BuildDriverInfoList failed: %v (code: 0x%08X)\n", err, uint32(errno))
|
||||
return
|
||||
}
|
||||
fmt.Println("Driver info list built.")
|
||||
|
||||
// Select best compatible driver
|
||||
fmt.Println("Selecting best compatible driver...")
|
||||
ret, _, err = procSetupDiCallClassInstaller.Call(
|
||||
DIF_SELECTBESTCOMPATDRV,
|
||||
hDevInfo,
|
||||
uintptr(unsafe.Pointer(devInfoData)),
|
||||
)
|
||||
if ret == 0 {
|
||||
errno := err.(syscall.Errno)
|
||||
fmt.Printf("ERROR: DIF_SELECTBESTCOMPATDRV failed: %v (code: 0x%08X)\n", err, uint32(errno))
|
||||
fmt.Println(" (This might mean the INF is not compatible or catalog issue)")
|
||||
return
|
||||
}
|
||||
fmt.Println("Best compatible driver selected.")
|
||||
|
||||
// Install the device
|
||||
fmt.Println("Installing device with selected driver...")
|
||||
fmt.Println("(If a Windows Security dialog appears, click 'Install this driver software anyway')")
|
||||
ret, _, err = procSetupDiCallClassInstaller.Call(
|
||||
DIF_INSTALLDEVICE,
|
||||
hDevInfo,
|
||||
uintptr(unsafe.Pointer(devInfoData)),
|
||||
)
|
||||
if ret == 0 {
|
||||
errno := err.(syscall.Errno)
|
||||
fmt.Printf("ERROR: DIF_INSTALLDEVICE failed: %v (code: 0x%08X)\n", err, uint32(errno))
|
||||
} else {
|
||||
fmt.Println("SUCCESS - driver installed on device!")
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user