I'm trying to inject my DLL into a 64-bit process that I just created. I initially create it suspended so that I can apply WinAPI patch trampolines in that process (from my injected DLL.) But if I understand it correctly, I cannot inject my DLL into a suspended process.
So I came up with the following code, following the guy's suggestions, but it doesn't go far. The VirtualProtectEx fails and I get an error code ERROR_INVALID_ADDRESS. I marked it in the source below.
Any idea where am I messing up?
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
si.cb = sizeof(si);
WCHAR buffer[MAX_PATH];
::StringCchCopy(buffer, _countof(buffer), L"injected-process.exe");
if(CreateProcessW(0, buffer, 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi))
{
inject_dll_into_suspended_x64_proc(pi.hProcess, pi.hThread, "injected-process.exe");
//... continue on
}
and then the code to prep process for injection:
bool inject_dll_into_suspended_x64_proc(HANDLE hProc, HANDLE hMainThread, const char* pstrProcFileName)
{
bool bRes = false;
int nOSError = NO_ERROR;
DWORD dwEntryOffset = 0;
LOADED_IMAGE li = { 0 };
if (::MapAndLoad(pstrProcFileName, NULL, &li, FALSE, TRUE))
{
dwEntryOffset = li.FileHeader->OptionalHeader.AddressOfEntryPoint;
::UnMapAndLoad(&li);
}
if(dwEntryOffset)
{
// 90 nop
// EB FE jmp self
static BYTE inject_asm_x64[] = {
0x90,
0xEB, 0xFE,
};
BYTE buffBackup[sizeof(inject_asm_x64)] = { 0 };
//Get process base addr
BYTE* pBaseAddr = (BYTE*)::VirtualAllocEx(hProc, NULL, sizeof(buffBackup), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pBaseAddr)
{
BYTE* pAddr = pBaseAddr + dwEntryOffset;
DWORD dwOldProtect = 0;
if (::VirtualProtectEx(hProc, pAddr, sizeof(buffBackup), PAGE_EXECUTE_READWRITE, &dwOldProtect)) //** FAILS: With error code: 487, or ERROR_INVALID_ADDRESS
{
__try
{
//Backup what we have there now
size_t szcbRead = 0;
if (::ReadProcessMemory(hProc, pAddr, buffBackup, sizeof(buffBackup), &szcbRead) &&
szcbRead == sizeof(buffBackup))
{
//Now write our code into entry point
size_t dwcbSzWrtn = 0;
if (WriteProcessMemory(hProc, pAddr, inject_asm_x64, sizeof(inject_asm_x64), &dwcbSzWrtn) &&
dwcbSzWrtn == sizeof(inject_asm_x64))
{
bool bIntermediateSuccess = false;
bool bThreadIsSuspended = true;
//Resume thread
if (ResumeThread(hMainThread) == 1)
{
bThreadIsSuspended = false;
CONTEXT context;
bool bReached = false;
//Wait for it to reach our JMP self opcode
for(;; ::Sleep(1))
{
if(!::GetThreadContext(hMainThread, &context))
{
//Failed
nOSError = ::GetLastError();
break;
}
if(context.Rip == (DWORD64)(pAddr + 1)) //First is nop, so skip it
{
//Got it
bReached = true;
break;
}
}
if(bReached)
{
//Do our DLL injection now
if(inject_dll_here(hProc))
{
//Injected OK
bIntermediateSuccess = true;
}
else
nOSError = ::GetLastError();
//Suspend main thread
if(::SuspendThread(hMainThread) == 0)
{
//Thread is again suspended
bThreadIsSuspended = true;
}
else
{
//Failed
nOSError = ::GetLastError();
bIntermediateSuccess = false;
}
}
}
else
nOSError = ::GetLastError();
if(bThreadIsSuspended)
{
//Revert process memory back
if (WriteProcessMemory(hProc, pAddr, buffBackup, sizeof(buffBackup), &dwcbSzWrtn) &&
dwcbSzWrtn == sizeof(buffBackup))
{
//Now restore the main thread
if (ResumeThread(hMainThread) == 1)
{
//Done
bRes = bIntermediateSuccess;
}
else
nOSError = ::GetLastError();
}
else
nOSError = ::GetLastError();
}
}
else
nOSError = ::GetLastError();
}
else
nOSError = ::GetLastError();
}
__finally
{
//Reset protection flags
::VirtualProtectEx(hProc, pAddr, sizeof(buffBackup), dwOldProtect, NULL);
}
}
else
nOSError = ::GetLastError();
//Free mem
::VirtualFreeEx(hProc, pBaseAddr, 0, MEM_RELEASE);
}
else
nOSError = ::GetLastError();
}
else
nOSError = ::GetLastError();
return bRes;
}
Related
Im making a DLL in c++ that is injected into another program.
When injecting more than once the program crashes so I want the DLL to first check if it was already injected and if so it will do some code like showing a message box or just quitting
This can be done using EnumProcessModules
BOOL isInjected() {
const char ProcessName = "Process.exe";
std::string DllName = "MyDll.dll";
DWORD dwProcessId = NULL;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)
return false;
PROCESSENTRY32 pe{};
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe))
{
do
{
if (_tcsicmp(pe.szExeFile, _T(ProcessName)) == 0)
{
dwProcessId = pe.th32ProcessID;
break;
}
} while (Process32Next(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId);
if (hProcess == NULL)
{
return false;
}
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
int amount = 0;
for (unsigned int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
std::string str1 = szModName;
if (str1.find(DllName) != std::string::npos) amount++;
}
}
if (amount >= 2) return true;
}
return false;
}
I have to upload audio chunks continuously on a HLS Server as a part of my project. I am able to upload chunks sucessfully using HTTP Put method with wininet API in C++ using following code.
bool CHTTP::HttpPut(char *szFile,int fileType)
{
bool bErrorFlag = false;
if(m_hInternet == NULL)
{
int retStatus = OpenHTTPSession();
if(retStatus < 1)
{
return true;
}
}
char szPostURL[256];
INTERNET_BUFFERS BufferIn = {0};
DWORD dwBytesRead;
DWORD dwBytesWritten;
BYTE pBuffer[350000];
BOOL bRead, bRet;
static int flag = 1;
BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );
char szLocalFilePath[256];
if(fileType == AUDIO_CHUNK)
sprintf(szLocalFilePath,"%s/%s",m_strFilePath,szFile);
else
strcpy(szLocalFilePath,szFile);
int iFileSize = 0;
if(fileType == AUDIO_CHUNK)
{
strcpy(szPostURL,m_strPostPath);
strcat(szPostURL,"/");
strcat(szPostURL,szFile);
}
else if(fileType == M3U8)
strcpy(szPostURL,m_szM3U8FileToPost);
else if(fileType == AUTO_M3U8)
strcpy(szPostURL,m_szM3U8AutoPost);
DWORD dwFlags =
INTERNET_FLAG_KEEP_CONNECTION |
INTERNET_FLAG_NO_COOKIES |
INTERNET_FLAG_NO_CACHE_WRITE |
INTERNET_FLAG_NO_UI |
INTERNET_FLAG_RELOAD |INTERNET_FLAG_SECURE;
m_hRequest = HttpOpenRequest(m_hHttpSession, (const char*)"PUT",szPostURL, "HTTP/1.1",NULL , (const char**)"*/*\0",dwFlags, 1);
if(m_hRequest==NULL)
{
bErrorFlag = true;
CloseHTTPSession();
return bErrorFlag;
}
else
{
bErrorFlag = false;
}
int num_of_try = 0;
while(num_of_try < 3)
{
char logDump[1000];
num_of_try++;
HANDLE hFile = CreateFile (szLocalFilePath, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
bErrorFlag = true;
break;
}
else if(!m_bLogFlagCreateErr)
{
m_bLogFlagCreateErr = true;
sprintf(logDump,"CreateFile success %s",szFile);
WriteLog(mLogFile,logDump);
bErrorFlag = false;
}
BufferIn.dwBufferTotal = GetFileSize (hFile, NULL);
iFileSize = BufferIn.dwBufferTotal;
if(!HttpSendRequestEx( m_hRequest, &BufferIn, NULL, HSR_INITIATE, 0))
{
bErrorFlag = true;
m_bLogFlagSend = false;
sprintf(logDump,"Error on HttpSendRequestEx %lu %s",GetLastError(),szFile);
WriteLog(mLogFile,logDump);
break;
}
else
{
bErrorFlag = false;
sprintf(logDump,"HttpSendRequest success %s",szFile);
WriteLog(mLogFile,logDump);
}
DWORD sum = 0;
int size = 0;
do
{
bRead = ReadFile (hFile, pBuffer,iFileSize,
&dwBytesRead, NULL);
if(dwBytesRead != iFileSize)
{
sprintf(logDump,"dwBytesRead %d iFileSize %d %s",dwBytesRead,iFileSize,szFile);
WriteLog(mLogFile,logDump);
}
if(dwBytesRead > 0)
{
bRet=InternetWriteFile( m_hRequest, pBuffer, dwBytesRead,
&dwBytesWritten);
while(dwBytesRead < dwBytesWritten && bRet)
{
sprintf(logDump,"dwBytesRead %d dwBytesWritten %d %s",dwBytesRead,dwBytesWritten,szFile);
WriteLog(mLogFile,logDump);
bRet=InternetWriteFile( m_hRequest, pBuffer+dwBytesWritten, dwBytesRead - dwBytesWritten ,&dwBytesWritten);
}
if(!bRet)
{
int error = GetLastError();
sprintf(logDump,"InternetWriteFile %lu %s",error,szFile);
WriteLog(mLogFile,logDump);
bErrorFlag = true;
break;
}
else
{
sprintf(logDump,"InternetWriteFile buffer success %s",szFile);
WriteLog(mLogFile,logDump);
bErrorFlag = false;
}
}
}
while (dwBytesRead == iFileSize);
CloseHandle (hFile);
if(!HttpEndRequest(m_hRequest, NULL, 0, 0))
{
int error = GetLastError();
if(error != 12032)
{
sprintf(logDump,"HttpEndRequest %lu %s",error,szFile);
WriteLog(mLogFile,logDump)
bErrorFlag = true;
break;
}
else
{
bErrorFlag = true;
continue;
}
}
else
{
sprintf(logDump,"HttpEndRequest success %s",szFile);
WriteLog(mLogFile,logDump);
DWORD dwCode, dwCodeSize;
dwCodeSize = sizeof(DWORD);
if(!HttpQueryInfo(m_hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwCode, &dwCodeSize, NULL))
{
int error = GetLastError();
char tmp[256];
sprintf(tmp,"HttpQueryfails %d %s",error, szFile);
WriteLog(mLogFile,tmp);
}
else
{
if(dwCode != 201 && dwCode != 204)
{
char tmp[256];
sprintf(tmp,"dwcode %d is not 201 or 204 %s",dwCode,szFile);
WriteLog(mLogFile,tmp);
bErrorFlag = true;
break;
}
}
bErrorFlag = false;
break;
}
}
CloseHTTPSession();
return bErrorFlag;
}
Most of the times chunks uploaded are of full size. Randomly chunks uploaded on server are not of full size as shown in following image.
sample image
In such case I am not getting any error messages, even dwBytesWritten returned by InternetWriteFile function is also correct. I am unable to understand what should I do to solve it. Any help in this regard is appreciated.
I am trying to get the base string in the DLL using EvtFormatMessage but no matter what I do its not working. The windows help page made it sound like you can use the values and valuecount parameters to change the default behavior but when I change them nothing is printed.
Another attempt I made was to go through the publishers metadata and match it with the correct eventId and version but the EvtOpenEventMetadatEnum has no items for it to iterate through for all events publishers. It works for time change events but not for other events.
This is the code I have to return the message string. hMetadata is the publisher metadata and hEvent is the event metadata
LPWSTR GetMessageString(EVT_HANDLE hMetadata, EVT_HANDLE hEvent, EVT_FORMAT_MESSAGE_FLAGS FormatId, DWORD MsgID)
{
LPWSTR pBuffer = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = ERROR_SUCCESS;
if (!fpEvtFormatMessage(hMetadata, hEvent, MsgID, 0, NULL, FormatId, dwBufferSize, pBuffer, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
// An event can contain one or more keywords. The function returns keywords
// as a list of keyword strings. To process the list, you need to know the
// size of the buffer, so you know when you have read the last string, or you
// can terminate the list of strings with a second null terminator character
// as this example does.
if ((EvtFormatMessageKeyword == FormatId))
pBuffer[dwBufferSize - 1] = L'\0';
else
dwBufferSize = dwBufferUsed;
pBuffer = (LPWSTR)malloc(dwBufferSize * sizeof(WCHAR));
if (pBuffer)
{
fpEvtFormatMessage(hMetadata, hEvent, MsgID, 0, NULL, FormatId, dwBufferSize, pBuffer, &dwBufferUsed);
// Add the second null terminator character.
if ((EvtFormatMessageKeyword == FormatId))
pBuffer[dwBufferUsed - 1] = L'\0';
}
else
{
TRACE5(_T("malloc failed\n"));
}
}
else if (ERROR_EVT_MESSAGE_NOT_FOUND == status || ERROR_EVT_MESSAGE_ID_NOT_FOUND == status)
;
else
{
TRACE5(_T("EvtFormatMessage failed with %u\n"), status);
}
}
This is the code that is supposed to match the event I have with the template event in the dll
hEvents = fpEvtOpenEventMetadataEnum(g_hMetadata, 0);
if (NULL == hEvents)
{
TRACE5(_T("EvtOpenEventMetadataEnum failed with %lu\n"), GetLastError());
goto cleanup;
}
// Enumerate the events and print each event's metadata.
while (run)
{
hEvent = fpEvtNextEventMetadata(hEvents, 0);
if (NULL == hEvent)
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
TRACE5(_T("EvtNextEventMetadata failed with %lu\n"), status);
}
break;
}
msgId = getEventID(g_hMetadata, hEvent, &tempVersion);
if (dwMsgID == msgId && tempVersion == version) {
PEVT_VARIANT pProperty = NULL; // Contains a metadata value
PEVT_VARIANT pTemp = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status2 = ERROR_SUCCESS;
if (!fpEvtGetEventMetadataProperty(hEvent, EventMetadataEventMessageID, 0, dwBufferSize, pProperty, &dwBufferUsed))
{
status2 = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status2)
{
dwBufferSize = dwBufferUsed;
pTemp = (PEVT_VARIANT)realloc(pProperty, dwBufferSize);
if (pTemp)
{
pProperty = pTemp;
pTemp = NULL;
fpEvtGetEventMetadataProperty(hEvent, EventMetadataEventMessageID, 0, dwBufferSize, pProperty, &dwBufferUsed);
}
else
{
TRACE5(_T("realloc failed\n"));
status2 = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status2 = GetLastError()))
{
TRACE5(_T("EvtGetEventMetadataProperty failed with %d\n"), GetLastError());
goto cleanup;
}
}
if (-1 == pProperty->UInt32Val)
{
*pStrNonExpLibMsg = "Message string: \n";
}
else
{
*pStrNonExpLibMsg = GetMessageString(g_hMetadata, NULL, EvtFormatMessageId, pProperty->UInt32Val);
if (pMessage)
{
free(pMessage);
}
}
run = false;
break;
}
fpEvtClose(hEvent);
hEvent = NULL;
}
cleanup:
if (hEvents)
fpEvtClose(hEvents);
if (hEvent)
fpEvtClose(hEvent);
return status;
}
DWORD getEventID(EVT_HANDLE g_hMetadata, EVT_HANDLE hEvent, DWORD *evtVersion)
{
PEVT_VARIANT pProperty = NULL; // Contains a metadata value
PEVT_VARIANT pTemp = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = ERROR_SUCCESS;
DWORD retValue = NULL;
// Get the specified metadata property. If the pProperty buffer is not big enough, reallocate the buffer.
for (int i = 0; i < 2; i++)
{
if (!fpEvtGetEventMetadataProperty(hEvent, (EVT_EVENT_METADATA_PROPERTY_ID)i, 0, dwBufferSize, pProperty, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
dwBufferSize = dwBufferUsed;
pTemp = (PEVT_VARIANT)realloc(pProperty, dwBufferSize);
if (pTemp)
{
pProperty = pTemp;
pTemp = NULL;
fpEvtGetEventMetadataProperty(hEvent, (EVT_EVENT_METADATA_PROPERTY_ID)i, 0, dwBufferSize, pProperty, &dwBufferUsed);
}
else
{
TRACE5(_T("realloc failed\n"));
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
TRACE5(_T("EvtGetEventMetadataProperty failed with %d\n"), GetLastError());
goto cleanup;
}
}
if (i == 0)
{
retValue = pProperty->UInt32Val;
}
else
{
*evtVersion = pProperty->UInt32Val;
}
RtlZeroMemory(pProperty, dwBufferUsed);
}
Pipe is being used, If server call WriteFile/ReadFile, client have to call ReadFile/WriteFile for synchronize each other.I implemented it like this.
Example :
**COMMON : **
BOOL RecvData(DWORD &dwScore)
{
DWORD dwRead = 0;
if(0 == ReadFile(g_hPipe, &dwScore, sizeof(DWORD), &dwRead, 0))
return FALSE;
if (sizeof(DWORD) != dwRead)
return FALSE;
return TRUE;
}
BOOL SendData(DWORD dwScore)
{
DWORD dwSend = 0;
if(0 == WriteFile(g_hPipe, &dwScore, sizeof(DWORD), &dwSend, 0))
return FALSE;
if (sizeof(DWORD) != dwSend)
return FALSE;
return TRUE;
}
**SERVER : **
VOID StartServerManager()
{
DWORD dwScore = 0;
while (TRUE)
{
if(FALSE == RecvData(dwScore))
continue;
//.... do something dwScore + dwSkill ...
if(FALSE == SendData(dwScore))
continue;
}
}
**CLIENT : **
#define VILLA_READ_MODE 0xDEDC
#define VILLA_WRITE_MODE 0xCDEC
VOID StartClientManager()
{
DWORD dwScore = 4;
DWORD dwMode = VILLA_WRITE_MODE;
while(TRUE)
{
switch(dwMode)
{
case VILLA_WRITE_MODE:
SendData(dwScore);
dwMode = VILLA_READ_MODE;
break;
case VILLA_READ_MODE:
RecvData(dwScore);
dwMode = VILLA_WRITE_MODE;
break;
}
}
}
If I change StartServerManager() into like this
VOID StartServerManager()
{
DWORD dwScore = 0;
while (TRUE)
{
if(FALSE == RecvData(dwScore))
continue;
//.... do something dwScore + dwSkill ...
if(FALSE == SendData(dwScore))
continue;
if(FALSE == RecvData(dwScore))
continue;
if(FALSE == RecvData(dwScore))
continue;
}
}
Function will block at ReadFile()
if(0 == ReadFile(g_hPipe, &dwScore, sizeof(DWORD), &dwRead, 0))
BOOL RecvData(DWORD &dwScore)
{
DWORD dwRead = 0;
if(0 == ReadFile(g_hPipe, &dwScore, sizeof(DWORD), &dwRead, 0))
return FALSE;
if (sizeof(DWORD) != dwRead)
return FALSE;
return TRUE;
}
Implemented with threads, too.
Is there any method pass block on ReadFile?
I thought about this...
#define VILLA_READ_MODE 0xDEDC
#define VILLA_WRITE_MODE 0xCDEC
VOID StartClientManager()
{
HANDLE hThread[2];
DWORD dwModeRead = VILLA_READ_MODE;
DWORD dwModeWrite = VILLA_WRITE_MODE;
hThread[1] = CreateThread(NULL, 0, SYNCTHREAD, &dwModeRead, 0, 0);
hThread[2] = CreateThread(NULL, 0, SYNCTHREAD, &dwModeWrite, 0, 0);
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
}
DWORD WINAPI SYNCTHREAD(DWORD &dwMode)
{
switch (dwMode)
{
case VILLA_READ_MODE:
RecvData(dwScore);
break;
case VILLA_WRITE_MODE:
SendData(dwScore);
break;
}
}
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);