//
// $Id: RegistryProbe.cpp,v 1.11 2005/09/19 22:40:45 bakerj Exp $
//
//****************************************************************************************//
// Copyright (c) 2005, The MITRE Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice, this list
//       of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this 
//       list of conditions and the following disclaimer in the documentation and/or other
//       materials provided with the distribution.
//     * Neither the name of The MITRE Corporation nor the names of its contributors may be
//       used to endorse or promote products derived from this software without specific 
//       prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
// SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//****************************************************************************************//

#include "RegistryProbe.h"

//****************************************************************************************//
//								RegistryProbe Class									  //	
//****************************************************************************************//
RegistryProbe *RegistryProbe::instance = NULL;

RegistryProbe::RegistryProbe()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------
}

RegistryProbe::~RegistryProbe()
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Do nothing for now
	//
	// -----------------------------------------------------------------------
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Public Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
Probe* RegistryProbe::Instance()
{

	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//	Ensure that the RegistryProbe is a singleton.
	// -----------------------------------------------------------------------

	// Use lazy initialization
	if(instance == NULL) 
		instance = new RegistryProbe();

	return instance;	
}

pdVector RegistryProbe::Run(ProbeData *probeDataIn)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Run the registry probe. Return a vector of RegistryData objects
	//
	//	If in verbose logging mode write out a record for each match found 
	//	even if a later refinement excludes that match. For example, if
	//	a key pattern match is specified of .* all keys will match. Now a name
	//	of 'foo' under the key has been specified. In verbose mode a record for 
	//	all keys that matched will be printed and any key that doesn't have 
	//	a name of 'foo under it will have a message stating that the name was 
	//	not found. If not in verbose mode only keys that have a matching name 
	//	are printed.
	// -----------------------------------------------------------------------
	pdVector returnVector;
	sVector hives;
	sVector keys;
	sVector names;
	RegistryData *regKeyIn = (RegistryData*)probeDataIn;
	RegistryData *tmp = NULL;

	//	Hive, Key, and Name are literal
	if((regKeyIn->hive)->type == literal && (regKeyIn->key)->type == literal && (regKeyIn->name)->type == literal) {

		try {

			//	Call GetRegistryKey
			tmp = GetRegistryKey(regKeyIn->hive->object, regKeyIn->key->object, regKeyIn->name->object); 
			returnVector.push_back(tmp);
			tmp = NULL;

		} catch(...) {

			tmp = new RegistryData();
			tmp->SetMessage("Error: (RegistryProbe) Unknown exception occured while running registry probe");
			tmp->SetStatus(error);
			tmp->hive->object = regKeyIn->hive->object;
			tmp->key->object = regKeyIn->key->object;
			tmp->name->object = regKeyIn->name->object;
			tmp->isPatternMatchObject = regKeyIn->isPatternMatchObject;
			returnVector.push_back(tmp);
			tmp = NULL;
		}

	//	At least one pattern match
	} else {

		// Must be in a try/catch block
		try {

			bool foundMatchingHive = false;
			bool foundMatchingKey = false;
			bool foundMatchingName = false;

			//	Reset the matcher
			myMatcher->Reset();

			//	Get matching Hives
			if((regKeyIn->hive)->type == pattern_match) {

				GetMatchingHives(regKeyIn->hive->object, &hives);
				
				if(hives.size() > 0)
					foundMatchingHive = true;

			} else {

				//	Use input hive if it exists
				if(GetRootKey(regKeyIn->hive->object)!= NULL) {
					hives.push_back(regKeyIn->hive->object);
					foundMatchingHive = true;
				}
			}

			//	For each matching hive found
			sVector::iterator hive;
			for (hive=hives.begin(); hive!=hives.end(); hive++) {
				//	Reset the keys vector
				keys.clear();

				//	Key is a pattern match
				if((regKeyIn->key)->type == pattern_match) {

					//	Get matching keys
					KeyPatternMatch((*hive), regKeyIn->key->object, &keys);
					
					if(keys.size() > 0)
						foundMatchingKey = true;


				//	Key is not a pattern match
				} else {

					// should add a check to see if the key exists..
					keys.push_back(regKeyIn->key->object);
					foundMatchingKey = true;
				}

				//	For each matching key found
				sVector::iterator key;
				for (key=keys.begin(); key!=keys.end(); key++) {

					//Reset the names Vector
					names.clear();

					//	Name is a pattern match
					if(regKeyIn->name->type == pattern_match) {

						//	Get matching names
						GetMatchingNames((*hive), (*key), regKeyIn->name->object, &names);

						if(names.size() > 0) 
							foundMatchingName = true;

					//	Name is not a pattern match
					} else {
						names.push_back(regKeyIn->name->object);				
						foundMatchingName = true;
					}

					//	For each matching name
					sVector::iterator name;
					for (name=names.begin(); name!=names.end(); name++) {

						//	Call GetRegistryProbe
						tmp =  GetRegistryKey((*hive), (*key), (*name));
						if (tmp->GetStatus() != doesNotExist){
							returnVector.push_back(tmp);
						} else {
							delete tmp;
						}
					}
				}
			}

			// Add an object indicateing that the patterns either matched an object or did not
			tmp = new RegistryData();
			tmp->hive->object = regKeyIn->hive->object;
			tmp->hive->type = regKeyIn->hive->type;
			tmp->key->object = regKeyIn->key->object;
			tmp->key->type = regKeyIn->key->type;
			tmp->name->object = regKeyIn->name->object;
			tmp->name->type = regKeyIn->name->type;
			if(!foundMatchingHive || !foundMatchingKey || !foundMatchingName) {
				
				tmp->SetMessage("No matches were found in the registry for the specified pattern.");
				tmp->SetStatus(doesNotExist);

			} else {

				tmp->SetMessage("The specified pattern matched at least one item in the registry.");
				tmp->SetStatus(exists);
			}
			tmp->isPatternMatchObject = true;
			returnVector.push_back(tmp);
			tmp = NULL;

		//	Might be an error with hive key or name... The exception caught should specify the error
		} catch(Exception ex) {

			tmp = new RegistryData();
			tmp->SetMessage(ex.GetErrorMessage());
			tmp->hive->object = regKeyIn->hive->object;
			tmp->hive->type = regKeyIn->hive->type;
			tmp->key->object = regKeyIn->key->object;
			tmp->key->type = regKeyIn->key->type;
			tmp->name->object = regKeyIn->name->object;
			tmp->name->type = regKeyIn->name->type;
			tmp->isPatternMatchObject = regKeyIn->isPatternMatchObject;
			// Set the status
			if(ex.GetSeverity() == ERROR_NOTICE) {
				tmp->SetStatus(doesNotExist);
			} else {
				tmp->SetStatus(error);
			}

			returnVector.push_back(tmp);
			tmp = NULL;

		//	Unknown error
		} catch(...) {

			tmp = new RegistryData();
			tmp->SetMessage("Error: (RegistryProbe) Unknown exception occured while running registry probe");
			tmp->hive->object = regKeyIn->hive->object;
			tmp->hive->type = regKeyIn->hive->type;
			tmp->key->object = regKeyIn->key->object;
			tmp->key->type = regKeyIn->key->type;
			tmp->name->object = regKeyIn->name->object;
			tmp->name->type = regKeyIn->name->type;
			tmp->isPatternMatchObject = regKeyIn->isPatternMatchObject;
			returnVector.push_back(tmp);
			tmp = NULL;
		}
	}

	return returnVector;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Private Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void RegistryProbe::GetMatchingHives(string pattern, sVector *hives)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Return a vector of hives as strings that match the pattern 
	//	Supported hives:
	//		"HKEY_CLASSES_ROOT"
	//		"HKEY_CURRENT_CONFIG"
	//		"HKEY_CURRENT_USER"
	//		"HKEY_LOCAL_MACHINE"
	//		"HKEY_USERS"
	//
	//	May throw REGEXException if the pattern is invalid.
	//
	// -----------------------------------------------------------------------

	try {
		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_CLASSES_ROOT"))
			hives->push_back("HKEY_CLASSES_ROOT");

		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_CURRENT_CONFIG"))
			hives->push_back("HKEY_CURRENT_CONFIG");

		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_CURRENT_USER"))
			hives->push_back("HKEY_CURRENT_USER");

		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_LOCAL_MACHINE"))
			hives->push_back("HKEY_LOCAL_MACHINE");

		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_USERS"))
			hives->push_back("HKEY_USERS");
		
	}catch(REGEXException ex) {
		if(ex.GetSeverity() == ERROR_WARN) {
			string pcreMsg = "";
			pcreMsg.append("Registry Keys Probe Warning - while searching for matching hives:\n");
			pcreMsg.append("-----------------------------\n");
			pcreMsg.append(ex.GetErrorMessage());
			if(Log::verboseMode) {
				cout << pcreMsg << "\n"<< endl;
				Log::WriteLog(pcreMsg + "\n\n");
			}
		}
		
		throw;
	}
}

