Storage Forensics2009/11/23 21:49
Proneer | Security is a people problem...


WMI (Windows Management Instrumentation)



WMI(Windows Management Instrumentation)는 네트워크에서 관리 정보를 공유하는 표준을 만들기 위한 업계의 발의인 WBEM(Web-Based Enterprise Management Initiative)를 Microsoft에서 구현한 것이다. 다시 말해, WMI는 Windows 환경에서 관리 정보(OS, 서비스, 응용프로그램 등)를 공유하기 위한 표준인 것이다.

WMI는 Windows NT 4.0 SP4에 처음 릴리즈 되었는데 이때는 15개의 WMI 공급자를 사용할 수 있었다. 이후 Windows 2000 에는 29개, Windows 2003 에서는 80개, 이후 Vista, Server 2008을 거치면서 100개의 공급자를 지원하고 있다. 이러한 공급자 하에서 관리 정보를 액세스하기 위해서는 관리 정보를 조작할 수 있는 "서버탐색기"라는 기능을 통해 가능하다.

서버탐색기를 통해 관리 정보를 획득하기 위해서는 미리 정의된 WMI 클래스를 이용하여 서버탐색기에 WQL(WMI Query Language) 질의를 통해 가능하다. WMI 클래스는 다음을 통해 확인 가능하다.
http://msdn.microsoft.com/en-us/library/aa394084(VS.85).aspx

WMI 클래스들 중 저장장치의 정보를 얻기 위한 클래스는 다음과 같다.

  • Win32_PhysicalMedia
  • Win32_DiskDrive
  • Win32_DiskPartition
  • Win32_LogicalDisk

이외에도 Windows 환경에서 제공하는 다양한 정보(거의 모든 정보)를 WMI 클래스 질의를 통해 액세스가 가능하다. 또한 하나 이상의 클래스를 조합하여 질의가 가능하다. 다음은 앞서 살펴본 4개의 클래스를 이용하여 저장장치 정보를 액세스하게 만든 프로그램이다.


다음은 Win32_LogicalDisk 클래스와 Win32_DiskPartition 클래스의 연관된 정보를 액세스하는 예제 코드이다.
//
// File Name : PartitionToDrive.h   
//
#pragma once

#include "resource.h"

#define		MAX_DRIVE_LETTER	256

#define		RADIX				10

typedef struct tagDiskToPartition	DISKTOPARTITION;

/*
* disk(e.i. \\PHSYICALDRIVE0 or SAMSUNG HD154C
* patition(e.i. C:, D: or E: ...)
*/
struct tagDiskToPartition
{
	WCHAR	szDiskDrive_Index[MAX_DRIVE_LETTER];
	WCHAR	szDiskDrive_DeviceID[MAX_DRIVE_LETTER];
	WCHAR	szDiskDrive_Model[MAX_DRIVE_LETTER];
	WCHAR	szDiskDrive_Size[MAX_DRIVE_LETTER];
	WCHAR	szLogicalDisk_DeviceID[MAX_DRIVE_LETTER];
	WCHAR	szLogicalDisk_Description[MAX_DRIVE_LETTER];
	WCHAR	szLogicalDisk_FileSystem[MAX_DRIVE_LETTER];
};

BOOL wmi_run();
BOOL wmi_get_PartitionToDrive(CList *listDiskToPartition);
BOOL wmi_close();

//
// File Name : PartitionToDrive.cpp
//
#include "stdafx.h"
#include "PartitionToDrive.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define _WIN32_DCOM
#include 
using namespace std;
#include 
#include 
#pragma comment(lib, "wbemuuid.lib")  

CWinApp theApp;
using namespace std;

IWbemLocator *pLoc = NULL;
IWbemServices *pSvc = NULL;


