CRegKeyEx GetValuesCount returns invalid number - c++

I have this code in C++/VS2013/Win7x64, the app is compiled in 64-bit
CString strKey=_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs");
CRegKeyEx reg;
// Count entries
if (reg.Open(HKEY_LOCAL_MACHINE, strKey, KEY_ALL_ACCESS) != ERROR_SUCCESS)
return;
if (reg.QueryInfo() != ERROR_SUCCESS) return;
dwCountEntries = reg.GetValuesCount();
This is the CRegKeyEx class
ifndef __REGKEYEX_H__INCLUDED__
#define __REGKEYEX_H__INCLUDED__
#include <atlbase.h>
//
// Enhanced version of ATL's CRegKey class
// After you open/attach the key, you should call QueryInfo in order
// to initialize some members which this class use.
//
class CRegKeyEx : public CRegKey
{
public:
// Retreives information about the key
LONG QueryInfo();
// Number of subkeys
DWORD GetSubKeysCount() { return m_cSubKeys; }
// Number of values
DWORD GetValuesCount() { return m_cValues; }
// Enumerate values of arbitrary type
// allocate space in ppBuff (you have to free() it)
LONG EnumValue(DWORD dwIndex, CString& strName,
LPBYTE* ppBuff, DWORD* pBuffSize, DWORD* pType);
// Enum value as String
// *pType will be REG_SZ or REG_EXPAND_SZ
LONG EnumValue(DWORD dwIndex, CString& strName, CString& strValue, DWORD* pType);
// EnumKey with CString output
LONG EnumKey(DWORD dwIndex, CString& strName);
protected:
DWORD m_cSubKeys;
DWORD m_cMaxSubKeyLen;
DWORD m_cValues;
DWORD m_cMaxValueNameLen;
DWORD m_cMaxValueLen; // this is in bytes (can be any kind of data)
};
// ---- implementation ----
// Retreives information about the key
inline LONG CRegKeyEx::QueryInfo()
{
LONG ret;
m_cSubKeys = 0;
m_cMaxSubKeyLen = 0;
m_cValues = 0;
m_cMaxValueNameLen = 0;
m_cMaxValueLen = 0;
ret = ::RegQueryInfoKey(m_hKey,
NULL, NULL, NULL,
&m_cSubKeys, &m_cMaxSubKeyLen,
NULL,
&m_cValues, &m_cMaxValueNameLen, &m_cMaxValueLen,
NULL, NULL);
// include the terminating NULL character(s)
m_cMaxSubKeyLen++;
m_cMaxValueNameLen++;
return ret;
}
// Enumerate values of arbitrary type
// allocate space in ppBuff (you have to free() it)
inline LONG CRegKeyEx::EnumValue(DWORD dwIndex,
CString& strName,
LPBYTE* ppBuff,
DWORD* pBuffSize,
DWORD* pType)
{
TCHAR *pName;
DWORD cName;
LPBYTE pBuff = NULL;
DWORD dwBuffSize = 0;
DWORD dwType;
LONG ret;
// Allocate space for buffers
pName = (TCHAR*)malloc(m_cMaxValueNameLen * sizeof(TCHAR));
cName = m_cMaxValueNameLen;
if (ppBuff != NULL) // data may not be required
{
pBuff = (LPBYTE)malloc(m_cMaxValueLen);
dwBuffSize = m_cMaxValueLen;
}
// Retreive name and data
ret = ::RegEnumValue(m_hKey, dwIndex,
pName, &cName,
NULL, &dwType,
pBuff, pBuff ? &dwBuffSize : NULL);
if (ret != ERROR_SUCCESS)
{
free(pName);
free(pBuff);
return ret;
}
// Resize the buffers
pName = (TCHAR*)realloc(pName, (cName + 1) * sizeof(TCHAR));
if (pBuff)
pBuff = (LPBYTE)realloc(pBuff, dwBuffSize);
if (ppBuff)
*ppBuff = pBuff;
if (pBuffSize)
*pBuffSize = dwBuffSize;
if (pType)
*pType = dwType;
strName = pName;
free(pName);
return ERROR_SUCCESS;
}
// Enum value as String
// *pType will be REG_SZ or REG_EXPAND_SZ
inline LONG CRegKeyEx::EnumValue(DWORD dwIndex,
CString& strName,
CString& strValue,
DWORD* pType)
{
DWORD dwType;
LPBYTE pBuff;
LONG ret;
ret = EnumValue(dwIndex, strName, &pBuff, NULL, &dwType);
if (ret != ERROR_SUCCESS)
return ret;
if (pType)
*pType = dwType;
if (dwType == REG_SZ || dwType == REG_EXPAND_SZ)
{
strValue = (TCHAR*)pBuff;
free(pBuff);
}
else
{
free(pBuff);
return ERROR_INVALID_DATATYPE;
}
return ERROR_SUCCESS;
}
// EnumKey with CString output
inline LONG CRegKeyEx::EnumKey(DWORD dwIndex, CString& strName)
{
TCHAR *pName;
DWORD dwLen;
LONG ret;
// Allocate space for buffers
dwLen = m_cMaxSubKeyLen;
pName = (TCHAR*)malloc(dwLen * sizeof(TCHAR));
memset(pName, 0, dwLen * sizeof(TCHAR));
ret = CRegKey::EnumKey(dwIndex, pName, &dwLen, NULL);
strName = pName;
free(pName);
return ret;
}
#endif __REGKEYEX_H__INCLUDED__
The registry key have 1725 values and GetValuesCount returns only 762 !