void RegistryProbe::GetMatchingKeys(string hiveIn, string keyIn, string pattern, sVector *keys)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Search the registry for keys under the designated hive and input key 
	//	that match the pattern. add all matches to the keys vector. For every sub key
	//	found make recursive call. stop when all subkeys have been searched
	//
	// -----------------------------------------------------------------------
	HKEY hkey;								//	pointer to the key that will be opened
	LONG res;								//	result from enumerating the subkeys
	LONG openRes;							//	result from opening the key
	LPTSTR lpName = (LPTSTR)malloc(1024);	//	buffer to store the subkey name
	DWORD dwName = 1024;					//	number of chars in the subkey
	DWORD dwIndex = 0;						//	index of subkey to enumerate
	FILETIME ftLastWriteTime;				//	time the cur subkey was last written to
	string workingKey = "";					//	The name of the keyIn and the subkey concatenated
	string errorMessage = "";				//	

	/////////////////////////////////////////////////////////////////
	//	Open the specified key
	/////////////////////////////////////////////////////////////////
	HKEY rootKey = GetRootKey(hiveIn);
	if(rootKey == NULL)
	{
		errorMessage.append("(RegistryProbe) The registry hive '");
		errorMessage.append(hiveIn);
		errorMessage.append("' does not exist.");
		throw RegistryProbeException(errorMessage);
	}
			

	openRes = RegOpenKeyEx(	rootKey,		// handle to open hive
							keyIn.c_str(),	// subkey name
							0,				// reserved
							KEY_READ,		// security access mask
							&hkey);			// pointer to open key

	/////////////////////////////////////////////////////////////////
	//	Check attempt to open key
	/////////////////////////////////////////////////////////////////
	if (openRes == ERROR_SUCCESS) {

		for (dwIndex = 0, res = ERROR_SUCCESS; res == ERROR_SUCCESS; dwIndex++) {
			//	Get the working key as a string
			workingKey = keyIn;
			if(workingKey.compare("") != 0) {

				if(workingKey.at(workingKey.length()-1) != '\\') {
					workingKey.append("\\");
				}
			}

			//	Reset the buffer and the buffer size
			dwName = 1024;
			ZeroMemory(lpName, dwName);
						
			res = RegEnumKeyEx(	hkey,				// handle to key to enumerate
								dwIndex,			// subkey index
								lpName,				// subkey name
								&dwName,			// size of subkey buffer
								NULL,				// reserved
								NULL,				// class string buffer
								NULL,				// size of class string buffer
								&ftLastWriteTime);	// last write time

			//	Check results
			if(res == ERROR_SUCCESS) {

				//	Add the subkey to the working key
				workingKey.append(lpName);

				//	Make recursive call
				GetMatchingKeys(hiveIn, workingKey, pattern, keys);

				//	If a match add the new key to the keys vector
				if(myMatcher->IsMatch(pattern.c_str(), workingKey.c_str()))
					keys->push_back(workingKey);
			}
		}
	}
	
	RegCloseKey(hkey);	
}