int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	CList listDiskToPartition;
	
	wmi_run();
	wmi_get_PartitionToDrive(&listDiskToPartition);
	system("pause");
	wmi_close();

	POSITION	pos;
	DISKTOPARTITION	sDiskToPartition;

	for (pos = listDiskToPartition.GetHeadPosition(); pos != NULL;)
	{
		sDiskToPartition = listDiskToPartition.GetNext(pos);
		
		if (wcscmp(sDiskToPartition.szDiskDrive_DeviceID, L""))
			wcout << L"Disk DeviceID        : " << sDiskToPartition.szDiskDrive_DeviceID << endl;
		if (wcscmp(sDiskToPartition.szDiskDrive_Index, L""))
			wcout << L"Disk Index           : " << sDiskToPartition.szDiskDrive_Index << endl;
		if (wcscmp(sDiskToPartition.szDiskDrive_Model, L""))
			wcout << L"Disk Model           : " << sDiskToPartition.szDiskDrive_Model << endl;
		if (wcscmp(sDiskToPartition.szDiskDrive_Size, L""))
			wcout << L"Disk Size            : " << sDiskToPartition.szDiskDrive_Size << endl;
		if (wcscmp(sDiskToPartition.szLogicalDisk_Description, L"")) {
			wcout.imbue( locale("korean") );
			wcout << L"Partition Decription : " << sDiskToPartition.szLogicalDisk_Description << endl;
		}
		if (wcscmp(sDiskToPartition.szLogicalDisk_DeviceID, L""))
			wcout << L"Partition DeviceID   : " << sDiskToPartition.szLogicalDisk_DeviceID << endl;
		if (wcscmp(sDiskToPartition.szLogicalDisk_FileSystem, L""))
			wcout << L"Partition FileSystem : " << sDiskToPartition.szLogicalDisk_FileSystem << endl;
		wcout << L"---------------------------------------" << endl;
	}
	listDiskToPartition.RemoveAll();

	return 0;
}

//// Step 1-5 at:// http://msdn.microsoft.com/en-us/library/aa390423(VS.85).aspx
BOOL wmi_run()
{     
	HRESULT hres;    
	// Step 1: --------------------------------------------------    
	// Initialize COM. ------------------------------------------    
	hres =  CoInitializeEx(0, COINIT_APARTMENTTHREADED);     
	if (FAILED(hres))    
	{        
		cout << "Failed to initialize COM library. Error code = 0x"             
			<< hex << hres << endl;        
		return 1;                  // Program has failed.    
	}    

	// Step 2: --------------------------------------------------    
	// Set general COM security levels --------------------------    
	// Note: If you are using Windows 2000, you need to specify -    
	// the default authentication credentials for a user by using    
	// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----    
	// parameter of CoInitializeSecurity ------------------------    
	hres =  CoInitializeSecurity(        
		NULL,         
		-1,                          // COM authentication        
		NULL,                        // Authentication services        
		NULL,                        // Reserved        
		RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication         
		RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation          
		NULL,                        // Authentication info        
		EOAC_NONE,                   // Additional capabilities         
		NULL                         // Reserved        
		);      

	if (FAILED(hres))    
	{        
		cout << "Failed to initialize security. Error code = 0x"             
			<< hex << hres << endl;        
		CoUninitialize();        
		return 1;                    // Program has failed.    
	}    

	// Step 3: ---------------------------------------------------    
	// Obtain the initial locator to WMI -------------------------    
	//IWbemLocator *pLoc = NULL;    
	hres = CoCreateInstance(        
		CLSID_WbemLocator,                     
		0,         
		CLSCTX_INPROC_SERVER,        
		IID_IWbemLocator, 
		(LPVOID *) &pLoc);    

	if (FAILED(hres))    
	{        
		cout << "Failed to create IWbemLocator object."            
			<< " Err code = 0x"            
			<< hex << hres << endl;        
		CoUninitialize();        
		return 1;                 // Program has failed.    
	}    

	// Step 4: -----------------------------------------------------    
	// Connect to WMI through the IWbemLocator::ConnectServer method    
	//IWbemServices *pSvc = NULL;    
	// Connect to the root\cimv2 namespace with    
	// the current user and obtain pointer pSvc    
	// to make IWbemServices calls.    
	hres = pLoc->ConnectServer(         
		_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace         
		NULL,                    // User name. NULL = current user         
		NULL,                    // User password. NULL = current         
		0,                       // Locale. NULL indicates current         
		NULL,                    // Security flags.         
		0,                       // Authority (e.g. Kerberos)         
		0,                       // Context object          
		&pSvc                    // pointer to IWbemServices proxy         
		);    

	if (FAILED(hres))    
	{        
		cout << "Could not connect. Error code = 0x"              
			<< hex << hres << endl;        
		pLoc->Release();             
		CoUninitialize();        
		return 1;                // Program has failed.    
	}    
	cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;    

	// Step 5: --------------------------------------------------    
	// Set security levels on the proxy -------------------------    
	hres = CoSetProxyBlanket(       
		pSvc,                        // Indicates the proxy to set       
		RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx       
		RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx       
		NULL,                        // Server principal name        
		RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx        
		RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx       
		NULL,                        // client identity       
		EOAC_NONE                    // proxy capabilities     
		);    

	if (FAILED(hres))    
	{        
		cout << "Could not set proxy blanket. Error code = 0x"             
			<< hex << hres << endl;        
		pSvc->Release();        
		pLoc->Release();             
		CoUninitialize();        
		return 1;               // Program has failed.    
	} 

	return 0;
}