Related

How get all bytes of a resource embedded in a executable?

I have a code that inject dlls via Manual Map and works fine ( reading all bytes of file in disk ), now i want read all these bytes directly from a resource, i already tried with the following adaptation, but withou sucess until now.
Here is how is reading file from disk directly:
bool MapRemoteModule(unsigned long pId, char *module)
{
IMAGE_DOS_HEADER *dosHd;
IMAGE_NT_HEADERS *ntHd;
HANDLE hFile = CreateFile(module,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile == INVALID_HANDLE_VALUE)
return false;
unsigned int fSize;
if(GetFileAttributes(module) & FILE_ATTRIBUTE_COMPRESSED)
fSize = GetCompressedFileSize(module, NULL);
else
fSize = GetFileSize(hFile, NULL);
unsigned char *dllBin = new unsigned char[fSize];
unsigned int nBytes;
ReadFile(hFile, dllBin, fSize, (LPDWORD)&nBytes, FALSE);
CloseHandle(hFile);
...
and here is my try of adapt to work read these bytes from resource:
// Mapping.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "resource.h"
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <string>
using namespace std;
#pragma comment(lib, "shlwapi.lib")
#define ID_LOADER_DLL MAKEINTRESOURCE(IDR_DLL1)
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD_PTR)(ptr) + (DWORD_PTR)(addValue))
#define MakeDelta(cast, x, y) (cast) ( (DWORD_PTR)(x) - (DWORD_PTR)(y))
bool MapRemoteModule(unsigned long pId, LPCSTR ResName);
unsigned long GetProcessIdByName(char *);
HMODULE GetRemoteModuleHandle(unsigned long, char *);
FARPROC GetRemoteProcAddress(unsigned long, char *, char *);
bool FixImports(unsigned long, void *, IMAGE_NT_HEADERS *, IMAGE_IMPORT_DESCRIPTOR *);
bool FixRelocs(void *, void *, IMAGE_NT_HEADERS *, IMAGE_BASE_RELOCATION *, unsigned int);
bool MapSections(HANDLE, void *, void *, IMAGE_NT_HEADERS *);
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD, PIMAGE_NT_HEADERS);
LPVOID GetPtrFromRVA(DWORD, PIMAGE_NT_HEADERS, PBYTE);
__declspec(naked) void DllCall_stub(HMODULE hMod)
{
_asm
{
push 0
push 1
push [esp+0Ch]
mov eax, 0xDEADBEEF
call eax
ret
}
}
__declspec(naked) void DC_stubend(void) { }
bool MapRemoteModule(unsigned long pId, LPCSTR ResName)
{
IMAGE_DOS_HEADER *dosHd;
IMAGE_NT_HEADERS *ntHd;
HRSRC hResource;
HGLOBAL hResourceLoaded;
LPBYTE lpBuffer;
hResource = FindResource(NULL, ResName, RT_RCDATA);
if (NULL != hResource)
{
hResourceLoaded = LoadResource(NULL, hResource);
if (NULL != hResourceLoaded)
{
lpBuffer = (LPBYTE) LockResource(hResourceLoaded);
if (NULL != lpBuffer)
{
unsigned int fSize = 0;
fSize = SizeofResource(NULL, hResource);
if (fSize > 0)
{
unsigned char *dllBin = lpBuffer;
unsigned int nBytes = fSize;
dosHd = MakePtr(IMAGE_DOS_HEADER *, dllBin, 0);
if(dosHd->e_magic != IMAGE_DOS_SIGNATURE)
{
delete dllBin;
return false;
}
ntHd = MakePtr(IMAGE_NT_HEADERS *, dllBin, dosHd->e_lfanew);
if(ntHd->Signature != IMAGE_NT_SIGNATURE)
{
delete dllBin;
return false;
}
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);
if(!hProcess)
return false;
void *moduleBase = VirtualAllocEx(hProcess,
NULL,
ntHd->OptionalHeader.SizeOfImage,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
if(!moduleBase)
return false;
void *stubBase = VirtualAllocEx(hProcess,
NULL,
MakeDelta(SIZE_T, DC_stubend, DllCall_stub),
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
if(!stubBase)
return false;
IMAGE_IMPORT_DESCRIPTOR *impDesc = (IMAGE_IMPORT_DESCRIPTOR *)GetPtrFromRVA(
(DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress),
ntHd,
(PBYTE)dllBin);
if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
{
if(!FixImports(pId,
(unsigned char *)dllBin,
ntHd,
impDesc)) return FALSE;
};
IMAGE_BASE_RELOCATION *reloc = (IMAGE_BASE_RELOCATION *)GetPtrFromRVA(
(DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress),
ntHd,
(PBYTE)dllBin);
if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)
{
FixRelocs(dllBin,
moduleBase,
ntHd,
reloc,
ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
}
else
{
return false;
};
WriteProcessMemory(hProcess,
moduleBase,
dllBin,
ntHd->FileHeader.SizeOfOptionalHeader + sizeof(ntHd->FileHeader) + sizeof(ntHd->Signature),
(SIZE_T *)&nBytes);
MapSections(hProcess, moduleBase, dllBin, ntHd);
VirtualProtect((LPVOID)DllCall_stub,
MakeDelta(SIZE_T, DC_stubend, DllCall_stub),
PAGE_EXECUTE_READWRITE,
(DWORD *)&nBytes);
*MakePtr(unsigned long *, DllCall_stub, 9) =
MakePtr(unsigned long, moduleBase, ntHd->OptionalHeader.AddressOfEntryPoint);
WriteProcessMemory(hProcess,
stubBase,
(LPVOID)DllCall_stub,
MakeDelta(SIZE_T, DC_stubend, DllCall_stub),
(SIZE_T *)&nBytes);
CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)stubBase,
moduleBase,
0,
NULL);
delete dllBin;
return true;
}
}
}
}
return false;
}
bool MapSections(HANDLE hProcess, void *moduleBase, void *dllBin, IMAGE_NT_HEADERS *ntHd)
{
IMAGE_SECTION_HEADER *header = IMAGE_FIRST_SECTION(ntHd);
unsigned int nBytes = 0;
unsigned int virtualSize = 0;
unsigned int n = 0;
for(unsigned int i = 0; ntHd->FileHeader.NumberOfSections; i++)
{
if(nBytes >= ntHd->OptionalHeader.SizeOfImage)
break;
WriteProcessMemory(hProcess,
MakePtr(LPVOID, moduleBase, header->VirtualAddress),
MakePtr(LPCVOID, dllBin, header->PointerToRawData),
header->SizeOfRawData,
(LPDWORD)&n);
virtualSize = header->VirtualAddress;
header++;
virtualSize = header->VirtualAddress - virtualSize;
nBytes += virtualSize;
VirtualProtectEx(hProcess,
MakePtr(LPVOID, moduleBase, header->VirtualAddress),
virtualSize,
header->Characteristics & 0x00FFFFFF,
NULL);
}
return true;
}
bool FixImports(unsigned long pId, void *base, IMAGE_NT_HEADERS *ntHd, IMAGE_IMPORT_DESCRIPTOR *impDesc)
{
char *module;
bool retfix=1;
char tempstr[MAX_PATH]="";
while((module = (char *)GetPtrFromRVA((DWORD)(impDesc->Name), ntHd, (PBYTE)base)))
{
if(!GetRemoteModuleHandle(pId, module))
{
retfix=0;
break;
};
IMAGE_THUNK_DATA *itd =
(IMAGE_THUNK_DATA *)GetPtrFromRVA((DWORD)(impDesc->FirstThunk), ntHd, (PBYTE)base);
while(itd->u1.AddressOfData)
{
IMAGE_IMPORT_BY_NAME *iibn;
iibn = (IMAGE_IMPORT_BY_NAME *)GetPtrFromRVA((DWORD)(itd->u1.AddressOfData), ntHd, (PBYTE)base);
itd->u1.Function = MakePtr(DWORD, GetRemoteProcAddress(pId,
module,
(char *)iibn->Name), 0);
itd++;
}
impDesc++;
}
return retfix;
}
bool FixRelocs(void *base, void *rBase, IMAGE_NT_HEADERS *ntHd, IMAGE_BASE_RELOCATION *reloc, unsigned int size)
{
unsigned long ImageBase = ntHd->OptionalHeader.ImageBase;
unsigned int nBytes = 0;
unsigned long delta = MakeDelta(unsigned long, rBase, ImageBase);
while(1)
{
unsigned long *locBase =
(unsigned long *)GetPtrFromRVA((DWORD)(reloc->VirtualAddress), ntHd, (PBYTE)base);
unsigned int numRelocs = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
if(nBytes >= size) break;
unsigned short *locData = MakePtr(unsigned short *, reloc, sizeof(IMAGE_BASE_RELOCATION));
for(unsigned int i = 0; i < numRelocs; i++)
{
if(((*locData >> 12) & IMAGE_REL_BASED_HIGHLOW))
*MakePtr(unsigned long *, locBase, (*locData & 0x0FFF)) += delta;
locData++;
}
nBytes += reloc->SizeOfBlock;
reloc = (IMAGE_BASE_RELOCATION *)locData;
}
return true;
}
FARPROC GetRemoteProcAddress(unsigned long pId, char *module, char *func)
{
HMODULE remoteMod = GetRemoteModuleHandle(pId, module);
HMODULE localMod = GetModuleHandle(module);
unsigned long delta = MakeDelta(unsigned long, remoteMod, localMod);
return MakePtr(FARPROC, GetProcAddress(localMod, func), delta);
}
HMODULE GetRemoteModuleHandle(unsigned long pId, char *module)
{
MODULEENTRY32 modEntry;
HANDLE tlh = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pId);
modEntry.dwSize = sizeof(MODULEENTRY32);
Module32First(tlh, &modEntry);
do
{
if(!_stricmp(modEntry.szModule, module))
return modEntry.hModule;
modEntry.dwSize = sizeof(MODULEENTRY32);
}
while(Module32Next(tlh, &modEntry));
return NULL;
}
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva, PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned int i;
for ( i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
DWORD size = section->Misc.VirtualSize;
if ( 0 == size )
size = section->SizeOfRawData;
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + size)))
return section;
}
return 0;
}
LPVOID GetPtrFromRVA( DWORD rva, IMAGE_NT_HEADERS *pNTHeader, PBYTE imageBase )
{
PIMAGE_SECTION_HEADER pSectionHdr;
INT delta;
pSectionHdr = GetEnclosingSectionHeader( rva, pNTHeader );
if ( !pSectionHdr )
return 0;
delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
return (PVOID) ( imageBase + rva - delta );
}
int _tmain(int argc, _TCHAR* argv[])
{
ULONG rc;
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
memset(&StartupInfo, 0, sizeof(StartupInfo));
StartupInfo.cb = sizeof(STARTUPINFO);
StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow = SW_HIDE;
if (!CreateProcess( NULL, "c:\\windows\\system32\\notepad.exe", NULL, NULL, FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&StartupInfo,
&ProcessInfo))
{
return 0;
}
WaitForSingleObject(ProcessInfo.hProcess, 5000);
if(!GetExitCodeProcess(ProcessInfo.hProcess, &rc))
rc = 0;
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
MapRemoteModule(ProcessInfo.dwProcessId, ID_LOADER_DLL);
return 0;
}
Someone could help to solve?