void RegistryProbe::GetMatchingNames(string hiveIn, string keyIn, string pattern, sVector *names)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Search the registry for names under the designated hive and input key 
	//	that match the pattern. add all matches to the names vector. 
	//	stop when all names have been searched
	//
	// -----------------------------------------------------------------------
	HKEY hkey;								//	pointer to the key that will be opened
	LONG res;								//	result from enumerating the subkeys
	LONG openRes;							//	result from opening the key
	LPTSTR lpName = (LPTSTR)malloc(1024);	//	buffer to store the subkey name
	DWORD dwName = 1024;					//	number of chars in the subkey
	DWORD dwIndex = 0;						//	index of subkey to enumerate
	string name = "";						//	The name of the keyIn and the subkey concatenated
	string errorMessage = "";				//

	/////////////////////////////////////////////////////////////////
	//	Open the specified key
	/////////////////////////////////////////////////////////////////
	HKEY rootKey = GetRootKey(hiveIn);
	if(rootKey == NULL) {

		errorMessage.append("(RegistryProbe) The registry hive '");
		errorMessage.append(hiveIn);
		errorMessage.append("' does not exist.");
		throw RegistryProbeException(errorMessage);
	}
			

	openRes = RegOpenKeyEx(	rootKey,		// handle to open hive
							keyIn.c_str(),	// subkey name
							0,				// reserved
							KEY_QUERY_VALUE,// security access mask
							&hkey);			// pointer to open key

	/////////////////////////////////////////////////////////////////
	//	Check attempt to open key
	/////////////////////////////////////////////////////////////////
	if (openRes == ERROR_SUCCESS) {

		try {
			myMatcher->Reset();
			for (dwIndex = 0, res = ERROR_SUCCESS; res == ERROR_SUCCESS; dwIndex++) {

				//	Reset the buffer and the buffer size
				dwName = 1024;
				ZeroMemory(lpName, dwName);
						
				res = RegEnumValue(	hkey,		// handle to key to query
									dwIndex,	// index of value to query
									lpName,		// value buffer
									&dwName,	// size of value buffer
									NULL,		// reserved
									NULL,		// type buffer
									NULL,		// data buffer
									NULL);		// size of data buffer

				//	Check results
				if(res == ERROR_SUCCESS) {

					//	Get the name
					name = "";
					name.append(lpName);

					//	If a match add the new name to the names vector
					if(myMatcher->IsMatch(pattern.c_str(), name.c_str()))
						names->push_back(name);

				}
			}
		} catch(REGEXException ex) {
			if(ex.GetSeverity() == ERROR_WARN) {

				string pcreMsg = "";
				pcreMsg.append("Registry Keys Probe Warning - when searching for matching names:\n");
				pcreMsg.append("-----------------------------\n");
				pcreMsg.append(ex.GetErrorMessage());
				if(Log::verboseMode) {
					cout << pcreMsg << "\n"<< endl;
					Log::WriteLog(pcreMsg + "\n\n");
				}
			} else {
				throw;
			}
		}
	}
	
	RegCloseKey(hkey);	
}