BOOL wmi_close()
{ 
	// Cleanup    
	// ========    
	pSvc->Release();    
	pLoc->Release();    
	CoUninitialize();    
	return 0;   // Program successfully completed. 
}

BOOL wmi_get_PartitionToDrive(CList *listDiskToPartition)
{    
	// Use the IWbemServices pointer to make requests of WMI.     
	// Make requests here:    
	HRESULT hres;    
	IEnumWbemClassObject* pEnumerator = NULL;    

	// logical disk 정보에 대한 쿼리 요청
	hres = pSvc->ExecQuery(                    
		bstr_t("WQL"),                     
		bstr_t("SELECT * FROM Win32_LogicalDisk"),                    
		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,                     
		NULL,                    
		&pEnumerator);    

	if (FAILED(hres)) 
	{        
		cout << "Query for processes failed. "             
			<< "Error code = 0x"              
			<< hex << hres << endl;        
		pSvc->Release();        
		pLoc->Release();             
		CoUninitialize();        
		return FALSE;               // Program has failed.    
	} 
	else 
	{
		IWbemClassObject *pclsObj;        
		ULONG uReturn = 0;        
		while (pEnumerator) 
		{
			DISKTOPARTITION	sDiskToPartition;
			::ZeroMemory(&sDiskToPartition, sizeof(sDiskToPartition));

			hres = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);           
			if(0 == uReturn) break;    

			// logical disk 쿼리 결과에서 원하는 정보 획득
			VARIANT vtLogicalDisk_DeviceID, vtLogicalDisk_Description, vtLogicalDisk_FileSystem;           
			hres = pclsObj->Get(_bstr_t(L"DeviceID"), 0, &vtLogicalDisk_DeviceID, 0, 0);
			hres = pclsObj->Get(_bstr_t(L"Description"), 0, &vtLogicalDisk_Description, 0, 0);
			hres = pclsObj->Get(_bstr_t(L"FileSystem"), 0, &vtLogicalDisk_FileSystem, 0, 0);

			// logical disk deviceID 와 연관된 Partition 정보를 가져오기 위한  쿼리 생성           
			wstring tmp = vtLogicalDisk_DeviceID.bstrVal;           
			wstring wstrQuery = L"Associators of {Win32_LogicalDisk.DeviceID='";           
			wstrQuery += tmp;           
			wstrQuery += L"'} where AssocClass=Win32_LogicalDiskToPartition";           

			// 해당 쿼리문으로 쿼리       
			IEnumWbemClassObject* pEnumerator1 = NULL;           
			hres = pSvc->ExecQuery(                             
				bstr_t("WQL"),                              
				bstr_t( wstrQuery.c_str()),                             
				WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,                              
				NULL,                             
				&pEnumerator1 );           

			if ( FAILED(hres) ) 
			{            
				cout << "Query for processes failed. " << "Error code = 0x" << hex << hres << endl;            
				pSvc->Release();            
				pLoc->Release();                 
				CoUninitialize();            
				return FALSE;               // Program has failed.           
			} 
			else 
			{                
				IWbemClassObject *pclsObj1;                
				ULONG uReturn1 = 0;                
				while( pEnumerator1 ) 
				{                     
					hres = pEnumerator1->Next( WBEM_INFINITE, 1, &pclsObj1, &uReturn1 );                     
					if(0 == uReturn1) 
					{
						// logical disk 정보(C: or d: ...) 의 정보만 존재하는 경우 
						// 파티션이 나눠진 경우가 아니라 독립된 장치로 존재하는 경우(A:, CD-ROM or virtual CD-ROM)
						BOOL				bFlag = FALSE;
						POSITION			pos = NULL;
						DISKTOPARTITION		tmpDiskToPartition;
						
						// 중복 제거를 위해
						for (pos = listDiskToPartition->GetHeadPosition(); pos != NULL;)
						{
							tmpDiskToPartition = listDiskToPartition->GetNext(pos);
							if (!wcscmp(tmpDiskToPartition.szLogicalDisk_DeviceID, vtLogicalDisk_DeviceID.bstrVal))
							{
								bFlag = TRUE;
								break;
							}
						}

						if (!bFlag)
						{
							// if vt == 1, 정보를 가져오지 못한 경우
							if (vtLogicalDisk_DeviceID.vt != 1)		
								wcscpy(sDiskToPartition.szLogicalDisk_DeviceID, vtLogicalDisk_DeviceID.bstrVal);
							if (vtLogicalDisk_Description.vt != 1)	
								wcscpy(sDiskToPartition.szLogicalDisk_Description, vtLogicalDisk_Description.bstrVal);
							if (vtLogicalDisk_FileSystem.vt != 1)	
								wcscpy(sDiskToPartition.szLogicalDisk_FileSystem, vtLogicalDisk_FileSystem.bstrVal);

							listDiskToPartition->AddTail(sDiskToPartition);
						}

						break;
					}	
					
                    // Partition 정보와 연관된 Disk Drive 정보를 가져오기 위한 쿼리 생성                     
					VARIANT vtDiskPartition_DeviceID;                     
					hres = pclsObj1->Get( _bstr_t(L"DeviceID"), 0, &vtDiskPartition_DeviceID, 0, 0 );  
					wstring wstrQuery = L"Associators of {Win32_DiskPartition.DeviceID='";                     
					wstrQuery += vtDiskPartition_DeviceID.bstrVal;                     
					wstrQuery += L"'} where AssocClass=Win32_DiskDriveToDiskPartition";                       

					// 생성한 쿼리문으로 쿼리
					IEnumWbemClassObject* pEnumerator2 = NULL;                     
					hres = pSvc->ExecQuery(                                       
						bstr_t("WQL"),                                        
						bstr_t(wstrQuery.c_str()),                                       
						WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,                                        
						NULL,                                       
						&pEnumerator2 );                    

					if ( FAILED(hres) ) 
					{                        
						cout << "Query for processes failed. " << "Error code = 0x" << hex << hres << endl;                        
						pSvc->Release();                        
						pLoc->Release();                             
						CoUninitialize();                        
						return FALSE;               // Program has failed.                     
					} 
					else 
					{                        
						IWbemClassObject *pclsObj2;                        
						ULONG uReturn2 = 0;                        
						while( pEnumerator2 ) 
						{                            
							hres = pEnumerator2->Next( WBEM_INFINITE, 1, &pclsObj2, &uReturn2 );                            
							if(0 == uReturn2) 
							{
								break;
							}

							// 쿼리 결과에서 원하는 정보 획득(disk drive)
							VARIANT vtDiskDrive_DeviceID, vtDiskDrive_Index, vtDiskDrive_Model, vtDiskDrive_Size;                            
							hres = pclsObj2->Get( _bstr_t(L"Index"), 0, &vtDiskDrive_Index, 0, 0 );                              
							hres = pclsObj2->Get( _bstr_t(L"DeviceID"), 0, &vtDiskDrive_DeviceID, 0, 0 );
							hres = pclsObj2->Get( _bstr_t(L"Model"), 0, &vtDiskDrive_Model, 0, 0 );
							hres = pclsObj2->Get( _bstr_t(L"Size"), 0, &vtDiskDrive_Size, 0, 0 );

							BOOL				bFlag = FALSE;
							POSITION			pos = NULL;
							DISKTOPARTITION		tmpDiskToPartition;
							WCHAR				szBuf[MAX_DRIVE_LETTER];
							ZeroMemory(szBuf, sizeof(szBuf));

							// 중복 제거를 위해
							for (pos = listDiskToPartition->GetHeadPosition(); pos != NULL;)
							{
								tmpDiskToPartition = listDiskToPartition->GetNext(pos);
								if (!wcscmp(tmpDiskToPartition.szLogicalDisk_DeviceID, vtLogicalDisk_DeviceID.bstrVal))
								{
									bFlag = TRUE;
									break;
								}
							}

							if (!bFlag)
							{
								if (vtDiskDrive_DeviceID.vt != 1)		
									wcscpy(sDiskToPartition.szDiskDrive_DeviceID, vtDiskDrive_DeviceID.bstrVal);
								if (vtDiskDrive_DeviceID.vt != 1) {
									_itow(vtDiskDrive_Index.uintVal, szBuf, RADIX);
									wcscpy(sDiskToPartition.szDiskDrive_Index, szBuf);
								}
								if (vtDiskDrive_Model.vt != 1)		
									wcscpy(sDiskToPartition.szDiskDrive_Model, vtDiskDrive_Model.bstrVal);
								if (vtDiskDrive_Size.vt != 1)		
									wcscpy(sDiskToPartition.szDiskDrive_Size, vtDiskDrive_Size.bstrVal);
								if (vtLogicalDisk_DeviceID.vt != 1)		
									wcscpy(sDiskToPartition.szLogicalDisk_DeviceID, vtLogicalDisk_DeviceID.bstrVal);
								if (vtLogicalDisk_Description.vt != 1)	
									wcscpy(sDiskToPartition.szLogicalDisk_Description, vtLogicalDisk_Description.bstrVal);
								if (vtLogicalDisk_FileSystem.vt != 1)	
									wcscpy(sDiskToPartition.szLogicalDisk_FileSystem, vtLogicalDisk_FileSystem.bstrVal);

								listDiskToPartition->AddTail(sDiskToPartition);
							}

							VariantClear( &vtDiskDrive_Index );                        
							VariantClear( &vtDiskDrive_DeviceID );
							VariantClear( &vtDiskDrive_Model );
							VariantClear( &vtDiskDrive_Size );
						}                        
						pclsObj1->Release();                    
					}                    
					VariantClear( &vtDiskPartition_DeviceID );                    
					pEnumerator2->Release();      					
				}                
				pclsObj->Release();            
			}            
			VariantClear( &vtLogicalDisk_DeviceID );            
			VariantClear( &vtLogicalDisk_Description );
			VariantClear( &vtLogicalDisk_FileSystem );
			pEnumerator1->Release();        
		}     
	}     
	pEnumerator->Release();     

	return TRUE;
}
저작자 표시 비영리 변경 금지
Creative Commons License
Creative Commons License
Posted by Proneer

TRACKBACK http://forensic-proof.com/trackback/41 관련글 쓰기

댓글을 달아 주세요