Print name, type and data of registry

I am trying to print info about registry. My problem is in the first for loop.
I can't get it to print dataType and data correctly.
Also, adding them in the same print will crash the program or not print correctly.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
void EnumerateValues(HKEY hKey, DWORD numValues)
{
DWORD dwIndex = 0;
LPSTR valueName = new CHAR[64];
DWORD valNameLen;
DWORD dataType;
DWORD data;
DWORD dataSize;
for (int i = 0; i < numValues; i++)
{
RegEnumValue(hKey,
dwIndex,
valueName,
&valNameLen,
NULL,
&dataType,
(BYTE*)&data,
&dataSize);
dwIndex++;
_tprintf(TEXT("(%d) %s %d\n"), i+1, valueName, dataType);
// printf("Code: 0x%08X\n", data);
}
}
void EnumerateSubKeys(HKEY RootKey, char* subKey, unsigned int tabs = 0)
{
HKEY hKey;
DWORD cSubKeys; //Used to store the number of Subkeys
DWORD maxSubkeyLen; //Longest Subkey name length
DWORD cValues; //Used to store the number of Subkeys
DWORD maxValueLen; //Longest Subkey name length
DWORD retCode; //Return values of calls
RegOpenKeyEx(RootKey, subKey, 0, KEY_ALL_ACCESS, &hKey);
RegQueryInfoKey(hKey, // key handle
NULL, // buffer for class name
NULL, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&maxSubkeyLen, // longest subkey length
NULL, // longest class string
&cValues, // number of values for this key
&maxValueLen, // longest value name
NULL, // longest value data
NULL, // security descriptor
NULL); // last write time
if(cSubKeys>0)
{
char currentSubkey[MAX_PATH];
for(int i=0;i < cSubKeys;i++){
DWORD currentSubLen=MAX_PATH;
retCode=RegEnumKeyEx(hKey, // Handle to an open/predefined key
i, // Index of the subkey to retrieve.
currentSubkey, // buffer to receives the name of the subkey
&currentSubLen, // size of that buffer
NULL, // Reserved
NULL, // buffer for class string
NULL, // size of that buffer
NULL); // last write time
if(retCode==ERROR_SUCCESS)
{
for (int i = 0; i < tabs; i++)
printf("\t");
printf("(%d) %s\n", i+1, currentSubkey);
char* subKeyPath = new char[currentSubLen + strlen(subKey)];
sprintf(subKeyPath, "%s\\%s", subKey, currentSubkey);
EnumerateSubKeys(RootKey, subKeyPath, (tabs + 1));
}
}
}
else
{
EnumerateValues(hKey, cValues);
}
RegCloseKey(hKey);
}
int main()
{
EnumerateSubKeys(HKEY_CURRENT_USER,"SOFTWARE\\Dropbox");
getchar();
return 0;
}
Your call to RegEnumValue is incorrect. It has the following problems:
You are expected to initialise valNameLen before calling the function.
You are expected to initialise dataSize before calling the function.
You fail to check the return value of RegEnumValue and thus assume that the function succeeds. And in fact it fails because you of the aforementioned errors.
Let's ignore the value for now, since that's much more complex. Let's just try and enumerate the names of the values. That code would look like this:
void EnumerateValues(HKEY hKey, DWORD numValues)
{
for (DWORD dwIndex = 0; dwIndex < numValues; dwIndex++)
{
char valueName[64];
DWORD valNameLen = sizeof(valueName);
DWORD dataType;
DWORD dataSize = 0;
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, &dataType, NULL, &dataSize);
if (retval == ERROR_SUCCESS)
{
printf("(%d) %s %d\n", dwIndex+1, valueName, dataType);
}
else
{
// handle error
}
}
}
Note also that I stopped using a dynamically allocated character array as your code did. Your code leaked that array. Obviously if you need to cope with arbitrarily large value names, then you would need to use dynamically allocated arrays.
As for extracting the data, that's a bigger task that I don't believe is in the scope of
this question. You need special code for each individual data type.
For instance, to read a REG_SZ you would use code like this:
char *data = new char [dataSize+1];
data[dataSize] = '\0';
valNameLen = sizeof(valueName);
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, NULL, (LPBYTE)data, &dataSize);
if (retval == ERROR_SUCCESS)
{
printf("(%d) %s %d %s\n", dwIndex+1, valueName, dataType, data);
}
else
{
// handle error
}
delete[] data;