string RegistryProbe::GetRegKeyValue(string strKeyIn)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Break string into a hive, a key, and a name. Then call the 
	//	RegistryKeys probe to get the value
	//
	// -----------------------------------------------------------------------
	
	int tmp					= 0;
	string value			= "";
	RegistryData *rkIn	= new RegistryData();

	//	Remove leading and trailing \ if they exist
	if(strKeyIn.find("\\") == 0)
		strKeyIn = strKeyIn.substr(1, strKeyIn.length()-1);

	if(strKeyIn.find_last_of("\\") == strKeyIn.length()-1)
		strKeyIn = strKeyIn.substr(0, strKeyIn.length()-1);

	//	Parse the input
	tmp = strKeyIn.find("\\");
	rkIn->hive->object = strKeyIn.substr(0, tmp);
	strKeyIn = strKeyIn.substr(tmp+1, strKeyIn.length());
	tmp = strKeyIn.find_last_of("\\");
	rkIn->name->object = strKeyIn.substr(tmp+1, strKeyIn.length());
	rkIn->key->object = strKeyIn.substr(0, tmp);


	//	Call the probe
	Probe *probe = RegistryProbe::Instance();
	pdVector rksOut;
	rksOut = probe->Run(rkIn);
	delete rkIn;
	rkIn = NULL;

	// Must write a record to the sc file for this registry key so that
	// it can be used durring analysis
	rksOut[0]->Write();

	RegistryData *resultRegKey = (RegistryData*)rksOut[0];

	//	Check the status 
	if(resultRegKey->GetStatus() == error) {
		string errMsg = "Error: An error occured while collecting data for the specified registry key.\n";
		errMsg.append("Probe message: " + resultRegKey->GetMessage());
		throw RegistryProbeException(errMsg);

	} else if(resultRegKey->GetStatus() == doesNotExist) {
		string errMsg = "Error: The specified registry key does not exist.\n";
		errMsg.append("Probe message: " + resultRegKey->GetMessage());
		throw RegistryProbeException(errMsg);
	}

	//	Return the Value
	return resultRegKey->value->value;
}

