You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1051 lines
36 KiB
1051 lines
36 KiB
// vchk.cpp : Defines the entry point for the console application.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#pragma hdrstop
|
|
|
|
#include "vchk.h"
|
|
#include "allowed.h"
|
|
#include "ilimpchk.h"
|
|
|
|
//#include <devguid.h>
|
|
#include <setupapi.h>
|
|
//#include <regstr.h>
|
|
#include <cfgmgr32.h>
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//#define VCHK_TRACE_ON 1
|
|
|
|
#ifdef VCHK_TRACE_ON
|
|
const char* VchkTraceGetName(const char* szName)
|
|
{
|
|
const char* szLastSeg = szName;
|
|
const char* szSlash = strchr(szName, '\\');
|
|
while (szSlash) {
|
|
++szSlash;
|
|
szLastSeg = szSlash;
|
|
szSlash = strchr(szSlash, '\\');
|
|
}
|
|
return szLastSeg;
|
|
}
|
|
#define VCHK_TRACE(x) {cerr << " [" << VchkTraceGetName(__FILE__) << ":" << __LINE__ << "] " << x;}
|
|
#else
|
|
#define VCHK_TRACE(x)
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Enumerates display devices
|
|
|
|
typedef class CDisplayDeviceEnum {
|
|
public:
|
|
|
|
static bool IsDigitsOnly(const char* sz);
|
|
|
|
CDisplayDeviceEnum();
|
|
~CDisplayDeviceEnum() {free(Buffer);}
|
|
|
|
bool IsValid() const {return bValid;}
|
|
bool Next();
|
|
|
|
CString GetMiniportPath();
|
|
|
|
DWORD GetDeviceId() {return iEnum;}
|
|
|
|
DWORD GetLastError() {return dwLastError;}
|
|
const char* GetLastErrorStr() {return szLastError;}
|
|
|
|
void MarkDevice(DISPLAY_DEVICE& r_DisplayDevice);
|
|
void UnmarkDevice();
|
|
bool IsMarkedDevice();
|
|
|
|
private:
|
|
static const GUID const displayClassGUID;
|
|
|
|
BYTE* Buffer;
|
|
size_t BufferSize;
|
|
bool bValid;
|
|
|
|
DWORD iEnum;
|
|
HDEVINFO hDevInfo;
|
|
SP_DEVINFO_DATA DeviceInfoData;
|
|
HKEY hMarkedKey;
|
|
|
|
DWORD dwLastError;
|
|
const char* szLastError;
|
|
|
|
bool ReallocBuffer(size_t NewSize)
|
|
{
|
|
if (NewSize > BufferSize) {
|
|
void* p = realloc(Buffer, NewSize);
|
|
if (!p) return false;
|
|
|
|
Buffer = (PBYTE)p;
|
|
BufferSize = NewSize;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MarkKey(HKEY hKey);
|
|
void UnmarkKey();
|
|
bool IsMarkedDEVINST(DEVINST DevInst);
|
|
|
|
} typedef_CDisplayDeviceEnum;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum implementation
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum::IsDigitsOnly
|
|
|
|
bool CDisplayDeviceEnum::IsDigitsOnly(const char* sz)
|
|
{
|
|
if (!sz || !*sz) return false;
|
|
while (('0' <= *sz) && (*sz <= '9')) ++sz;
|
|
return !*sz;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum constants
|
|
|
|
const GUID const CDisplayDeviceEnum::displayClassGUID =
|
|
{0x4d36e968L, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum constructor
|
|
|
|
CDisplayDeviceEnum::CDisplayDeviceEnum() :
|
|
|
|
bValid(true),
|
|
Buffer(NULL),
|
|
BufferSize(0),
|
|
iEnum(0),
|
|
hDevInfo(INVALID_HANDLE_VALUE),
|
|
hMarkedKey(NULL),
|
|
dwLastError(0),
|
|
szLastError(NULL)
|
|
|
|
{
|
|
ZeroMemory(&DeviceInfoData, sizeof(DeviceInfoData));
|
|
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
|
|
|
|
ReallocBuffer(MAX_PATH + 1);
|
|
|
|
// Get Device Info Set for display class GUID
|
|
hDevInfo = SetupDiGetClassDevs(&displayClassGUID, // class guid
|
|
NULL, // Enumerator
|
|
NULL, // top level window
|
|
DIGCF_PRESENT);
|
|
if (hDevInfo != INVALID_HANDLE_VALUE) {
|
|
Next();
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
szLastError = "SetupDiGetClassDevs failure";
|
|
bValid = false;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum::Next() - gets next device into scope
|
|
|
|
bool CDisplayDeviceEnum::Next()
|
|
{
|
|
if (!bValid) return false;
|
|
|
|
// get device info for the device in the Device Info Set at index iEnum
|
|
if (SetupDiEnumDeviceInfo(hDevInfo, // device info set
|
|
iEnum, // member index
|
|
&DeviceInfoData)) // Device Info data
|
|
{
|
|
++iEnum;
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
szLastError = "SetupDiEnumDeviceInfo failure";
|
|
bValid = false;
|
|
}
|
|
|
|
return bValid;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum::GetMiniportPath() - gets miniport of current device
|
|
|
|
CString CDisplayDeviceEnum::GetMiniportPath()
|
|
{
|
|
DWORD BufferSizeNeeded = BufferSize;
|
|
DWORD DataT;
|
|
|
|
// Get Registry Information for the Device
|
|
// First time through is to find out how much memory we need to allocate.
|
|
// Second time actually gives us the information we want.
|
|
while (!SetupDiGetDeviceRegistryProperty(hDevInfo, // device info set
|
|
&DeviceInfoData, // info for the device we want to retrieve
|
|
SPDRP_SERVICE, // Specify that we want the service name
|
|
&DataT,
|
|
Buffer, // this should return the service name
|
|
BufferSizeNeeded,
|
|
&BufferSizeNeeded))
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
if (dwError == ERROR_INSUFFICIENT_BUFFER) {
|
|
if (ReallocBuffer(BufferSizeNeeded)) continue;
|
|
szLastError = "Not enough memory";
|
|
} else {
|
|
szLastError = "SetupDiGetDeviceRegistryProperty failure";
|
|
}
|
|
dwLastError = dwError;
|
|
bValid = false;
|
|
|
|
return CString();
|
|
}
|
|
|
|
// get miniport path
|
|
CString sRegPath("System\\CurrentControlSet\\Services\\");
|
|
sRegPath += (LPCSTR)Buffer;
|
|
|
|
// open the services key, find the service, and get the image path
|
|
HKEY hkService;
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
(LPCSTR)sRegPath,
|
|
0,
|
|
KEY_READ,
|
|
&hkService) != ERROR_SUCCESS)
|
|
{
|
|
dwLastError = GetLastError();
|
|
szLastError = "RegOpenKeyEx failure";
|
|
bValid = false;
|
|
return CString();
|
|
}
|
|
|
|
if (!ReallocBuffer(MAX_PATH)) {
|
|
dwLastError = -1;
|
|
szLastError = "Not enough memory";
|
|
bValid = false;
|
|
return CString();
|
|
}
|
|
|
|
DWORD cb = BufferSize;
|
|
ZeroMemory(Buffer, cb);
|
|
|
|
if (RegQueryValueEx(hkService,
|
|
"ImagePath",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)Buffer,
|
|
&cb) != ERROR_SUCCESS)
|
|
{
|
|
dwLastError = GetLastError();
|
|
szLastError = "RegQueryValueEx failure";
|
|
bValid = false;
|
|
return CString();
|
|
}
|
|
|
|
return CString((const char*)Buffer);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum::MarkDevice(DISPLAY_DEVICE&)
|
|
//
|
|
// XXX olegk (it is really XXX level of hack)
|
|
// we will mark the child monitor subkey and than will be searching for
|
|
// children with marked keys later in IsMarkedDevice()
|
|
//
|
|
|
|
void CDisplayDeviceEnum::MarkDevice(DISPLAY_DEVICE& r_DisplayDevice)
|
|
{
|
|
if (hMarkedKey) UnmarkDevice();
|
|
|
|
VCHK_TRACE("-------- Marking Device ----------\n");
|
|
VCHK_TRACE("ID : " << r_DisplayDevice.DeviceID << endl);
|
|
VCHK_TRACE("Key : " << r_DisplayDevice.DeviceKey << endl);
|
|
VCHK_TRACE("Name : " << r_DisplayDevice.DeviceName << endl);
|
|
VCHK_TRACE("String : " << r_DisplayDevice.DeviceString << endl);
|
|
|
|
DISPLAY_DEVICE MonitorInfo;
|
|
MonitorInfo.cb = sizeof(MonitorInfo);
|
|
if (!EnumDisplayDevices(r_DisplayDevice.DeviceName, 0, &MonitorInfo, 0)) {
|
|
VCHK_TRACE("Can't get monitor info for " <<
|
|
r_DisplayDevice.DeviceString << ' ' <<
|
|
r_DisplayDevice.DeviceName << endl);
|
|
return;
|
|
}
|
|
|
|
CString sKey;
|
|
|
|
// XXX olegk - Assume that all device keys are under HKEY_LOCAL_MACHINE
|
|
{
|
|
const CHAR szMachineRegPath[] = "\\REGISTRY\\Machine\\";
|
|
|
|
if (_strnicmp(szMachineRegPath,
|
|
MonitorInfo.DeviceKey,
|
|
sizeof(szMachineRegPath) - 1))
|
|
{
|
|
dwLastError = DWORD(-1);
|
|
szLastError = "Invalid registry path (must be under HKEY_LOCAL_MACHINE)";
|
|
|
|
VCHK_TRACE("Invalid registry path " << MonitorInfo.DeviceKey << endl);
|
|
return;
|
|
}
|
|
sKey = (LPCSTR)(MonitorInfo.DeviceKey) + sizeof(szMachineRegPath) - 1;
|
|
}
|
|
|
|
HKEY hKey;
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
(LPCSTR)sKey,
|
|
0,
|
|
KEY_READ,
|
|
&hKey) != ERROR_SUCCESS)
|
|
{
|
|
// Do nothing - no service will be found
|
|
DWORD dwError = GetLastError();
|
|
VCHK_TRACE("RegOpenKeyEx failure " << dwError << " : " << r_DisplayDevice.DeviceKey << endl);
|
|
return;
|
|
}
|
|
|
|
VCHK_TRACE("Marked Key: " << (LPCSTR)sKey << endl);
|
|
MarkKey(hKey);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum::UnmarkDevice(DISPLAY_DEVICE&)
|
|
|
|
void CDisplayDeviceEnum::UnmarkDevice()
|
|
{
|
|
UnmarkKey();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum::IsMarkedDevice()
|
|
|
|
bool CDisplayDeviceEnum::IsMarkedDevice()
|
|
{
|
|
const size_t nMaxLevel = 10; // XXX olegk - I can't imagine more than 3 but...
|
|
DEVINST DevInstStack[nMaxLevel];
|
|
size_t nLevel = 0;
|
|
|
|
if (CM_Get_Child(&DevInstStack[nLevel], DeviceInfoData.DevInst, 0) != CR_SUCCESS) return false;
|
|
|
|
while (!IsMarkedDEVINST(DevInstStack[nLevel])) {
|
|
if ((nLevel < nMaxLevel) &&
|
|
(CM_Get_Child(&DevInstStack[nLevel + 1],
|
|
DevInstStack[nLevel],
|
|
0) == CR_SUCCESS))
|
|
{
|
|
++nLevel;
|
|
continue;
|
|
}
|
|
while (CM_Get_Sibling(&DevInstStack[nLevel], DevInstStack[nLevel], 0) != CR_SUCCESS) {
|
|
if (!nLevel) return false; // End of search (no marker have been found)
|
|
--nLevel;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum::MarkKey(...)
|
|
|
|
void CDisplayDeviceEnum::MarkKey(HKEY hKey)
|
|
{
|
|
UnmarkKey();
|
|
hMarkedKey = hKey;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum::UnmarkKey(...)
|
|
|
|
void CDisplayDeviceEnum::UnmarkKey()
|
|
{
|
|
if (!hMarkedKey) return;
|
|
RegCloseKey(hMarkedKey);
|
|
hMarkedKey = NULL;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDisplayDeviceEnum::IsMarkedDEVINST(...)
|
|
|
|
bool CDisplayDeviceEnum::IsMarkedDEVINST(DEVINST DevInst)
|
|
{
|
|
bool bIsMarked = false;
|
|
|
|
HKEY hKey;
|
|
if (CM_Open_DevNode_Key(DevInst,
|
|
KEY_READ, // IN REGSAM samDesired,
|
|
0, // IN ULONG ulHardwareProfile,
|
|
RegDisposition_OpenExisting,
|
|
&hKey, //OUT PHKEY phkDevice,
|
|
CM_REGISTRY_SOFTWARE) == CR_SUCCESS)
|
|
{
|
|
extern bool IsTheSameRegKey(HKEY, HKEY);
|
|
bIsMarked = IsTheSameRegKey(hMarkedKey, hKey);
|
|
RegCloseKey(hKey);
|
|
}
|
|
return bIsMarked;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// The one and only application object
|
|
|
|
void
|
|
CDrvchkApp::PrintOut (LPCSTR str)
|
|
{
|
|
if (m_logf)
|
|
fprintf (m_logf, "%s", str);
|
|
else
|
|
cerr << str;
|
|
}
|
|
|
|
void
|
|
CDrvchkApp::PrintOut (unsigned num)
|
|
{
|
|
if (m_logf)
|
|
fprintf (m_logf, "%u", num);
|
|
else
|
|
cerr << num;
|
|
}
|
|
|
|
inline
|
|
void
|
|
CDrvchkApp::ListOut (LPCSTR str)
|
|
{
|
|
if (m_listf)
|
|
fprintf (m_listf, "%s", str);
|
|
}
|
|
|
|
void
|
|
CDrvchkApp::ListOut (unsigned num)
|
|
{
|
|
if (m_listf)
|
|
fprintf (m_listf, "%u", num);
|
|
}
|
|
|
|
ModulesAndImports allowed_modules;
|
|
ModulesAndImports allowed_imports;
|
|
ModulesAndImports known_illegal;
|
|
ModulesAndImports illegal_msgs;
|
|
|
|
void SetCurrentModule(const char* szModule)
|
|
{
|
|
allowed_imports.SetModule(szModule);
|
|
illegal_msgs.SetModule(szModule);
|
|
known_illegal.SetModule(szModule);
|
|
}
|
|
|
|
#define VCHK_WARN known_illegal.AddImport
|
|
#define VCHK_FAIL illegal_msgs.AddImport
|
|
#define VCHK_ALLOW allowed_imports.AddImport
|
|
|
|
void BuildInAllowedAndIllegal (void)
|
|
{
|
|
SetCurrentModule("HAL.DLL");
|
|
|
|
VCHK_FAIL ("HalAllocateCommonBuffer", "use VideoPortAllocateCommonBuffer");
|
|
VCHK_FAIL ("HalFreeCommonBuffer", "use VideoPortFreeCommonBuffer");
|
|
VCHK_WARN ("HalGetAdapter", "obsolete; see DDK manual");
|
|
VCHK_WARN ("HalGetBusData", "obsolete; see DDK manual");
|
|
VCHK_WARN ("HalGetBusDataByOffset");
|
|
VCHK_WARN ("HalSetBusData", "obsolete; see DDK manual");
|
|
VCHK_WARN ("HalSetBusDataByOffset");
|
|
VCHK_WARN ("HalTranslateBusAddress");
|
|
VCHK_FAIL ("KeGetCurrentIrql", "use VideoPortGetCurrentIrql");
|
|
VCHK_FAIL ("KeQueryPerformanceCounter", "use VideoPortQueryPerformanceCounter");
|
|
VCHK_FAIL ("KfAcquireSpinLock", "use VideoPortAcquireSpinLock");
|
|
VCHK_FAIL ("KfReleaseSpinLock", "use VideoPortReleaseSpinLock");
|
|
VCHK_FAIL ("READ_PORT_ULONG", "use VideoPortReadPortUlong");
|
|
VCHK_FAIL ("WRITE_PORT_ULONG", "use VideoPortWritePortUlong");
|
|
|
|
SetCurrentModule ("NTOSKRNL.EXE");
|
|
|
|
VCHK_ALLOW ("_except_handler3");
|
|
VCHK_FAIL ("ExAllocatePool", "use VideoPortAllocatePool");
|
|
VCHK_FAIL ("ExAllocatePoolWithTag", "use VideoPortAllocatePool");
|
|
VCHK_FAIL ("ExFreePool", "use VideoPortFreePool");
|
|
VCHK_FAIL ("ExFreePoolWithTag", "use VideoPortFreePool");
|
|
VCHK_WARN ("ExIsProcessorFeaturePresent");
|
|
VCHK_WARN ("ExQueueWorkItem");
|
|
VCHK_WARN ("IoAllocateMdl");
|
|
VCHK_WARN ("IoCreateNotificationEvent");
|
|
VCHK_WARN ("IoCreateSynchronizationEvent");
|
|
VCHK_WARN ("IoFreeMdl");
|
|
VCHK_WARN ("IoGetCurrentProcess");
|
|
VCHK_FAIL ("IoReportDetectedDevice");
|
|
VCHK_FAIL ("IoReportResourceForDetection");
|
|
VCHK_WARN ("KeCancelTimer");
|
|
VCHK_FAIL ("KeClearEvent", "use VideoPortClearEvent");
|
|
VCHK_FAIL ("KeDelayExecutionThread", "use VideoPortStallExecution");
|
|
VCHK_FAIL ("KeInitializeDpc", "use VideoPortQueueDpc");
|
|
VCHK_FAIL ("KeInitializeSpinLock", "use VideoPortXxxSpinLockXxx");
|
|
VCHK_WARN ("KeInitializeTimer");
|
|
VCHK_WARN ("KeInitializeTimerEx");
|
|
VCHK_FAIL ("KeInsertQueueDpc", "use VideoPortQueueDpc");
|
|
VCHK_WARN ("KeQuerySystemTime");
|
|
VCHK_WARN ("KeRestoreFloatingPointState");
|
|
VCHK_WARN ("KeSaveFloatingPointState");
|
|
VCHK_FAIL ("KeSetEvent", "use VideoPortSetEvent");
|
|
VCHK_WARN ("KeSetTimer");
|
|
VCHK_WARN ("KeSetTimerEx");
|
|
VCHK_FAIL ("MmAllocateContiguousMemory", "use VideoPortAllocateContiguousMemory");
|
|
VCHK_WARN ("MmAllocateNonCachedMemory");
|
|
VCHK_WARN ("MmBuildMdlForNonPagedPool");
|
|
VCHK_WARN ("MmFreeContiguousMemory");
|
|
VCHK_WARN ("MmFreeNonCachedMemory");
|
|
VCHK_WARN ("MmGetPhysicalAddress");
|
|
VCHK_WARN ("MmIsAddressValid");
|
|
VCHK_WARN ("MmMapIoSpace");
|
|
VCHK_WARN ("MmMapLockedPages");
|
|
VCHK_WARN ("MmMapLockedPagesSpecifyCache");
|
|
VCHK_WARN ("MmProbeAndLockPages");
|
|
VCHK_WARN ("MmQuerySystemSize");
|
|
VCHK_WARN ("MmUnlockPages");
|
|
VCHK_WARN ("MmUnmapIoSpace");
|
|
VCHK_WARN ("MmUnmapLockedPages");
|
|
VCHK_WARN ("ObReferenceObjectByHandle");
|
|
VCHK_WARN ("PsGetCurrentProcessId");
|
|
VCHK_WARN ("PsGetVersion");
|
|
VCHK_FAIL ("READ_REGISTER_UCHAR", "use VideoPortReadRegisterUchar");
|
|
VCHK_WARN ("RtlAnsiStringToUnicodeString");
|
|
VCHK_WARN ("RtlAppendUnicodeStringToString");
|
|
VCHK_WARN ("RtlCheckRegistryKey");
|
|
VCHK_WARN ("RtlCompareMemory");
|
|
VCHK_WARN ("RtlCopyUnicodeString");
|
|
VCHK_WARN ("RtlCreateRegistryKey");
|
|
VCHK_WARN ("RtlFreeAnsiString");
|
|
VCHK_WARN ("RtlFreeUnicodeString");
|
|
VCHK_WARN ("RtlInitAnsiString");
|
|
VCHK_WARN ("RtlInitUnicodeString");
|
|
VCHK_WARN ("RtlIntegerToUnicodeString");
|
|
VCHK_WARN ("RtlQueryRegistryValues");
|
|
VCHK_WARN ("RtlTimeToTimeFields");
|
|
VCHK_WARN ("RtlUnicodeStringToAnsiString");
|
|
VCHK_WARN ("RtlUnicodeToMultiByteN");
|
|
VCHK_WARN ("RtlUnwind");
|
|
VCHK_WARN ("RtlWriteRegistryValue");
|
|
VCHK_FAIL ("wcslen", "link to libcntpr.lib instead");
|
|
VCHK_FAIL ("WRITE_REGISTER_UCHAR", "use VideoPortWriteRegisterUchar");
|
|
VCHK_FAIL ("WRITE_REGISTER_USHORT", "use VideoPortWriteRegisterUshort");
|
|
VCHK_WARN ("ZwClose");
|
|
VCHK_WARN ("ZwCreateFile");
|
|
VCHK_WARN ("ZwEnumerateValueKey");
|
|
VCHK_WARN ("ZwMapViewOfSection");
|
|
VCHK_WARN ("ZwOpenKey");
|
|
VCHK_WARN ("ZwOpenSection");
|
|
VCHK_WARN ("ZwQueryValueKey");
|
|
VCHK_WARN ("ZwSetSystemInformation");
|
|
VCHK_WARN ("ZwUnmapViewOfSection");
|
|
VCHK_WARN ("ZwWriteFile");
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// main
|
|
|
|
int __cdecl _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
|
|
{
|
|
int nRetCode = 0;
|
|
|
|
// initialize MFC and print and error on failure
|
|
if (AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
|
|
{
|
|
CDrvchkApp theApp;
|
|
theApp.InitInstance ();
|
|
}
|
|
|
|
return nRetCode;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDrvchkApp construction
|
|
|
|
CDrvchkApp::CDrvchkApp() :
|
|
m_logf(NULL),
|
|
m_listf(NULL),
|
|
m_drv_name ("")
|
|
{
|
|
// TODO: add construction code here,
|
|
// Place all significant initialization in InitInstance
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// The one and only CDrvchkApp object
|
|
|
|
void
|
|
CommandLine::ParseParam( LPCTSTR lpszParam, BOOL bFlag, BOOL bLast )
|
|
{
|
|
|
|
if (m_parse_error != parseOK)
|
|
return;
|
|
|
|
CString param (lpszParam);
|
|
|
|
if (bFlag) {
|
|
|
|
param.MakeUpper();
|
|
|
|
if ((param==CString("?")) || (param == CString("HELP")) || (param == CString("H"))) {
|
|
|
|
m_parse_error = parseHelp;
|
|
|
|
} else if ((param==CString("?IMP")) || (param==CString("IMP?"))) {
|
|
|
|
m_parse_error = parseHelpImports;
|
|
|
|
} else if (m_last_flag.GetLength() && m_first_param) {
|
|
|
|
m_parse_error = parseError;
|
|
m_error_msg = CString("Flag ") + m_last_flag + CString(" requires a parameter.");
|
|
|
|
} else if ((param==CString("LOG")) || (param==CString("DRV")) || (param==CString("MON")) ||
|
|
(param==CString("LIST")) || (param==CString("LST")) || (param==CString("LS")) ||
|
|
(param==CString("LIS")) || (param==CString("ALLOW"))) {
|
|
|
|
if (bLast) {
|
|
m_parse_error = parseError;
|
|
m_error_msg = CString("Flag ") + param + CString(" requires a parameter.");
|
|
} else {
|
|
m_last_flag = param;
|
|
m_first_param = TRUE;
|
|
}
|
|
|
|
} else {
|
|
|
|
m_last_flag = CString();
|
|
m_parse_error = parseError;
|
|
m_error_msg = CString("Invalid flag: ") + param;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (m_last_flag==CString("ALLOW")) {
|
|
m_first_param = FALSE;
|
|
int nSplit = param.Find('!');
|
|
if (nSplit != -1) {
|
|
CString module = param.Left(nSplit);
|
|
CString import = param.Mid(nSplit + 1);
|
|
|
|
if (module.GetLength() && import.GetLength()) {
|
|
allowed_imports.SetModule(module);
|
|
allowed_imports.AddImport(import, "allowed by command line");
|
|
} else {
|
|
m_parse_error = parseError;
|
|
m_error_msg = CString("Bad parameter format for flag: ") + m_last_flag;
|
|
}
|
|
} else {
|
|
allowed_modules.SetModule(param);
|
|
}
|
|
} else if (m_last_flag==CString("DRV")) {
|
|
if (m_monitor >= 1) {
|
|
m_error_msg = "bad command line: Conflicting flags MON and DRV";
|
|
m_parse_error = parseError;
|
|
}
|
|
m_drv_fname = param;
|
|
m_last_flag="";
|
|
} else if (m_last_flag==CString("LOG")) {
|
|
m_log_fname = param;
|
|
m_last_flag="";
|
|
} else if (m_last_flag==CString("LIST") ||
|
|
m_last_flag==CString("LST") ||
|
|
m_last_flag==CString("LIS") ||
|
|
m_last_flag==CString("LS")) {
|
|
m_list_fname = param;
|
|
m_last_flag="";
|
|
} else if (m_last_flag==CString("MON")) {
|
|
if ((param.GetLength()==1) &&
|
|
(((LPCSTR)param)[0] >= '1') &&
|
|
(((LPCSTR)param)[0] <= '9'))
|
|
{
|
|
if (m_drv_fname.GetLength()) {
|
|
m_error_msg = "bad command line: Conflicting flags MON and DRV";
|
|
m_parse_error = parseError;
|
|
}
|
|
char c = ((LPCSTR)param)[0];
|
|
m_monitor = c - '0';
|
|
} else {
|
|
m_error_msg = "bad command line: MON flag has invalid parameter";
|
|
m_parse_error = parseError;
|
|
}
|
|
m_last_flag="";
|
|
} else {
|
|
m_parse_error = parseError;
|
|
m_error_msg = CString("Wrong parameter: ") + param;
|
|
m_last_flag="";
|
|
}
|
|
}
|
|
|
|
if (bLast) {
|
|
if (m_last_flag==CString("LOG") || m_last_flag==CString("DRV")) {
|
|
m_parse_error = parseError;
|
|
m_error_msg = CString("Flag ") + m_last_flag + CString(" requires a parameter.");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDrvchkApp initialization
|
|
|
|
const char* szHelp =
|
|
"Copyright (C) Microsoft Corporation. All rights reserved.\n"
|
|
"\n"
|
|
"usage: vchk [-?] [-LOG logfile] [-DRV drvname | -MON id] [-LIST listname]\n"
|
|
" [-ALLOW module[!import] [module[!import]] ...]\n"
|
|
"\n"
|
|
"where: -? displays this help\n"
|
|
" -IMP? dumps imports tables that check performed against\n"
|
|
" -LOG specifies output file name (if file already exists then new data\n"
|
|
" will be appended to it)\n"
|
|
" -DRV specifies the full name of the driver's binary to check\n"
|
|
" -MON specifies 1-based numeric id of the display adapter to check\n"
|
|
" -LIST specifies the file for summary (if file already exists then new\n"
|
|
" data will be appended to it)\n"
|
|
" -ALLOW specifies allowed imports\n"
|
|
" module: name of allowed module (if no import specified then all\n"
|
|
" imports from the module will be allowed)\n"
|
|
" import: specific import name\n"
|
|
"\n"
|
|
" if neither -MON nor -DRV switches used then all currently active video\n"
|
|
" drivers will be checked\n"
|
|
"\n"
|
|
"Example:\n"
|
|
" vchk -log c:\\log.out -list con -allow HAL.DLL!HalGetBusData VIDEOPORT.SYS\n";
|
|
|
|
BOOL CDrvchkApp::InitInstance()
|
|
{
|
|
// Standard initialization
|
|
// If you are not using these features and wish to reduce the size
|
|
|
|
m_os_ver_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx (&m_os_ver_info);
|
|
if (m_os_ver_info.dwPlatformId != VER_PLATFORM_WIN32_NT) { // doesn't work on Win9x
|
|
PrintOut ("warning: unsupported OS (Win9x), nothing done.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
//if (m_os_ver_info.dwMajorVersion != 5) { // doesn't work on NT version prior to Win2K
|
|
if (m_os_ver_info.dwMajorVersion < 5) { // XXX olegk - will it work in the future????
|
|
PrintOut ("warning: unsupported OS (");
|
|
PrintOut (m_os_ver_info.dwMajorVersion);
|
|
PrintOut (".");
|
|
PrintOut (m_os_ver_info.dwMinorVersion);
|
|
PrintOut ("): nothing done.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
ParseCommandLine (m_cmd_line);
|
|
BuildInAllowedAndIllegal();
|
|
|
|
if (m_cmd_line.m_log_fname.GetLength()) {
|
|
m_logf = fopen (m_cmd_line.m_log_fname, "a+");
|
|
if (!m_logf) m_logf = fopen (m_cmd_line.m_log_fname, "a");
|
|
}
|
|
|
|
if (m_cmd_line.m_list_fname.GetLength()) {
|
|
m_listf = fopen (m_cmd_line.m_list_fname, "a+");
|
|
if (!m_listf) m_listf = fopen (m_cmd_line.m_list_fname, "a");
|
|
}
|
|
|
|
switch (m_cmd_line.m_parse_error) {
|
|
case CommandLine::parseOK: {
|
|
int device_num = m_cmd_line.m_monitor;
|
|
|
|
if (m_cmd_line.m_drv_fname.GetLength()) {
|
|
|
|
ChkDriver (m_cmd_line.m_drv_fname);
|
|
|
|
} else {
|
|
DWORD cbData = 0;
|
|
DEVMODE dmCurrent;
|
|
TCHAR szDeviceDescription[10000];
|
|
TCHAR szImagePath[MAX_PATH + 1];
|
|
TCHAR szVarImagePath[MAX_PATH + 1];
|
|
TCHAR szExpImagePath[MAX_PATH + 1];
|
|
DISPLAY_DEVICE DisplayDevice, *pDisplayDevice = NULL;
|
|
|
|
CString dev_desc_CtrlSet;
|
|
|
|
|
|
int nNonMirroringDevice = 0;
|
|
|
|
//
|
|
// Find non mirroring display device #device_num if needed
|
|
//
|
|
if (device_num >= 1) {
|
|
ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
|
|
DisplayDevice.cb = sizeof(DisplayDevice);
|
|
DWORD i, nNonMirrorDev;
|
|
|
|
for (i = 0, nNonMirrorDev = 0; EnumDisplayDevices(NULL, i, &DisplayDevice, 0); ++i) {
|
|
if (DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue; // skip mirroring drivers
|
|
if (device_num == ++nNonMirroringDevice) {
|
|
pDisplayDevice = &DisplayDevice;
|
|
break;
|
|
}
|
|
}
|
|
if (!pDisplayDevice) {
|
|
PrintOut ("error: cannot find video service\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Let's find all the video drivers that are installed in the system
|
|
//
|
|
CDisplayDeviceEnum DevEnum;
|
|
bool bDevFound = false;
|
|
|
|
if (pDisplayDevice) DevEnum.MarkDevice(*pDisplayDevice);
|
|
|
|
while (DevEnum.IsValid()) {
|
|
if (!pDisplayDevice || DevEnum.IsMarkedDevice()) {
|
|
|
|
bDevFound = true;
|
|
|
|
CString sMiniportPath = DevEnum.GetMiniportPath();
|
|
if (!sMiniportPath.GetLength()) {
|
|
sprintf (szDeviceDescription, "error: cannot find video service #%d\n", DevEnum.GetDeviceId());
|
|
PrintOut (szDeviceDescription);
|
|
VCHK_TRACE("error: " << szDeviceDescription <<
|
|
"\n " << DevEnum.GetLastError() << " " << DevEnum.GetLastErrorStr() << endl)
|
|
|
|
break;
|
|
}
|
|
|
|
sprintf (szVarImagePath, "%%WINDIR%%\\%s", (LPCSTR)sMiniportPath);
|
|
ExpandEnvironmentStrings (szVarImagePath, szExpImagePath, MAX_PATH);
|
|
VCHK_TRACE("Checking miniport " << szExpImagePath << endl)
|
|
ChkDriver (szExpImagePath);
|
|
}
|
|
|
|
DevEnum.Next();
|
|
}
|
|
|
|
if (!bDevFound) PrintOut ("error: cannot find video service\n");
|
|
} // look for system drivers
|
|
} // parseOK
|
|
break;
|
|
|
|
case CommandLine::parseHelp: {
|
|
CString Filename, Version, Description, Copyright;
|
|
{
|
|
CHAR szModuleName[MAX_PATH + 1];
|
|
ZeroMemory(szModuleName, sizeof(szModuleName));
|
|
|
|
if (GetModuleFileName(m_hInstance, szModuleName, MAX_PATH)) {
|
|
DWORD dw = 0;
|
|
DWORD dwVerLen = GetFileVersionInfoSize(szModuleName, &dw);
|
|
|
|
if (dwVerLen) {
|
|
PBYTE Buffer = (PBYTE)malloc(dwVerLen + 1);
|
|
PVOID pValue;
|
|
if (Buffer &&
|
|
GetFileVersionInfo(szModuleName, dw, dwVerLen, Buffer))
|
|
{
|
|
UINT ValLen;
|
|
if (VerQueryValue(Buffer, "\\StringFileInfo\\000004B0\\OriginalFilename", &pValue, &ValLen)); {
|
|
Filename = CString((LPCSTR)pValue, ValLen);
|
|
}
|
|
if (VerQueryValue(Buffer, "\\StringFileInfo\\000004b0\\ProductVersion", &pValue, &ValLen));
|
|
Version = CString((LPCSTR)pValue, ValLen);
|
|
if (VerQueryValue(Buffer, "\\StringFileInfo\\000004b0\\FileDescription", &pValue, &ValLen));
|
|
Description = CString((LPCSTR)pValue, ValLen);
|
|
}
|
|
|
|
free(Buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
cout << endl << (Filename.GetLength() ? (LPCSTR)Filename : "VCHK.EXE!");
|
|
if (Version.GetLength()) cout << " " << (LPCSTR)Version;
|
|
if (Description.GetLength()) cout << ": " << (LPCSTR)Description;
|
|
cout << endl;
|
|
cout << szHelp;
|
|
} // parseHelp
|
|
break;
|
|
|
|
case CommandLine::parseHelpImports: {
|
|
|
|
BuildInAllowedAndIllegal();
|
|
|
|
cout << "\n--- Illegal imports (errors) --------------\n\n";
|
|
illegal_msgs.Dump(cout);
|
|
|
|
cout << "\n--- Known illegal imports (warnings) ------\n\n";
|
|
known_illegal.Dump(cout);
|
|
|
|
cout << "\n--- Allowed imports -----------------------\n\n";
|
|
allowed_imports.Dump(cout);
|
|
|
|
cout << "\n--- Allowed modules -----------------------\n\n";
|
|
allowed_modules.Dump(cout);
|
|
|
|
} // parseHelpImports
|
|
break;
|
|
|
|
default:
|
|
PrintOut ("error: ");
|
|
PrintOut (m_cmd_line.m_error_msg.GetLength() ? (LPCSTR)m_cmd_line.m_error_msg : "unknown failure");
|
|
PrintOut ("\nUse vchk -? for help.\n");
|
|
} // switch
|
|
|
|
if (m_logf)
|
|
fclose (m_logf);
|
|
m_logf = NULL;
|
|
|
|
if (m_listf)
|
|
fclose (m_listf);
|
|
m_listf = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CDrvchkApp::ChkDriver (CString drv_name)
|
|
{
|
|
m_drv_name = drv_name;
|
|
cerr << (LPCSTR)m_drv_name << endl;
|
|
if (!InitIllegalImportsSearch (m_drv_name, "INIT")) {
|
|
PrintOut ("error: can't perform check in ");
|
|
PrintOut (m_drv_name);
|
|
PrintOut (", check the name and path please\n");
|
|
} else if (CheckDriverAndPrintResults ()) {
|
|
PrintOut ("success: no illegal imports in ");
|
|
PrintOut (m_drv_name);
|
|
PrintOut ("\n");
|
|
}
|
|
}
|
|
|
|
BOOL CDrvchkApp::CheckDriverAndPrintResults ()
|
|
{
|
|
|
|
Names Modules = CheckSectionsForImports ();
|
|
|
|
if (!Modules.Ptr) {
|
|
PrintOut ("error: cannot retrieve import information from ");
|
|
PrintOut (m_drv_name);
|
|
PrintOut ("\n");
|
|
return FALSE;
|
|
}
|
|
|
|
int errors_found = 0;
|
|
int warnings_found = 0;
|
|
bool bad_data = false;
|
|
|
|
for (int i=0;
|
|
i<Modules.Num;
|
|
Modules.Ptr = GetNextName(Modules.Ptr), i++) {
|
|
|
|
Names Imports = GetImportsList (Modules.Ptr);
|
|
if (!Imports.Num) {
|
|
bad_data = true;
|
|
break;
|
|
}
|
|
|
|
VCHK_TRACE("Checking " << (LPCSTR)Modules.Ptr << endl)
|
|
|
|
CString module_name (Modules.Ptr);
|
|
module_name.MakeUpper();
|
|
|
|
if (allowed_modules.IsModule(module_name)) {
|
|
//
|
|
// The whole module is allowed, no errors on any import
|
|
// from this module.
|
|
//
|
|
VCHK_TRACE("Allowed module " << (LPCSTR)module_name << endl)
|
|
continue;
|
|
}
|
|
|
|
BOOL KnownIllegals = known_illegal.IsModule(module_name);
|
|
if (KnownIllegals) {
|
|
VCHK_TRACE("Known Illegals from " << (LPCSTR)module_name << endl)
|
|
}
|
|
|
|
BOOL IllegalMsgs = illegal_msgs.IsModule(module_name);
|
|
if (IllegalMsgs) {
|
|
VCHK_TRACE("Illegal Imports from " << (LPCSTR)module_name << endl)
|
|
}
|
|
|
|
BOOL AllowedImports = allowed_imports.IsModule(module_name);
|
|
if (AllowedImports) {
|
|
VCHK_TRACE("Allowed Imports from " << (LPCSTR)module_name << endl)
|
|
}
|
|
|
|
LPSTR ImportsPtr = Imports.Ptr;
|
|
|
|
for (int j=0;
|
|
j<Imports.Num;
|
|
Imports.Ptr = GetNextName (Imports.Ptr), j++) {
|
|
|
|
if (allowed_imports.Lookup(Imports.Ptr)) continue;
|
|
|
|
CString msg = "";
|
|
|
|
CString ImportFnName = module_name +
|
|
CString("!") +
|
|
CString(Imports.Ptr);
|
|
|
|
if (KnownIllegals && known_illegal.Lookup(Imports.Ptr, msg)) {
|
|
PrintOut ("warning: ");
|
|
++warnings_found;
|
|
} else if (AllowedImports && allowed_imports.Lookup(Imports.Ptr)) {
|
|
continue; // Ignore allowed import
|
|
} else if (IllegalMsgs && illegal_msgs.Lookup(Imports.Ptr, msg)) {
|
|
PrintOut ("error: ");
|
|
++errors_found;
|
|
} else {
|
|
PrintOut ("warning: "); // Default case; now we make it warning too, but keep it
|
|
++warnings_found; // a separate case for very probable future changes.
|
|
}
|
|
|
|
PrintOut (m_drv_name);
|
|
PrintOut (": ");
|
|
PrintOut (ImportFnName);
|
|
if (msg.GetLength()) {
|
|
PrintOut (" -- ");
|
|
PrintOut (msg);
|
|
}
|
|
PrintOut ("\n");
|
|
}
|
|
|
|
|
|
if (ImportsPtr) HeapFree (GetProcessHeap(), 0, ImportsPtr);
|
|
}
|
|
|
|
CString drv_bin_name;
|
|
for (int i=m_drv_name.GetLength()-1; i>=0; i--) {
|
|
if (m_drv_name.GetAt(i)=='\\') {
|
|
drv_bin_name = ((LPCSTR)m_drv_name) + i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
BOOL skip_it = FALSE;
|
|
if (m_drv_name.Find("\\wdm\\") != -1) {
|
|
skip_it = TRUE;
|
|
}
|
|
|
|
char buf[256];
|
|
if (skip_it) {
|
|
sprintf (buf, "SKIP WDM:");
|
|
} else if (bad_data) {
|
|
sprintf (buf, "WRONG_BINARY:");
|
|
} else if (errors_found!=0) {
|
|
sprintf (buf, "ERRORS: ");
|
|
} else if (warnings_found!=0) {
|
|
sprintf (buf, "WARNINGS:");
|
|
} else {
|
|
sprintf (buf, "SUCCESS:");
|
|
}
|
|
|
|
ListOut (buf);
|
|
sprintf (buf, "\t%3d errors\t%3d warnings\t%s\n", errors_found, warnings_found, (LPCSTR)drv_bin_name);
|
|
ListOut (buf);
|
|
|
|
return (errors_found==0);
|
|
}
|
|
|