Devcon hwids命令源代码实现 SetupAPI函数实现
2022-01-28
72
0
Devcon hwids命令显示设备的硬件ID信息。主要的显示包括如下:
了解过之前几个命令的同学应该觉地比较简单,因为或多或少有些信息如设备友名,设备实例名路径我们都获取过,而设备的硬件ID和兼容ID其实与是比较简单是,和设备的友名一样,是通过SetupDiGetDeviceRegistryProperty函数的SPDRP_HARDWAREID和SPDRP_COMPATIBLEIDS属性信息获取的。
int cmdHwIds(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[])
/*++
Routine Description:
HWIDS <id> ...
use EnumerateDevices to do hardwareID matching
for each match, dump hw/compat id's to stdout
note that we only enumerate present devices
Arguments:
BaseName - name of executable
Machine - if non-NULL, remote machine
argc/argv - remaining parameters - passed into EnumerateDevices
Return Value:
EXIT_xxxx
--*/
{
GenericContext context;
int failcode;
UNREFERENCED_PARAMETER(Flags);
if(!argc) {
return EXIT_USAGE;
}
context.count = 0;
context.control = FIND_DEVICE | FIND_HWIDS;
failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,FindCallback,&context);
if(failcode == EXIT_OK) {
if(!context.count) {
FormatToStream(stdout,Machine?MSG_FIND_TAIL_NONE:MSG_FIND_TAIL_NONE_LOCAL,Machine);
} else {
FormatToStream(stdout,Machine?MSG_FIND_TAIL:MSG_FIND_TAIL_LOCAL,context.count,Machine);
}
}
return failcode;
}
可以看到,cmdHwIds函数是EnumerateDevices函数实现的。注意这里的DIGCF_PRESENT表示当前正在运行的设备和context.control = FIND_DEVICE | FIND_HWIDS
获取的设备信息。
int EnumerateDevices(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PWSTR* argv, _In_ CallbackFunc Callback, _In_ LPVOID Context)
/*++
Routine Description:
Generic enumerator for devices that will be passed the following arguments:
<id> [<id>...]
=<class> [<id>...]
where <id> can either be @instance-id, or hardware-id and may contain wildcards
<class> is a class name
Arguments:
BaseName - name of executable
Machine - name of machine to enumerate
Flags - extra enumeration flags (eg DIGCF_PRESENT)
argc/argv - remaining arguments on command line
Callback - function to call for each hit
Context - data to pass function for each hit
Return Value:
EXIT_xxxx
--*/
{
HDEVINFO devs = INVALID_HANDLE_VALUE;
IdEntry * templ = NULL;
int failcode = EXIT_FAIL;
int retcode;
int argIndex;
DWORD devIndex;
SP_DEVINFO_DATA devInfo;
SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
BOOL doSearch = FALSE;
BOOL match;
BOOL all = FALSE;
GUID cls;
DWORD numClass = 0;
int skip = 0;
UNREFERENCED_PARAMETER(BaseName);
if(!argc) {
return EXIT_USAGE;
}
templ = new IdEntry[argc];
if(!templ) {
goto final;
}
//
// determine if a class is specified
//
if(argc>skip && argv[skip][0]==CLASS_PREFIX_CHAR && argv[skip][1]) {
if(!SetupDiClassGuidsFromNameEx(argv[skip]+1,&cls,1,&numClass,Machine,NULL) &&
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
goto final;
}
if(!numClass) {
failcode = EXIT_OK;
goto final;
}
skip++;
}
if(argc>skip && argv[skip][0]==WILD_CHAR && !argv[skip][1]) {
//
// catch convinient case of specifying a single argument '*'
//
all = TRUE;
skip++;
} else if(argc<=skip) {
//
// at least one parameter, but no <id>'s
//
all = TRUE;
}
//
// determine if any instance id's were specified
//
// note, if =<class> was specified with no id's
// we'll mark it as not doSearch
// but will go ahead and add them all
//
for(argIndex=skip;argIndex<argc;argIndex++) {
templ[argIndex] = GetIdType(argv[argIndex]);
if(templ[argIndex].Wild || !templ[argIndex].InstanceId) {
//
// anything other than simple InstanceId's require a search
//
doSearch = TRUE;
}
}
if(doSearch || all) {
//
// add all id's to list
// if there's a class, filter on specified class
//
devs = SetupDiGetClassDevsEx(numClass ? &cls : NULL,
NULL,
NULL,
(numClass ? 0 : DIGCF_ALLCLASSES) | Flags,
NULL,
Machine,
NULL);
} else {
//
// blank list, we'll add instance id's by hand
//
devs = SetupDiCreateDeviceInfoListEx(numClass ? &cls : NULL,
NULL,
Machine,
NULL);
}
if(devs == INVALID_HANDLE_VALUE) {
goto final;
}
for(argIndex=skip;argIndex<argc;argIndex++) {
//
// add explicit instances to list (even if enumerated all,
// this gets around DIGCF_PRESENT)
// do this even if wildcards appear to be detected since they
// might actually be part of the instance ID of a non-present device
//
if(templ[argIndex].InstanceId) {
SetupDiOpenDeviceInfo(devs,templ[argIndex].String,NULL,0,NULL);
}
}
devInfoListDetail.cbSize = sizeof(devInfoListDetail);
if(!SetupDiGetDeviceInfoListDetail(devs,&devInfoListDetail)) {
goto final;
}
//
// now enumerate them
//
if(all) {
doSearch = FALSE;
}
devInfo.cbSize = sizeof(devInfo);
for(devIndex=0;SetupDiEnumDeviceInfo(devs,devIndex,&devInfo);devIndex++) {
if(doSearch) {
for(argIndex=skip,match=FALSE;(argIndex<argc) && !match;argIndex++) {
TCHAR devID[MAX_DEVICE_ID_LEN];
LPTSTR *hwIds = NULL;
LPTSTR *compatIds = NULL;
//
// determine instance ID
//
if(CM_Get_Device_ID_Ex(devInfo.DevInst,devID,MAX_DEVICE_ID_LEN,0,devInfoListDetail.RemoteMachineHandle)!=CR_SUCCESS) {
devID[0] = TEXT('\0');
}
if(templ[argIndex].InstanceId) {
//
// match on the instance ID
//
if(WildCardMatch(devID,templ[argIndex])) {
match = TRUE;
}
} else {
//
// determine hardware ID's
// and search for matches
//
hwIds = GetDevMultiSz(devs,&devInfo,SPDRP_HARDWAREID);
compatIds = GetDevMultiSz(devs,&devInfo,SPDRP_COMPATIBLEIDS);
if(WildCompareHwIds(hwIds,templ[argIndex]) ||
WildCompareHwIds(compatIds,templ[argIndex])) {
match = TRUE;
}
}
DelMultiSz(hwIds);
DelMultiSz(compatIds);
}
} else {
match = TRUE;
}
if(match) {
retcode = Callback(devs,&devInfo,devIndex,Context);
if(retcode) {
failcode = retcode;
goto final;
}
}
}
failcode = EXIT_OK;
final:
if(templ) {
delete [] templ;
}
if(devs != INVALID_HANDLE_VALUE) {
SetupDiDestroyDeviceInfoList(devs);
}
return failcode;
}
关键函数代码段,可以看到
{
devID[0] = TEXT('\0');
}
- CM_Get_Device_ID_Ex用于获取设备实例路径名
- hwIds = GetDevMultiSz(devs,&devInfo,SPDRP_HARDWAREID); 用于获取硬件ID
- compatIds = GetDevMultiSz(devs,&devInfo,SPDRP_COMPATIBLEIDS);获取兼容ID
__drv_allocatesMem(object)
LPTSTR * GetDevMultiSz(_In_ HDEVINFO Devs, _In_ PSP_DEVINFO_DATA DevInfo, _In_ DWORD Prop)
/*++
Routine Description:
Get a multi-sz device property
and return as an array of strings
Arguments:
Devs - HDEVINFO containing DevInfo
DevInfo - Specific device
Prop - SPDRP_HARDWAREID or SPDRP_COMPATIBLEIDS
Return Value:
array of strings. last entry+1 of array contains NULL
returns NULL on failure
--*/
{
LPTSTR buffer;
DWORD size;
DWORD reqSize;
DWORD dataType;
LPTSTR * array;
DWORD szChars;
size = 8192; // initial guess, nothing magic about this
buffer = new TCHAR[(size/sizeof(TCHAR))+2];
if(!buffer) {
return NULL;
}
while(!SetupDiGetDeviceRegistryProperty(Devs,DevInfo,Prop,&dataType,(LPBYTE)buffer,size,&reqSize)) {
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
goto failed;
}
if(dataType != REG_MULTI_SZ) {
goto failed;
}
size = reqSize;
delete [] buffer;
buffer = new TCHAR[(size/sizeof(TCHAR))+2];
if(!buffer) {
goto failed;
}
}
szChars = reqSize/sizeof(TCHAR);
buffer[szChars] = TEXT('\0');
buffer[szChars+1] = TEXT('\0');
array = GetMultiSzIndexArray(buffer);
if(array) {
return array;
}
failed:
if(buffer) {
delete [] buffer;
}
return NULL;
}
回调函数
int FindCallback(_In_ HDEVINFO Devs, _In_ PSP_DEVINFO_DATA DevInfo, _In_ DWORD Index, _In_ LPVOID Context)
/*++
Routine Description:
Callback for use by Find/FindAll
just simply display the device
Arguments:
Devs )_ uniquely identify the device
DevInfo )
Index - index of device
Context - GenericContext
Return Value:
EXIT_xxxx
--*/
{
GenericContext *pFindContext = (GenericContext*)Context;
UNREFERENCED_PARAMETER(Index);
if(!pFindContext->control) {
DumpDevice(Devs,DevInfo);
pFindContext->count++;
return EXIT_OK;
}
if(!DumpDeviceWithInfo(Devs,DevInfo,NULL)) {
return EXIT_OK;
}
if(pFindContext->control&FIND_DEVICE) {
DumpDeviceDescr(Devs,DevInfo);
}
if(pFindContext->control&FIND_CLASS) {
DumpDeviceClass(Devs,DevInfo);
}
if(pFindContext->control&FIND_STATUS) {
DumpDeviceStatus(Devs,DevInfo);
}
if(pFindContext->control&FIND_RESOURCES) {
DumpDeviceResources(Devs,DevInfo);
}
if(pFindContext->control&FIND_DRIVERFILES) {
DumpDeviceDriverFiles(Devs,DevInfo);
}
if(pFindContext->control&FIND_STACK) {
DumpDeviceStack(Devs,DevInfo);
}
if(pFindContext->control&FIND_HWIDS) {
DumpDeviceHwIds(Devs,DevInfo);
}
if (pFindContext->control&FIND_DRIVERNODES) {
DumpDeviceDriverNodes(Devs,DevInfo);
}
pFindContext->count++;
return EXIT_OK;
}