RegistryData* RegistryProbe::GetRegistryKey(string hiveIn, string keyIn, string nameIn)
{
	// -----------------------------------------------------------------------
	//  ABSTRACT
	//
	//  Gather new data and put in a RegistryData object.
	//
	// -----------------------------------------------------------------------

    HKEY hkey;
	DWORD parse_depth = 0;
	LONG res;

	string errorMessage = "";

	//	init output RegistryData
	RegistryData *resultKey = new RegistryData();
	resultKey->hive->object = hiveIn;
	resultKey->key->object = keyIn;
	resultKey->name->object = nameIn;

	// NOTE: An error getting the root key will result in a NULL key and
	// will be caught by RegOpenKeyEx().

	HKEY rootKey = GetRootKey(hiveIn);		

	res = RegOpenKeyEx(rootKey,				// handle to open hive
	                   keyIn.c_str(),		// subkey name
					   0,					// reserved
					   KEY_READ,			// security access mask
					   &hkey);				// pointer to open key

	if (res != ERROR_SUCCESS) {
		if(rootKey == NULL) {

			errorMessage.append("(RegistryProbe) The registry hive '");
			errorMessage.append(hiveIn);
			errorMessage.append("' does not exist.");
			resultKey->SetMessage(resultKey->GetMessage() + errorMessage);
			resultKey->SetStatus(doesNotExist);

		} else if (res == ERROR_FILE_NOT_FOUND) {

			errorMessage.append("(RegistryProbe) The registry key '");
			errorMessage.append(keyIn.c_str());
			errorMessage.append("' does not exist.");
			resultKey->SetMessage(resultKey->GetMessage() + errorMessage);
			resultKey->SetStatus(doesNotExist);

		} else if (res == ERROR_INVALID_HANDLE) {

			errorMessage.append("(RegistryProbe) The handle for the registry key '");
			errorMessage.append(keyIn.c_str());
			errorMessage.append("' is not valid.");
			resultKey->SetMessage(resultKey->GetMessage() + errorMessage);
			resultKey->SetStatus(error);

		} else {
			
			string systemErrMsg = Common::GetErrorMessage(res);

			char errorCodeBuffer[20];
			_ltoa(res, errorCodeBuffer, 20);

			errorMessage.append("(RegistryProbe) Unable to get values for registry key '");
			errorMessage.append(keyIn.c_str());
			errorMessage.append("'.  Error Code - ");
			errorMessage.append(errorCodeBuffer);
			errorMessage.append(" - " + systemErrMsg);
			resultKey->SetMessage(resultKey->GetMessage() + errorMessage);
			resultKey->SetStatus(error);
		}		
		
	} else {


		DWORD type = 0;
		DWORD valuelen = 0;

		// Determine how big the buffer must be to store the data.  By specifying NULL for the
		// buffer size parameter, the function returns the value ERROR_MORE_DATA, and stores
		// the required buffer size, in bytes, into valuelen.

		res = RegQueryValueEx(hkey,				// handle to key
							  nameIn.c_str(),	// value name
							  NULL,				// reserved
							  NULL,				// type buffer
							  NULL,				// data buffer
							  &valuelen);		// size of data buffer

		// Allocate space for the buffer.

		LPBYTE value = (LPBYTE) malloc(valuelen);

		// Retrieve the type and value for the specified name associated with an open registry
		// key.

		res = RegQueryValueEx(hkey,				// handle to key
							  nameIn.c_str(),	// value name
							  NULL,				// reserved
							  &type,			// type buffer
							  value,			// data buffer
							  &valuelen);		// size of data buffer

		if (res == ERROR_FILE_NOT_FOUND) {

			errorMessage.append("(RegistryProbe) The name '");
			errorMessage.append(nameIn.c_str());
			errorMessage.append("' does not exist under ");
			errorMessage.append(hiveIn.c_str());
			errorMessage.append("\\");
			errorMessage.append(keyIn.c_str());
			errorMessage.append(".");
			resultKey->SetMessage(resultKey->GetMessage() + errorMessage);
			resultKey->SetStatus(doesNotExist);

		} else if (res != ERROR_SUCCESS) {

			string systemErrMsg = Common::GetErrorMessage(res);

			char errorCodeBuffer[20];
			_ltoa(res, errorCodeBuffer, 20);
			
			string errorMessage = "";
			errorMessage.append("(RegistryProbe) Unable to get values for '");
			errorMessage.append(nameIn.c_str());
			errorMessage.append("' under registry key '");
			errorMessage.append(hiveIn.c_str());
			errorMessage.append("\\");
			errorMessage.append(keyIn.c_str());
			errorMessage.append("'.  Error Code - ");
			errorMessage.append(errorCodeBuffer);
			errorMessage.append(" - " + systemErrMsg);
			resultKey->SetMessage(resultKey->GetMessage() + errorMessage);
			resultKey->SetStatus(error);

		//	Only call RetrieveInfo() if res == ERROR_SUCCESS
		} else {

			// We now have all the info we need.
			RetrieveInfo(hiveIn, keyIn, nameIn, type, value, valuelen, resultKey);
		}

		free(value);

		RegCloseKey(hkey);
	}

	return resultKey;
}