Heap allocation problems

I am running into memory errors when I try to run my C++ program in Visual Studio 2012. I am thinking that this code is the cause (since when I remove it, it runs fine):
void GetMachineHash(CString &strHashHex) {
CMD5 cMD5;
BYTE *szHash = (BYTE*)malloc(48);
LPBYTE szMachineNameHash, szNetworkAddressHash, szVolumeIdHash;
TCHAR szMachineId[100];
DWORD nMachineIdLen = 100;
TCHAR szNetworkAddress[13];
IP_ADAPTER_INFO *pAdapterInfo, *pAdapter = NULL;
DWORD dwRetVal = 0;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
TCHAR szVolumeId[20];
TCHAR szVolumeName[MAX_PATH];
TCHAR szFileSystemName[MAX_PATH];
DWORD dwSerialNumber = 0;
DWORD dwMaxComponentLen = 0;
DWORD dwFileSystemFlags = 0;
ZeroMemory(szHash, 48);
ZeroMemory(szMachineId, 100);
ZeroMemory(szVolumeId, 20);
ZeroMemory(szVolumeName, MAX_PATH);
ZeroMemory(szFileSystemName, MAX_PATH);
ZeroMemory(szNetworkAddress, 13);
GetComputerName(szMachineId, &nMachineIdLen);
cMD5.Calculate(szMachineId);
szMachineNameHash = cMD5.Hash();
pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
TRACE(_T("Error allocating memory needed to call GetAdaptersinfo()"));
szNetworkAddressHash = NULL;
}
// Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
if (pAdapterInfo == NULL) {
TRACE(_T("Error allocating memory needed to call GetAdaptersinfo()"));
szNetworkAddressHash = NULL;
}
}
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
pAdapter = pAdapterInfo;
while (pAdapter) {
if (pAdapter->Type != MIB_IF_TYPE_LOOPBACK) {
_stprintf_s(szNetworkAddress, 13, _T("%.2X%.2X%.2X%.2X%.2X%.2X"),
pAdapter->Address[0],
pAdapter->Address[1],
pAdapter->Address[2],
pAdapter->Address[3],
pAdapter->Address[4],
pAdapter->Address[5]
);
break;
}
pAdapter = pAdapter->Next;
}
} else {
TRACE(_T("GetAdaptersInfo() call failed"));
szNetworkAddressHash = NULL;
}
cMD5.Calculate(szNetworkAddress);
szNetworkAddressHash = cMD5.Hash();
if (GetVolumeInformation(
NULL,
szVolumeName,
sizeof(szVolumeName),
&dwSerialNumber,
&dwMaxComponentLen,
&dwFileSystemFlags,
szFileSystemName,
sizeof(szFileSystemName))) {
_stprintf_s(szVolumeId, 20, _T("%lu"), dwSerialNumber);
}
cMD5.Calculate(szVolumeId);
szVolumeIdHash = cMD5.Hash();
// Calculate hash from hashes
memcpy(szHash, szMachineNameHash, 16);
memcpy(szHash+16, szNetworkAddressHash, 16);
memcpy(szHash+32, szVolumeIdHash, 16);
cMD5.Calculate(szHash, 48);
strHashHex.Preallocate(33);
strHashHex = cMD5.HexHash();
free(szHash);
free(pAdapterInfo);
return;
}
And then if I leave the function and just remove this code:
strHashHex.Preallocate(33);
strHashHex = cMD5.HexHash();
Then it will work fine as well. So I am wondering if that is the code that's causing the memory problems, and if it is, how can I fix it?
Here's the CMD5 class (which utilizes the Windows API to generate a MD5 sum):
class CMD5
{
public:
CMD5() {
if(CryptAcquireContext(&m_hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET) == 0){
if(GetLastError() == NTE_EXISTS){
CryptAcquireContext(&m_hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0);
}
}
}
~CMD5() {
if(m_hCryptProv)
CryptReleaseContext(m_hCryptProv, 0);
m_hCryptProv = NULL;
free(m_szHash);
}
bool Calculate(LPCTSTR szText) {
DWORD dwLen = sizeof(TCHAR) * _tcslen(szText);
DWORD dwHashLen;
DWORD dwHashLenSize = sizeof(DWORD);
if (CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &m_hHash)) {
if (CryptHashData(m_hHash, (const BYTE*)szText, dwLen, 0)) {
if (CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0)) {
if(m_szHash = (BYTE*)malloc(dwHashLen)) {
if (CryptGetHashParam(m_hHash, HP_HASHVAL, (BYTE*)m_szHash, &dwHashLen, 0)) {
CryptDestroyHash(m_hHash);
}
}
}
}
}
return false;
}
bool Calculate(const LPBYTE szText, DWORD dwLen) {
DWORD dwHashLen;
DWORD dwHashLenSize = sizeof(DWORD);
if (CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &m_hHash)) {
if (CryptHashData(m_hHash, (const BYTE*)szText, dwLen, 0)) {
if (CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0)) {
if(m_szHash = (BYTE*)malloc(dwHashLen)) {
if (CryptGetHashParam(m_hHash, HP_HASHVAL, (BYTE*)m_szHash, &dwHashLen, 0)) {
CryptDestroyHash(m_hHash);
}
}
}
}
}
return false;
}
LPBYTE Hash() const {
LPBYTE szHash = new BYTE[16];
ZeroMemory(szHash, 16);
memcpy(szHash, m_szHash, 16);
return szHash;
}
LPTSTR HexHash() const {
LPTSTR szBuf = new TCHAR[33];
ZeroMemory(szBuf, 33);
for (int i=0; i<16; i++)
_stprintf_s(szBuf+i*2, 33, _T("%02X"), m_szHash[i]);
szBuf[32]=0;
return szBuf;
}
private:
BYTE *m_szHash;
DWORD m_hHash;
HCRYPTPROV m_hCryptProv;
};
Also, the error I get from VS2012 is Critical error detected c0000374 and the call stack ends with a call to HeapAlloc() from _heap_alloc. Not sure if it matters but this code is being called in a DLL.
It looks like I was able to solve the memory allocation problems by changing the CMD5::HexHash() function to
void HexHash(CString &strHash) {
for (int i=0; i<16; i++)
strHash += StringFormat(_T("%02X"), m_szHash[i]);
return;
}
and call it via cMD5.HexHash(strHashHex);