HKEY RegistryProbe::GetRootKey(string hiveIn)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  An application must open a key before it can add data to the registry. To open a
	//  key, an application must supply a handle to another key in the registry that is
	//  already open. The system defines predefined keys that are always open.  Determine
	//  if one of these predefined keys can be used, and if so, return it.
	//
	//  NOTE: We have used _strnicmp() instead of the string compare() function as we need
	//  to do a compare without regard to case.
	//
	// -----------------------------------------------------------------------

    if (_strnicmp(hiveIn.c_str(), "HKEY_LOCAL_MACHINE", 18) == 0) {
        return HKEY_LOCAL_MACHINE;
    } else if (_strnicmp(hiveIn.c_str(), "HKEY_USERS", 10) == 0) {
        return HKEY_USERS;
    } else if (_strnicmp(hiveIn.c_str(), "HKEY_CURRENT_USER", 17) == 0) {
        return HKEY_CURRENT_USER;
    } else if (_strnicmp(hiveIn.c_str(), "HKEY_CURRENT_CONFIG", 19) == 0) {
        return HKEY_CURRENT_CONFIG;
    } else if (_strnicmp(hiveIn.c_str(), "HKEY_CLASSES_ROOT", 17) == 0) {
        return HKEY_CLASSES_ROOT;
    } else {
		return NULL;
    }
}

void RegistryProbe::KeyPatternMatch(string hive, string pattern, sVector *keys)
{
	// -----------------------------------------------------------------------
	//  ABSTRACT
	//
	//	Attempt to locate any constant portion of the registry key. If a constant
	//	portion can be found then start the pattern matching search from the end of the 
	//	constant portion to save time. This cuts the time to 1/20th of the old time, nad
	//	reduces the memory usage of this probe to 1/30th of the old memory usage.
	//
	// -----------------------------------------------------------------------

	string patternOut= "";
	string constantPortionOut= "";
	this->myMatcher->GetConstantPortion(pattern, "\\", &patternOut, &constantPortionOut);
	// Remove extra slashes
	constantPortionOut = myMatcher->RemoveExtraSlashes(constantPortionOut);


	if(patternOut.compare("") != 0) {
		try {
			myMatcher->Reset();

			//	Call search function wiht
			//	the constant portion found as the key and
			//	the entire pattern as the pattern
			GetMatchingKeys(hive, constantPortionOut, pattern, keys);

		} catch(REGEXException ex) {

			if(ex.GetSeverity() == ERROR_WARN) {
				string pcreMsg = "";
				pcreMsg.append("Registry Keys Probe Warning - while searching for matching keys:\n");
				pcreMsg.append("-----------------------------------------------------------------------\n");
				pcreMsg.append(ex.GetErrorMessage());
				if(Log::verboseMode) {
					cout << pcreMsg << "\n"<< endl;
					Log::WriteLog(pcreMsg + "\n\n");
				}
			} else {
				throw;
			}
		}

	} else {

		//	There are no pattern matching chars treat this as a normal path 
		//	after removing the double '\'
		pattern = myMatcher->RemoveExtraSlashes(pattern);
		keys->push_back(pattern);
	}
}