Calling SetupDiEnumDeviceInfo causes a subsequent CreateFile to return ERROR_SHARING_VIOLATION

In the following code the call to SetupDiEnumDeviceInfo() causes the subsequent CreateFile to return ERROR_SHARING_VIOLATION instead of opening the file. I was able to pinpoint the line by commenting out the other pieces of code until I hit one line that would cause the CreateFile to fail.
String SerialATDT::getComPortId()
{
#if 1
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
String comPort = "";
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_MODEM,
0, // Enumerator
0,
DIGCF_PRESENT );
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return "";
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
int offset = 0;
while ( SetupDiEnumDeviceInfo(hDevInfo, offset++, &DeviceInfoData) )
{
DWORD DataT;
#if 1
//
// Call function with null to begin with,
// then use the returned buffer size (doubled)
// to Alloc the buffer. Keep calling until
// success or an unknown failure.
//
// Double the returned buffersize to correct
// for underlying legacy CM functions that
// return an incorrect buffersize value on
// DBCS/MBCS systems.
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (LPTSTR)LocalAlloc(LPTR,buffersize * 2);
}
else
{
// Insert error handling here.
break;
}
}
// Look for identifying info in the name
if ( mComPortIdentifier.size() > 0 ) {
const char *temp = strstr(buffer, mComPortIdentifier.c_str());
if ( temp == 0 ) {
continue;
}
}
// Now find out the port number
DWORD nSize=0 ;
TCHAR buf[MAX_PATH];
if ( SetupDiGetDeviceInstanceId(hDevInfo, &DeviceInfoData, buf, MAX_PATH, &nSize) )
{
HKEY devKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
DWORD size = 0;
DWORD type;
RegQueryValueEx(devKey, TEXT("PortName"), NULL, NULL, NULL, & size);
BYTE* buff = new BYTE[size];
String result;
if( RegQueryValueEx(devKey, TEXT("PortName"), NULL, &type, buff, & size) == ERROR_SUCCESS ) {
comPort = (char*)buff;
if ( comPort.size() > 0 ) {
RegCloseKey(devKey);
break;
}
}
RegCloseKey(devKey);
delete [] buff;
}
#else
comPort = "COM44";
#endif
}
// Cleanup
SetupDiDestroyDeviceInfoList (hDevInfo);
if (buffer) {
LocalFree(buffer);
}
if ( GetLastError()!=NO_ERROR &&
GetLastError()!=ERROR_NO_MORE_ITEMS &&
GetLastError() != ERROR_INVALID_HANDLE )
{
TRACE_L("ATDT error after free %ld", GetLastError() );
// Insert error handling here.
return "";
}
return comPort;
#else
return "COM44";
#endif
}
bool SerialATDT::getComPort(HANDLE *hFile)
{
String comPort = getComPortId();
*hFile = INVALID_HANDLE_VALUE;
if ( comPort.size() > 0 ) {
String comPortStr;
comPortStr.Format("\\\\.\\%s", comPort.c_str());
*hFile = ::CreateFile( comPortStr.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL );
if ( *hFile == INVALID_HANDLE_VALUE ) {
TRACE_L("AT file open error %ld", GetLastError());
}
}
return *hFile != INVALID_HANDLE_VALUE;
}
I have been looking but have not found a reason why the DeviceInfoData needs to be cleared (nor have I found a method to do it). Has anybody run into this before?

C++ RegEnumValue() - fail to iterate to each value

I want to get all the registry values under specific key path, but RegEnumValue() always returns back the error code 259 as ERROR_NO_MORE_ITEMS and sectionValue has nonsense value. I check the registry manually and there are values under the specified key.
For example.
key is MyTestApp
key value is ManualTestCase = 10
key value is AutomationTestCase = 50
HKEY hKey; //registry key handle
LONG lResult; //result of registry operations
DWORD dwType, dwSize=0;
//try to open the key that we are currently pointing at with rootPath
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, rootPath, NULL, KEY_ALL_ACCESS, &hKey);
if (lResult == ERROR_SUCCESS)
{
LPTSTR className = NULL;
DWORD classNameSize = MAX_PATH;
DWORD subKey = 0;
DWORD maxSubKey;
DWORD maxClass;
DWORD value;
DWORD maxValue;
DWORD maxValueData;
DWORD securityDescriptor;
FILETIME ftLastWriteTime;
DWORD sectionNameSize;
int j;
//to get total keys for the specified path
lResult = RegQueryInfoKey(hKey, className, &classNameSize, NULL,
&subKey, &maxSubKey, &maxClass, &value, &maxValue,
&maxValueData, &securityDescriptor, &ftLastWriteTime);
if(lResult == ERROR_SUCCESS)
{
for(int i = 0; i < subKey; i++)
{
LPTSTR sectionName = new TCHAR[1096];
sectionNameSize = 1096;
ftLastWriteTime.dwHighDateTime = 0;
ftLastWriteTime.dwLowDateTime = 0;
//enumerate all the registry key names for specified path
lResult = RegEnumKeyEx(hKey, i, sectionName,
&sectionNameSize, NULL, NULL,
NULL, &ftLastWriteTime);
CString testStr = sectionName;
if(lResult == ERROR_SUCCESS)
{
j = 0;
do
{
LPTSTR sectionValue;
DWORD sectionValueSize = 4096;
DWORD dwType;
//enumerate all the values for specified key
lResult = RegEnumValue(hKey, j, sectionName,
&sectionNameSize, NULL, &dwType,
(LPBYTE)sectionValue, &sectionValueSize);
//
if(lResult == ERROR_SUCCESS)
{
//do something to the data
bool whatever = true;
}
else if(lResult == ERROR_MORE_DATA)
{
//
bool yeahSure = true;
}
j++;
}while(lResult != ERROR_NO_MORE_ITEMS);
}
delete[] sectionName;
}
}
}
RegCloseKey(hKey);
My guess is your problem is with how you use lResult = RegEnumKeyEx(hKey, i, sectionName,...
You are trying to enumerate values of a subkey without actually opening that subkey.