void RegistryProbe::RetrieveInfo(string hiveIn, string keyIn, string nameIn, 
									  DWORD typeIn, LPBYTE valueIn, DWORD valuelenIn, RegistryData *regKeyIn)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//	Convert the registry data n to string representations and add to the provided
	//	RegistryData object.
	// -----------------------------------------------------------------------

	switch (typeIn) {

		case REG_BINARY:
		{
			regKeyIn->type->value = "reg_binary";
			regKeyIn->value->dataType = binaryType;

			// The buffer must be three bytes long, two bytes for each hex charater in the
			// binary data, and one byte for the terminating NULL character.

			char binaryBuf[3];

			// Loop through each hex character.  Make sure the buffer is NULL terminated.
			// Also make sure 0 is in the form 00, and 1 is 01, etc.

			for (DWORD x=0; x<valuelenIn; x++) {

				ZeroMemory(binaryBuf, sizeof(binaryBuf));
				_snprintf(binaryBuf, sizeof(binaryBuf)-1, "%x", valueIn[x]);
				binaryBuf[sizeof(binaryBuf)-1] = '\0';
				if (strlen(binaryBuf) == 1) regKeyIn->value->value.append("0");
				regKeyIn->value->value.append(binaryBuf);
				regKeyIn->value->value.append(" ");
			}

			break;
		}

		case REG_DWORD:
		{
			regKeyIn->type->value = "reg_dword";
			regKeyIn->value->dataType = integerType;

			// The dwordBuf is 12 bytes since the max DWORD (2,147,483,647) is 10 characters
			// long.  Also add a byte for a possible negative sign and a byte for the
			// terminating NULL character.

			char dwordBuf[12];

			ZeroMemory(dwordBuf, sizeof(dwordBuf));
			_snprintf(dwordBuf, sizeof(dwordBuf)-1, "%d", *((DWORD *)valueIn));
			dwordBuf[sizeof(dwordBuf)-1] = '\0';
			regKeyIn->value->value.append(dwordBuf);

			break;
		}

		case REG_EXPAND_SZ:
		{
			regKeyIn->type->value = "reg_expand_sz";
			regKeyIn->value->dataType = stringType;

			char expandBuf[3];

			for (DWORD x=0; x<(valuelenIn); x++) {

				ZeroMemory(expandBuf, sizeof(expandBuf));
				_snprintf(expandBuf, sizeof(expandBuf)-1, "%C", valueIn[x]);
				expandBuf[sizeof(expandBuf)-1] = '\0';
				regKeyIn->value->value.append(expandBuf);
			}

			break;
		}

		case REG_MULTI_SZ:
		{
			regKeyIn->type->value = "reg_multi_sz";
			regKeyIn->value->dataType = stringType;

			char multiszBuf[3];

			// Loop through each character.  Make sure the buffer is NULL terminated.
			// MULTISZ data is an array of null-terminated strings, terminated by two null
			// characters.  Therefore, the loop goes to (valuelenIn - 2) since we can skip
			// the last two characters.  This keeps an extra bar from beeing added to the
			// end of the valueString.  A terminating NULL charater and will be
			// automatically replaced during the append method.

			// NOTE: valuelenIn can be less then 2.  When this is the case, (valuelenIn-2)
			// becomes a very high DWORD.  This is because there are no negative numbers
			// for DWORDS.  Make sure we guard against this by setting valuelenIn = 2 so
			// (valuelenIn-2) = 0 and the loop never runs.

			if (valuelenIn < 2) valuelenIn = 2;

			for (DWORD x=0; x<(valuelenIn-2); x++) {

				ZeroMemory(multiszBuf, sizeof(multiszBuf));
				_snprintf(multiszBuf, sizeof(multiszBuf)-1, "%C", valueIn[x]);
				multiszBuf[sizeof(multiszBuf)-1] = '\0';
				if (multiszBuf[0] == '\0') regKeyIn->value->value.append("|");
				else regKeyIn->value->value.append(multiszBuf);
			}
			
			break;
		}

		case REG_SZ:
		{
			regKeyIn->type->value = "reg_sz";
			regKeyIn->value->dataType = stringType;

			char strBuf[3];

			for (DWORD x=0; x<(valuelenIn); x++) {

				ZeroMemory(strBuf, sizeof(strBuf));
				_snprintf(strBuf, sizeof(strBuf)-1, "%C", valueIn[x]);
				strBuf[sizeof(strBuf)-1] = '\0';
				regKeyIn->value->value.append(strBuf);
			}

			break;
		}

		default:
		{
			regKeyIn->SetMessage("Error: Unable to determine the type and value of the registry key.");
			regKeyIn->type->status = error;
			regKeyIn->value->status = error;
			
			break;
		}
	}
}

//****************************************************************************************//
//							RegistryProbeException Class							  //	
//****************************************************************************************//
RegistryProbeException::RegistryProbeException(string errMsgIn, int severity) : Exception(errMsgIn, severity)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the error message and then set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class constructor that 
	//	takes a single string param.
	//
	// -----------------------------------------------------------------------

}

RegistryProbeException::~RegistryProbeException()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------

}
