Array of DWORDs - c++

I want to read multiple DWORDS and concatenate them into an array of type TCHAR. How can I do that?
At the end, array should look like a list sepparated through endline characters.
TCHAR array[MAX_PATH];
while(reading dwords)
{
lstrcat(array, dword to be concatenated);
lstrcat(array, L"\n");}
Added my code after people asking me to. I am trying to get the ID's in the same manner I get the names.
void getProcessList()
{//snapshot la toate procesele din sistem
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 proc32;
TCHAR names[MAX_PATH]; //wchar_t pentru ca folosim Unicode
char* pids=new char[200];
if(hSnap == INVALID_HANDLE_VALUE)
{
cout<<"invalid handle value error!\n";
return;
}
//setez dimensiunea structurii
proc32.dwSize = sizeof(PROCESSENTRY32);
//get info despre primul proces(se va afisa in do...while)
if(!Process32First(hSnap, &proc32))
{
cout<<"Tread32First() error!\n";
CloseHandle(hSnap);
return ;
}
wcscpy(names, L"");
//cauta in restul proceselor
//daca nr. threaduri<3, introdu in fisierul mapat
do
{
if(proc32.cntThreads < 3)
{
//cout<<"Current process id(adica programul A): "<<GetCurrentProcessId()<<"\n";
wcout<<L"Process Name: "<<proc32.szExeFile<<"\n";
cout<<"Process ID: " <<proc32.th32ProcessID<<"\n";
cout<<"Thread Count: "<<proc32.cntThreads<<"\n"<<endl;
//exclud procesul curent, nu vreau sa-l termin
//includ celelalte procese in string, separate de newline
if(GetCurrentProcessId()!=proc32.th32ProcessID)
{ // sprintf(pids,"%d",proc32.th32ProcessID);
lstrcat(names, proc32.szExeFile);
lstrcat(names, L"\n");
}
}
}while(Process32Next(hSnap, &proc32));
//afisez
wcout<<names;
//printf("asd: %d",pids);
//scriu in fisierul mapat
writeToFileMap(names);
//inchid handle la snapshot
CloseHandle(hSnap);
}

If you want to do it all with win32, use StringCchPrintf:
HRESULT hr = StringCchPrintf(names, ARRAYSIZE(names), L"%ld", proc32.th32ProcessID);
if (FAILED(hr)) {
// Handle error...
}

Related

CreateEvent initial state signaled is not signaling event

I am working on IO redirection program and i successfully created poc for it. The program spawn the child process and communicate with it using named pipes. I used Event object to get event whenever there is data on the pipe. I set the event to signaled state by default but i am not getting the event for the first time. To get the event i have to write on input pipe. When i write some command on input pipe i get the event and and get the output for the old command, not the current command(Please see the output).
below is the working code.
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <thread>
#include <string>
using namespace std;
#define input_pipe_name L"\\\\.\\pipe\\input"
#define output_pipe_name L"\\\\.\\pipe\\output"
#define process_name L"cmd.exe"
HANDLE input_pipe_handle;
HANDLE output_pipe_handle;
HANDLE input_file_handle;
HANDLE output_file_handle;
OVERLAPPED output_overlapped = { 0 };
BOOL InitHandels()
{
input_pipe_handle = CreateNamedPipe(input_pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 4096, 4096, 120000, 0);
SetHandleInformation(input_pipe_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
if (input_pipe_handle == INVALID_HANDLE_VALUE)
{
cout << "pipe creation error: " << GetLastError() << endl;
return FALSE;
}
output_pipe_handle = CreateNamedPipe(output_pipe_name, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 4096, 4096, 120000, 0);
SetHandleInformation(output_pipe_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
if (output_pipe_handle == INVALID_HANDLE_VALUE)
{
cout << "pipe creation error: " << GetLastError() << endl;
return FALSE;
}
input_file_handle = CreateFile(input_pipe_name, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (input_file_handle == INVALID_HANDLE_VALUE)
{
cout << "file creation error: " << GetLastError() << endl;
return FALSE;
}
output_file_handle = CreateFile(output_pipe_name, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (output_file_handle == INVALID_HANDLE_VALUE)
{
cout << "file creation error: " << GetLastError() << endl;
return FALSE;
}
output_overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
ConnectNamedPipe(output_pipe_handle, &output_overlapped);
}
void CreateChildProcess()
{
TCHAR szCmdline[] = L"cmd.exe";
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = output_pipe_handle;
siStartInfo.hStdOutput = output_pipe_handle;
siStartInfo.hStdInput = input_pipe_handle;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
if (!CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo))
{
cout << "process creation error: " << GetLastError() << endl;
//return FALSE;
}
else
{
HANDLE h_array[] = {output_overlapped.hEvent, piProcInfo.hProcess};
for (;;)
{
DWORD result = WaitForMultipleObjects(2, h_array, FALSE, 1000);
DWORD bwritten = 0, bread = 0;
char buffer[4096];
switch (result)
{
case WAIT_TIMEOUT:
//cout << "TimeOut" << endl;
break;
case WAIT_OBJECT_0:
ReadFile(output_file_handle, buffer, sizeof(buffer), &bread, &output_overlapped);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buffer, bread, &bwritten, 0);
ResetEvent(output_overlapped.hEvent);
break;
case WAIT_OBJECT_0 + 1:
break;
//return FALSE;
}
}
}
}
int main()
{
DWORD bwritten;
InitHandels();
//CreateChildProcess();
std::thread t1(CreateChildProcess);
for (;;Sleep(1000))
{
std::string mystring;
std::cin >> mystring;
mystring.append("\n");
WriteFile(input_file_handle, mystring.c_str(), mystring.length(), &bwritten, &output_overlapped);
//WriteFile(input_file_handle, "dir\n", 4, &bwritten, &output_overlapped);
}
t1.join();
return 0;
}
I get the following output
dir
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
D:\Programming\VS\to_post_on_stack\to_post_on_stack>hello
dir
Volume in drive D has no label.
Volume Serial Number is 54FB-7A94
Directory of D:\Programming\VS\to_post_on_stack\to_post_on_stack
01/13/2018 05:36 PM <DIR> .
01/13/2018 05:36 PM <DIR> ..
01/13/2018 05:36 PM <DIR> Debug
01/12/2018 08:54 PM 608 stdafx.cpp
01/12/2018 08:54 PM 642 stdafx.h
01/12/2018 08:54 PM 630 targetver.h
01/13/2018 05:36 PM 7,434 to_post_on_stack.cpp
01/12/2018 08:54 PM 8,038 to_post_on_stack.vcxproj
01/12/2018 08:54 PM 1,277 to_post_on_stack.vcxproj.filters
6 File(s) 18,629 bytes
3 Dir(s) 39,347,019,776 bytes free
D:\Programming\VS\to_post_on_stack\to_post_on_stack>dir
hello
'hello' is not recognized as an internal or external command,
operable program or batch file.
D:\Programming\VS\to_post_on_stack\to_post_on_stack>dir
As you can see in the output when i send dir command i get the old output. When i send hello i get the output for the dir command which i executed before hello.
SO can anyone point out the mistake that why i am not getting signal for the very first time. And why the output is not getting in sequence?
the code example full of critical bugs:
the first and main:
If hFile was opened with FILE_FLAG_OVERLAPPED, the following
conditions are in effect:
The lpOverlapped parameter must point to a valid and unique
OVERLAPPED structure, otherwise the function can incorrectly report
that the io operation is complete.
and
io operation resets the event specified by the hEvent member of the
OVERLAPPED structure to a nonsignaled state when it begins the I/O
operation. Therefore, the caller does not need to do that.
when io operation is complete - io subsystem write to lpOverlapped final status of operation, number of bytes transferred, and if it containing event - set this event to signal state. if you use the same lpOverlapped in concurrent - they overwrite result each other, and you never know - which operation is really complete - event is one, common !, also if you use event - system reset event before begin io - as result - one operation can complete and set event, then another operation reset it after this
you call in 2 threads in concurrent:
WriteFile(input_file_handle, ..&output_overlapped);
ReadFile(output_file_handle, .. &output_overlapped);
with this you already have UB because the same &output_overlapped used in concurrent. we need allocate unique overlapped to every operation. and if you use events for detect completion - you need create several events - this is not good way at all. much better use iocp completion here - we not need create events, we not need create separate thread.
ReadFile(output_file_handle, buffer, sizeof(buffer), &bread, &output_overlapped);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buffer, bread, &bwritten, 0);
ResetEvent(output_overlapped.hEvent);
at first ReadFile resets the event specified by the hEvent member of the OVERLAPPED structure to a nonsignaled state when it begins the I/O operation. Therefore, the caller does not need to do that. and more - when you call ResetEvent - operation can be already completed - so you reset already signaled event - and as result you lost completion signal. if call ReasetEvent this need do before io operation (ReadFile in concrete case) but not after - which is error. however we not need do this and before - because io subsystem anyway do this.
else one critical bug - we can not use buffer, breadin WriteFile just after asynchronous call to ReadFile - the call is can be not completed yet. and context of buffer yet not defined.
the &bread is undefined always in asynchronous call and must not be used at all
The lpNumberOfBytesRead parameter should be set to NULL. Use the
GetOverlappedResult function to get the actual number of bytes read.
If the hFile parameter is associated with an I/O completion port,
you can also get the number of bytes read by calling the
GetQueuedCompletionStatus function.
else one very common mistake - that we create 2 pipe pairs (input_pipe_handle, output_file_handle) - this is absolute not need - we can use the 1 pipe pair.
the call to SetHandleInformation excess - we need just create handle with inherit properties via SECURITY_ATTRIBUTES.
code example:
//#define _XP_SUPPORT_
struct IO_COUNT
{
HANDLE _hFile;
HANDLE _hEvent;
LONG _dwIoCount;
IO_COUNT()
{
_dwIoCount = 1;
_hEvent = 0;
}
~IO_COUNT()
{
if (_hEvent)
{
CloseHandle(_hEvent);
}
}
ULONG Create(HANDLE hFile);
void BeginIo()
{
InterlockedIncrement(&_dwIoCount);
}
void EndIo()
{
if (!InterlockedDecrement(&_dwIoCount))
{
SetEvent(_hEvent);
}
}
void Wait()
{
WaitForSingleObject(_hEvent, INFINITE);
}
};
class U_IRP : OVERLAPPED
{
enum { connect, read, write };
IO_COUNT* _pIoObject;
ULONG _code;
LONG _dwRef;
char _buffer[256];
~U_IRP()
{
_pIoObject->EndIo();
}
ULONG Read()
{
_code = read;
AddRef();
return CheckIoResult(ReadFile(_pIoObject->_hFile, _buffer, sizeof(_buffer), 0, this));
}
ULONG CheckIoResult(BOOL fOk)
{
if (fOk)
{
#ifndef _XP_SUPPORT_
OnIoComplete(NOERROR, InternalHigh);
#endif
return NOERROR;
}
ULONG dwErrorCode = GetLastError();
if (dwErrorCode != ERROR_IO_PENDING)
{
OnIoComplete(dwErrorCode, 0);
}
return dwErrorCode;
}
VOID OnIoComplete(DWORD dwErrorCode, DWORD_PTR dwNumberOfBytesTransfered)
{
switch (_code)
{
case connect:
switch (dwErrorCode)
{
case ERROR_PIPE_CONNECTED:
case ERROR_NO_DATA:
dwErrorCode = NOERROR;
case NOERROR:
Read();
}
break;
case read:
if (dwErrorCode == NOERROR)
{
if (dwNumberOfBytesTransfered)
{
if (int cchWideChar = MultiByteToWideChar(CP_OEMCP, 0, _buffer, (ULONG)dwNumberOfBytesTransfered, 0, 0))
{
PWSTR wz = (PWSTR)alloca(cchWideChar * sizeof(WCHAR));
if (MultiByteToWideChar(CP_OEMCP, 0, _buffer, (ULONG)dwNumberOfBytesTransfered, wz, cchWideChar))
{
if (int cbMultiByte = WideCharToMultiByte(CP_ACP, 0, wz, cchWideChar, 0, 0, 0, 0))
{
PSTR sz = (PSTR)alloca(cbMultiByte);
if (WideCharToMultiByte(CP_ACP, 0, wz, cchWideChar, sz, cbMultiByte, 0, 0))
{
DbgPrint("%.*s", cbMultiByte, sz);
}
}
}
}
}
Read();
}
break;
case write:
break;
default:
__debugbreak();
}
Release();
if (dwErrorCode)
{
DbgPrint("[%u]: error=%u\n", _code, dwErrorCode);
}
}
static VOID WINAPI _OnIoComplete(
DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped
)
{
static_cast<U_IRP*>(lpOverlapped)->OnIoComplete(RtlNtStatusToDosError(dwErrorCode), dwNumberOfBytesTransfered);
}
public:
void AddRef()
{
InterlockedIncrement(&_dwRef);
}
void Release()
{
if (!InterlockedDecrement(&_dwRef)) delete this;
}
U_IRP(IO_COUNT* pIoObject) : _pIoObject(pIoObject)
{
_dwRef = 1;
pIoObject->BeginIo();
RtlZeroMemory(static_cast<OVERLAPPED*>(this), sizeof(OVERLAPPED));
}
ULONG Write(const void* pvBuffer, ULONG cbBuffer)
{
_code = write;
AddRef();
return CheckIoResult(WriteFile(_pIoObject->_hFile, pvBuffer, cbBuffer, 0, this));
}
ULONG Connect()
{
_code = connect;
AddRef();
return CheckIoResult(ConnectNamedPipe(_pIoObject->_hFile, this));
}
static ULONG Bind(HANDLE hFile)
{
return BindIoCompletionCallback(hFile, U_IRP::_OnIoComplete, 0)
#ifndef _XP_SUPPORT_
&& SetFileCompletionNotificationModes(hFile, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)
#endif
? NOERROR : GetLastError();
}
};
ULONG IO_COUNT::Create(HANDLE hFile)
{
_hFile = hFile;
if (_hEvent = CreateEvent(0, TRUE, FALSE, 0))
{
return U_IRP::Bind(hFile);
}
return GetLastError();
}
void ChildTest()
{
static const WCHAR name[] = L"\\\\?\\pipe\\somename";
HANDLE hFile = CreateNamedPipeW(name,
PIPE_ACCESS_DUPLEX|FILE_READ_DATA|FILE_WRITE_DATA|FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE, 1, 0, 0, NMPWAIT_USE_DEFAULT_WAIT, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
IO_COUNT obj;
if (obj.Create(hFile) == NOERROR)
{
BOOL fOk = FALSE;
static SECURITY_ATTRIBUTES sa = { sizeof(sa), 0, TRUE };
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdError = CreateFileW(name, FILE_GENERIC_READ|FILE_GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0);
if (si.hStdError != INVALID_HANDLE_VALUE)
{
si.hStdInput = si.hStdOutput = si.hStdError;
WCHAR ApplicationName[MAX_PATH];
if (GetEnvironmentVariableW(L"ComSpec", ApplicationName, RTL_NUMBER_OF(ApplicationName)))
{
if (CreateProcessW(ApplicationName , 0, 0, 0, TRUE, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
fOk = TRUE;
}
}
CloseHandle(si.hStdError);
}
if (fOk)
{
U_IRP* p;
if (p = new U_IRP(&obj))
{
p->Connect();
p->Release();
}
obj.EndIo();
//++ simulate user commands
static PCSTR commands[] = { "dir\r\n", "ver\r\n", "exit\r\n" };
ULONG n = RTL_NUMBER_OF(commands);
PCSTR* psz = commands;
do
{
if (p = new U_IRP(&obj))
{
PCSTR command = *psz++;
p->Write(command, (ULONG)strlen(command) * sizeof(CHAR));
p->Release();
}
} while (--n);
//--
obj.Wait();
}
}
CloseHandle(hFile);
}
}

How to retrieve information from multiple/dual code signatures on an executable file

I've been using the following code (taken from KB323809 article) to retrieve information about the code signature on the executable file. This works fine for a single digital signature.
But how to retrieve information for multiple code signatures?
In that case the Microsoft code below simply retrives info only for the first signature.
My thought was to call CryptMsgGetParam with CMSG_SIGNER_COUNT_PARAM to get the number of signatures and then pass each signature index to the subsequent call to CryptMsgGetParam with CMSG_SIGNER_INFO_PARAM (in the code below.) But this approach always returns 1 signature, even if I clearly have more, like 3 in this example:
#include <windows.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <stdio.h>
#include <tchar.h>
#pragma comment(lib, "crypt32.lib")
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
typedef struct {
LPWSTR lpszProgramName;
LPWSTR lpszPublisherLink;
LPWSTR lpszMoreInfoLink;
} SPROG_PUBLISHERINFO, *PSPROG_PUBLISHERINFO;
BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
PSPROG_PUBLISHERINFO Info);
BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st);
BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext);
BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo,
PCMSG_SIGNER_INFO *pCounterSignerInfo);
int _tmain(int argc, TCHAR *argv[])
{
WCHAR szFileName[MAX_PATH];
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PCCERT_CONTEXT pCertContext = NULL;
BOOL fResult;
DWORD dwEncoding, dwContentType, dwFormatType;
PCMSG_SIGNER_INFO pSignerInfo = NULL;
PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
DWORD dwSignerInfo;
CERT_INFO CertInfo;
SPROG_PUBLISHERINFO ProgPubInfo;
SYSTEMTIME st;
ZeroMemory(&ProgPubInfo, sizeof(ProgPubInfo));
__try
{
if (argc != 2)
{
_tprintf(_T("Usage: SignedFileInfo <filename>\n"));
return 0;
}
#ifdef UNICODE
lstrcpynW(szFileName, argv[1], MAX_PATH);
#else
if (mbstowcs(szFileName, argv[1], MAX_PATH) == -1)
{
printf("Unable to convert to unicode.\n");
__leave;
}
#endif
// Get message handle and store handle from the signed file.
fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
szFileName,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
&dwEncoding,
&dwContentType,
&dwFormatType,
&hStore,
&hMsg,
NULL);
if (!fResult)
{
_tprintf(_T("CryptQueryObject failed with %x\n"), GetLastError());
__leave;
}
// Get signer information size.
fResult = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
NULL,
&dwSignerInfo);
if (!fResult)
{
_tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
__leave;
}
// Allocate memory for signer information.
pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
if (!pSignerInfo)
{
_tprintf(_T("Unable to allocate memory for Signer Info.\n"));
__leave;
}
// Get Signer Information.
fResult = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
(PVOID)pSignerInfo,
&dwSignerInfo);
if (!fResult)
{
_tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
__leave;
}
// Get program name and publisher information from
// signer info structure.
if (GetProgAndPublisherInfo(pSignerInfo, &ProgPubInfo))
{
if (ProgPubInfo.lpszProgramName != NULL)
{
wprintf(L"Program Name : %s\n",
ProgPubInfo.lpszProgramName);
}
if (ProgPubInfo.lpszPublisherLink != NULL)
{
wprintf(L"Publisher Link : %s\n",
ProgPubInfo.lpszPublisherLink);
}
if (ProgPubInfo.lpszMoreInfoLink != NULL)
{
wprintf(L"MoreInfo Link : %s\n",
ProgPubInfo.lpszMoreInfoLink);
}
}
_tprintf(_T("\n"));
// Search for the signer certificate in the temporary
// certificate store.
CertInfo.Issuer = pSignerInfo->Issuer;
CertInfo.SerialNumber = pSignerInfo->SerialNumber;
pCertContext = CertFindCertificateInStore(hStore,
ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo,
NULL);
if (!pCertContext)
{
_tprintf(_T("CertFindCertificateInStore failed with %x\n"),
GetLastError());
__leave;
}
// Print Signer certificate information.
_tprintf(_T("Signer Certificate:\n\n"));
PrintCertificateInfo(pCertContext);
_tprintf(_T("\n"));
// Get the timestamp certificate signerinfo structure.
if (GetTimeStampSignerInfo(pSignerInfo, &pCounterSignerInfo))
{
// Search for Timestamp certificate in the temporary
// certificate store.
CertInfo.Issuer = pCounterSignerInfo->Issuer;
CertInfo.SerialNumber = pCounterSignerInfo->SerialNumber;
pCertContext = CertFindCertificateInStore(hStore,
ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo,
NULL);
if (!pCertContext)
{
_tprintf(_T("CertFindCertificateInStore failed with %x\n"),
GetLastError());
__leave;
}
// Print timestamp certificate information.
_tprintf(_T("TimeStamp Certificate:\n\n"));
PrintCertificateInfo(pCertContext);
_tprintf(_T("\n"));
// Find Date of timestamp.
if (GetDateOfTimeStamp(pCounterSignerInfo, &st))
{
_tprintf(_T("Date of TimeStamp : %02d/%02d/%04d %02d:%02d\n"),
st.wMonth,
st.wDay,
st.wYear,
st.wHour,
st.wMinute);
}
_tprintf(_T("\n"));
}
}
__finally
{
// Clean up.
if (ProgPubInfo.lpszProgramName != NULL)
LocalFree(ProgPubInfo.lpszProgramName);
if (ProgPubInfo.lpszPublisherLink != NULL)
LocalFree(ProgPubInfo.lpszPublisherLink);
if (ProgPubInfo.lpszMoreInfoLink != NULL)
LocalFree(ProgPubInfo.lpszMoreInfoLink);
if (pSignerInfo != NULL) LocalFree(pSignerInfo);
if (pCounterSignerInfo != NULL) LocalFree(pCounterSignerInfo);
if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
if (hStore != NULL) CertCloseStore(hStore, 0);
if (hMsg != NULL) CryptMsgClose(hMsg);
}
return 0;
}
BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext)
{
BOOL fReturn = FALSE;
LPTSTR szName = NULL;
DWORD dwData;
__try
{
// Print Serial Number.
_tprintf(_T("Serial Number: "));
dwData = pCertContext->pCertInfo->SerialNumber.cbData;
for (DWORD n = 0; n < dwData; n++)
{
_tprintf(_T("%02x "),
pCertContext->pCertInfo->SerialNumber.pbData[dwData - (n + 1)]);
}
_tprintf(_T("\n"));
// Get Issuer name size.
if (!(dwData = CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG,
NULL,
NULL,
0)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// Allocate memory for Issuer name.
szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
if (!szName)
{
_tprintf(_T("Unable to allocate memory for issuer name.\n"));
__leave;
}
// Get Issuer name.
if (!(CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG,
NULL,
szName,
dwData)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// print Issuer name.
_tprintf(_T("Issuer Name: %s\n"), szName);
LocalFree(szName);
szName = NULL;
// Get Subject name size.
if (!(dwData = CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
NULL,
0)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// Allocate memory for subject name.
szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
if (!szName)
{
_tprintf(_T("Unable to allocate memory for subject name.\n"));
__leave;
}
// Get subject name.
if (!(CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
szName,
dwData)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// Print Subject Name.
_tprintf(_T("Subject Name: %s\n"), szName);
fReturn = TRUE;
}
__finally
{
if (szName != NULL) LocalFree(szName);
}
return fReturn;
}
LPWSTR AllocateAndCopyWideString(LPCWSTR inputString)
{
LPWSTR outputString = NULL;
outputString = (LPWSTR)LocalAlloc(LPTR,
(wcslen(inputString) + 1) * sizeof(WCHAR));
if (outputString != NULL)
{
lstrcpyW(outputString, inputString);
}
return outputString;
}
BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
PSPROG_PUBLISHERINFO Info)
{
BOOL fReturn = FALSE;
PSPC_SP_OPUS_INFO OpusInfo = NULL;
DWORD dwData;
BOOL fResult;
__try
{
// Loop through authenticated attributes and find
// SPC_SP_OPUS_INFO_OBJID OID.
for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
{
// Get Size of SPC_SP_OPUS_INFO structure.
fResult = CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
NULL,
&dwData);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
// Allocate memory for SPC_SP_OPUS_INFO structure.
OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData);
if (!OpusInfo)
{
_tprintf(_T("Unable to allocate memory for Publisher Info.\n"));
__leave;
}
// Decode and get SPC_SP_OPUS_INFO structure.
fResult = CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
OpusInfo,
&dwData);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
// Fill in Program Name if present.
if (OpusInfo->pwszProgramName)
{
Info->lpszProgramName =
AllocateAndCopyWideString(OpusInfo->pwszProgramName);
}
else
Info->lpszProgramName = NULL;
// Fill in Publisher Information if present.
if (OpusInfo->pPublisherInfo)
{
switch (OpusInfo->pPublisherInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
Info->lpszPublisherLink =
AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
Info->lpszPublisherLink =
AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszFile);
break;
default:
Info->lpszPublisherLink = NULL;
break;
}
}
else
{
Info->lpszPublisherLink = NULL;
}
// Fill in More Info if present.
if (OpusInfo->pMoreInfo)
{
switch (OpusInfo->pMoreInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
Info->lpszMoreInfoLink =
AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
Info->lpszMoreInfoLink =
AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszFile);
break;
default:
Info->lpszMoreInfoLink = NULL;
break;
}
}
else
{
Info->lpszMoreInfoLink = NULL;
}
fReturn = TRUE;
break; // Break from for loop.
} // lstrcmp SPC_SP_OPUS_INFO_OBJID
} // for
}
__finally
{
if (OpusInfo != NULL) LocalFree(OpusInfo);
}
return fReturn;
}
BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st)
{
BOOL fResult;
FILETIME lft, ft;
DWORD dwData;
BOOL fReturn = FALSE;
// Loop through authenticated attributes and find
// szOID_RSA_signingTime OID.
for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if (lstrcmpA(szOID_RSA_signingTime,
pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
{
// Decode and get FILETIME structure.
dwData = sizeof(ft);
fResult = CryptDecodeObject(ENCODING,
szOID_RSA_signingTime,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
(PVOID)&ft,
&dwData);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
break;
}
// Convert to local time.
FileTimeToLocalFileTime(&ft, &lft);
FileTimeToSystemTime(&lft, st);
fReturn = TRUE;
break; // Break from for loop.
} //lstrcmp szOID_RSA_signingTime
} // for
return fReturn;
}
BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, PCMSG_SIGNER_INFO *pCounterSignerInfo)
{
PCCERT_CONTEXT pCertContext = NULL;
BOOL fReturn = FALSE;
BOOL fResult;
DWORD dwSize;
__try
{
*pCounterSignerInfo = NULL;
// Loop through unathenticated attributes for
// szOID_RSA_counterSign OID.
for (DWORD n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++)
{
if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId,
szOID_RSA_counterSign) == 0)
{
// Get size of CMSG_SIGNER_INFO structure.
fResult = CryptDecodeObject(ENCODING,
PKCS7_SIGNER_INFO,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
0,
NULL,
&dwSize);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
// Allocate memory for CMSG_SIGNER_INFO.
*pCounterSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSize);
if (!*pCounterSignerInfo)
{
_tprintf(_T("Unable to allocate memory for timestamp info.\n"));
__leave;
}
// Decode and get CMSG_SIGNER_INFO structure
// for timestamp certificate.
fResult = CryptDecodeObject(ENCODING,
PKCS7_SIGNER_INFO,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
0,
(PVOID)*pCounterSignerInfo,
&dwSize);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
fReturn = TRUE;
break; // Break from for loop.
}
}
}
__finally
{
// Clean up.
if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
}
return fReturn;
}
In addition to the answer of Daniel Sie.
Found an attribute (szOID_NESTED_SIGNATURE) that would contain the CMSG_SIGNER_INFO that need to be decoded with following steps (this is Delphi code but sense is clear):
LNestedMsg := CryptMsgOpenToDecode(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, 0, 0, 0, nil, 0);
CryptMsgUpdate(LNestedMsg, LFindedAttr.rgValue.pbData, LFindedAttr.rgValue.cbData, True);
CryptMsgGetParam(LNestedMsg, CMSG_SIGNER_INFO_PARAM, 0, nil, #LSize);
CryptMsgGetParam(LNestedMsg, CMSG_SIGNER_INFO_PARAM, 0, LNestedSignerInfo, #LSize);
The acquired CMSG_SIGNER_INFO (LNestedSignerInfo) is the nested signature (in our case SHA2 signature).
To obtain the time-stamp information (RFC3161) of that signature - search the Unauthenticated attribute with pszObjId = szOID_RFC3161_counterSign (1.3.6.1.4.1.311.3.3.1).
Found attribute would contain the CMSG_SIGNER_INFO of the time-stamp counter signature, that also need to be decoded by previously described steps (CryptMsgOpenToDecode, CryptMsgUpdate, CryptMsgGetParam).
The CERT_CONTEXT of nested signature or timestamp counter signature is need to be searched in store with is obtained from corresponding HCRYPTMSG (result of CryptMsgOpenToDecode).
LNestedStore := CertOpenStore(CERT_STORE_PROV_MSG, PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, 0, 0, LNestedMsg);
LTimeStampStore := CertOpenStore(CERT_STORE_PROV_MSG, PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, 0, 0, LTimeStampMsg);
Example to decode szOID_RFC3161_counterSign attribute:
LNestedSignerAttr := LNestedSigner.UnauthAttrs.rgAttr;
for I := 0 to LNestedSigner.UnauthAttrs.cAttr - 1 do
begin
if SameText(string(LNestedSignerAttr.pszObjId), szOID_RFC3161_counterSign) then
begin
LNestedTimeStampMsg := CryptMsgOpenToDecode(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, 0, 0, 0, nil, nil);
if not Assigned(LNestedTimeStampMsg) then
RaiseLastOSError;
try
if not CryptMsgUpdate(LNestedTimeStampMsg, LNestedSignerAttr.rgValue.pbData, LNestedSignerAttr.rgValue.cbData, True) then
RaiseLastOSError;
if not CryptMsgGetParam(LNestedTimeStampMsg, CMSG_SIGNER_INFO_PARAM, 0, nil, #LSize) then
RaiseLastOSError;
GetMem(LTimeStampSigner, LSize);
try
if not CryptMsgGetParam(LNestedTimeStampMsg, CMSG_SIGNER_INFO_PARAM, 0, LTimeStampSigner, #LSize) then
RaiseLastOSError;
LAttr := LTimeStampSigner.AuthAttrs.rgAttr;
for J := 0 to LTimeStampSigner.AuthAttrs.cAttr - 1 do
begin
if SameText(string(LAttr.pszObjId), szOID_RSA_signingTime) then
begin
LSize := SizeOf(LFileTime);
if not CryptDecodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
szOID_RSA_signingTime, LAttr.rgValue.pbData, LAttr.rgValue.cbData, 0, #LFileTime, #LSize) then
RaiseLastOSError;
if FileTimeToLocalFileTime(#LFileTime, LLocalFileTime)
and FileTimeToSystemTime(#LLocalFileTime, LSystemTime) then
SHA2TimeStamp := SystemTimeToDateTime(LSystemTime)
else
SHA2TimeStamp := 0;
end;
Inc(LAttr);
end;
finally
FreeMem(LTimeStampSigner);
end;
finally
if not CryptMsgClose(LNestedTimeStampMsg) then
RaiseLastOSError;
end;
end;
Inc(LNestedSignerAttr);
end;
Authenticode stores secondary signatures in the UnauthenticatedAttributes of primary signer (index 0), instead of additional PKCS 7 signer.
From the primary signature, search the UnauthenticatedAttribue for below:
//Indicates the attribute is an octet encoded PKCS7
define szOID_NESTED_SIGNATURE "1.3.6.1.4.1.311.2.4.1"
The encoded object of this attribute is a full PKCS 7 signer.
Thanks.

How to convert WCHAR* to string in C++ and vice versa?

I tried to convert wchar* to string. First I made it as wstring. This method is specified in stackoverflow when I search. But it doesn't work for my part. What's wrong with it?
GetProcessImageNameFromPID.cpp
BOOL GetProcessImageNameFromPID::getProcessNameFromProcessID(DWORD processId, WCHAR**processName)
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
printError(TEXT("CreateToolhelp32Snapshot (of processes)"));
return(FALSE);
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof(PROCESSENTRY32);
// Retrieve information about the first process,
// and exit if unsuccessful
if (!Process32First(hProcessSnap, &pe32))
{
printError(TEXT("Process32First")); // show cause of failure
CloseHandle(hProcessSnap); // clean the snapshot object
return(FALSE);
}
// Now walk the snapshot of processes, and
// display information about each process in turn
int i = 0;
do
{
WCHAR*allprocessName = pe32.szExeFile;
//_tprintf( TEXT("\n%d)PROCESS NAME: %s"), i, allprocessName);
// Retrieve the priority class.
dwPriorityClass = 0;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
if (hProcess == NULL)
printError(TEXT("OpenProcess"));
else
{
dwPriorityClass = GetPriorityClass(hProcess);
if (!dwPriorityClass)
printError(TEXT("GetPriorityClass"));
CloseHandle(hProcess);
}
DWORD pid = pe32.th32ProcessID;
//_tprintf( TEXT("\n Process ID = %d"), pid );
if (pid == processId)
{
*processName = allprocessName;
//_tprintf( TEXT("Inside Method:\n"));
_tprintf(TEXT("PROCESS NAME: %s\n\n"), *processName);
return TRUE;
}
i++;
} while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
return(FALSE);
}
int _tmain(int argc, _TCHAR* argv[])
{
WCHAR**processName = (WCHAR**)malloc(sizeof(WCHAR));
GetProcessImageNameFromPID::getProcessNameFromProcessID(4, processName);
_tprintf(TEXT("PROCESS NAME: %s\n\n"), *processName); // correct
GetProcessImageNameFromPID::getProcessNameFromProcessID(executionProcessID, processName);
wstring ws(*processName);
string str(ws.begin(), ws.end());
processImageName = str;
cout << processImageName << endl; // some wrong characters are printed
}
There are various problems with your code, the last one is the most serious:
This looks strange:
WCHAR**processName = (WCHAR**)malloc(sizeof(WCHAR));
I suppose you want a pointer to WCHAR*, why dont you:
WCHAR* processName;
and then:
GetProcessImageNameFromPID::getProcessNameFromProcessID(4, &processName);
^~~~~ !!
What is the type of processImageName? What is the name of the process, if it contains non ASCII chars then your conversion code will give wrong characters.
Another is that code:
*processName = allprocessName;
is making *processName equal to pointer which is dangling pointer after your function ends, it points to WCHAR array in:
PROCESSENTRY32 pe32;
which is created on stack.
What you should do is make processName an array:
WCHAR processName[MAX_PATH];
and inside your function copy process name from pe32 to this array.

Is there a way to check which process is recieving User input?

Is there a way to check which process is receiving user input from a complete list of all running processes? For example:
PROCESSENTRY32 procentry;
HANDLE hproc;
BOOL retval, ProcFound = false;
hproc = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //GetsSnapshotOfAllProcesses
if(hproc == INVALID_HANDLE_VALUE)
{ // If Couldnt get snapshot
MessageBox(NULL, "Unable To Get Snapshot", "LoaderError", MB_OK);
return false;
}
procentry.dwSize = sizeof(PROCESSENTRY32); // Initialize
retval = Process32First(hproc, &procentry); //Copies Snapshot procentry
while(retval)
{
**if(UserInput == TRUE))**
{
return procentry.th32ProcessID; //
}
retval = Process32Next(hproc, &procentry); //
}
return 0;
}
Is there a function that will let me check which process is receiving user input?
if(UserInput == TRUE))
Also, is there a way to translate the processes to a string?
GetForegroundWindow() and GetWindowThreadProcessId() is the way to go:
DWORD dwProcessID = 0;
HWND hFGWnd = GetForegroundWindow();
if (hFGWnd != NULL)
GetWindowThreadProcessId(hFGWnd, &dwProcessID);
return dwProcessID;

C++: Get MAC address of network adapters on Vista?

We are currently using the NetBios method, and it works ok under XP. Preliminary tests under Vista show that it also works, but there are caveats - NetBIOS has to be present, for instance, and from what I've been reading, the order of the adapters is bound to change. Our alternative method - with SNMPExtensionQuery - seems to be broken under Vista.
The question is: do you know of a reliable way to get a list of the local MAC addresses on a Vista machine? Backwards compatibility with XP is a plus (I'd rather have one single method than lots of ugly #ifdef's). Thanks!
This will give you a list of all MAC addresses on your computer. It will work with all versions of Windows as well:
void getdMacAddresses(std::vector<std::string> &vMacAddresses;)
{
vMacAddresses.clear();
IP_ADAPTER_INFO AdapterInfo[32]; // Allocate information for up to 32 NICs
DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
DWORD dwStatus = GetAdaptersInfo( // Call GetAdapterInfo
AdapterInfo, // [out] buffer to receive data
&dwBufLen); // [in] size of receive data buffer
//No network card? Other error?
if(dwStatus != ERROR_SUCCESS)
return;
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
char szBuffer[512];
while(pAdapterInfo)
{
if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)
{
sprintf_s(szBuffer, sizeof(szBuffer), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x"
, pAdapterInfo->Address[0]
, pAdapterInfo->Address[1]
, pAdapterInfo->Address[2]
, pAdapterInfo->Address[3]
, pAdapterInfo->Address[4]
, pAdapterInfo->Address[5]
);
vMacAddresses.push_back(szBuffer);
}
pAdapterInfo = pAdapterInfo->Next;
}
}
Could you use the WMIService? I used it to get the mac-address of a machine in pre-Vista days though.
Old question, already answered, but this is safer code - in case WMI can't be fully initialized.
For getting access to information about your system, here is a minimalist class that tries to stay safe:
NOTE: ToString, convertToUtf8 and convertFromUtf8 are left as an exercise for the reader. :)
NOTE: I've just shown the safe initialization and tear-down of the WMI system, and the basics of getting values from WMI, and getting the MAC Addresses (the question in the OP).
This came from working code, but was modified as I pasted it in here. So it is possible other things got left out that ought to have been included. Oops.
class WmiAccessor
{
public:
WmiAccessor()
: _pWbemLocator(NULL)
, _pWbemServices(NULL)
, _com_initialized(false)
, _com_need_uninitialize(false)
, _svc_initialized(false)
, _loc_initialized(false)
, _all_initialized(false)
, _errors("")
, m_mutex()
{
HRESULT hr;
hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
switch (hr)
{
case S_OK:
// The COM library was initialized successfully on this thread.
_com_initialized = true;
_com_need_uninitialize = true;
break;
case S_FALSE:
// The COM library is already initialized on this thread.
_com_initialized = true;
_com_need_uninitialize = true;
break;
case RPC_E_CHANGED_MODE:
// A previous call to CoInitializeEx specified the concurrency model
// for this thread as multithread apartment (MTA).
// This could also indicate that a change from neutral-threaded apartment to
// single-threaded apartment has occurred.
_com_initialized = true;
_com_need_uninitialize = false;
break;
default:
_com_initialized = false;
_com_need_uninitialize = false;
_errors += "Failed to initialize COM.\r\n";
return;
}
hr = ::CoInitializeSecurity(NULL, -1, NULL, NULL,
0 /*RPC_C_AUTHN_LEVEL_DEFAULT*/,
3 /*RPC_C_IMP_LEVEL_IMPERSONATE*/,
NULL, EOAC_NONE, NULL);
// RPC_E_TOO_LATE == Security must be initialized before!
// It cannot be changed once initialized. I don't care!
if (FAILED(hr) && (hr != RPC_E_TOO_LATE))
{
_errors += "Failed to initialize COM Security.\r\n";
if (_com_need_uninitialize)
{
::CoUninitialize();
_com_need_uninitialize = false;
}
return;
}
hr = _pWbemLocator.CoCreateInstance(CLSID_WbemLocator);
if (FAILED(hr) || (_pWbemLocator == nullptr))
{
_errors += "Failed to initialize WBEM Locator.\r\n";
return;
}
_loc_initialized = true;
hr = _pWbemLocator->ConnectServer(
CComBSTR(L"root\\cimv2"), NULL, NULL, 0, NULL, 0, NULL, &_pWbemServices);
if (FAILED(hr) || (_pWbemServices == nullptr))
{
_errors += "Failed to connect WBEM Locator.\r\n";
_pWbemLocator.Release();
_loc_initialized = false;
return;
}
else
{
_svc_initialized = true;
// Set security Levels on the proxy
hr = CoSetProxyBlanket(_pWbemServices,
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(hr))
{
_errors += "Failed to set proxy blanket.\r\n";
return;
}
}
_all_initialized = true;
}
~WmiAccessor()
{
std::unique_lock<std::mutex> slock(m_mutex);
if (_svc_initialized)
{
if (_pWbemServices)
_pWbemServices.Release();
_svc_initialized = false;
}
if (_loc_initialized)
{
if (_pWbemLocator)
_pWbemLocator.Release();
_loc_initialized = false;
}
if (_com_initialized)
{
if (_com_need_uninitialize)
{
::CoUninitialize();
}
_com_initialized = false;
_com_need_uninitialize = false;
}
_all_initialized = false;
}
// public: must lock
std::string get_and_clear_errors()
{
std::string result = "";
std::unique_lock<std::mutex> slock(m_mutex);
std::swap(result, _errors);
return result;
}
// public: must lock
std::string get_string(const std::string& name, const std::string& dflt /*= ""*/)
{
std::unique_lock<std::mutex> slock(m_mutex);
return _all_initialized ? _string(name) : dflt;
}
// public: must lock
uint32_t get_uint32(const std::string& name, uint32_t dflt /*= 0*/)
{
std::unique_lock<std::mutex> slock(m_mutex);
return _all_initialized ? _uint32(name) : dflt;
}
// similarly for other public accessors of basic types.
private:
CComPtr<IWbemLocator> _pWbemLocator;
CComPtr<IWbemServices> _pWbemServices;
volatile bool _com_initialized;
volatile bool _com_need_uninitialize;
volatile bool _svc_initialized;
volatile bool _loc_initialized;
volatile bool _all_initialized;
std::string _errors;
CComVariant _variant(const std::wstring& name);
std::string _string(const std::string& name);
uint32_t _uint32(const std::string& name);
uint16_t _uint16(const std::string& name);
uint8_t _uint8(const std::string& name);
std::vector<std::string> _macAddresses(bool forceReCalculate = false);
// to protect internal objects, public methods need to protect the internals.
//
mutable std::mutex m_mutex;
std::vector<std::string> _macs; // unlikely to change, so save them once found.
// internal: assumes inside a lock
CComVariant _variant(const std::wstring& name)
{
if (!_all_initialized)
return CComVariant();
CComPtr<IEnumWbemClassObject> pEnum;
CComBSTR cbsQuery = std::wstring(L"Select " + name + L" from Win32_OperatingSystem").c_str();
HRESULT hr = _pWbemServices->ExecQuery(
CComBSTR(L"WQL"), cbsQuery, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum);
CComVariant cvtValue;
if (FAILED(hr) || !pEnum)
{
std::wstring wquery(cbsQuery, SysStringLen(cbsQuery));
_errors += "Failed to exec WMI query: '" + convertToUtf8(wquery) + "'\r\n";
return cvtValue;
}
ULONG uObjectCount = 0;
CComPtr<IWbemClassObject> pWmiObject;
hr = pEnum->Next(WBEM_INFINITE, 1, &pWmiObject, &uObjectCount);
if (FAILED(hr) || !pWmiObject)
{
_errors
+= "Failed to get WMI Next result for: '" + convertToUtf8(name) + "'\r\n";
return cvtValue;
}
hr = pWmiObject->Get(name.c_str(), 0, &cvtValue, 0, 0);
if (FAILED(hr))
{
_errors
+= "Failed to get WMI result value for: '" + convertToUtf8(name) + "'\r\n";
}
return cvtValue;
}
// internal: assumes inside a lock
std::string _string(const std::string& name)
{
if (!_all_initialized)
return "";
CComVariant cvtValue = _variant(convertFromUtf8(name).c_str());
std::wstring wValue(cvtValue.bstrVal, SysStringLen(cvtValue.bstrVal));
std::string sValue = convertToUtf8(wValue);
return sValue;
}
// internal: assumes inside a lock
uint32_t _uint32(const std::string& name)
{
if (!_all_initialized)
return 0;
CComVariant cvtValue = _variant(convertFromUtf8(name).c_str());
uint32_t uValue = static_cast<uint32_t>(cvtValue.lVal);
return uValue;
}
// similarly for other internal access of basic types.
// internal: assumes inside a lock
std::vector<std::string> _macAddresses(bool forceReCalculate /*= false*/)
{
if (!_all_initialized)
{
return _macs; // it will still be empty at this point.
}
if (forceReCalculate)
{
_macs.clear();
}
if (_macs.empty())
{
// hr == 0x80041010 == WBEM_E_INVALID_CLASS
// hr == 0x80041017 == WBEM_E_INVALID_QUERY
// hr == 0x80041018 == WBEM_E_INVALID_QUERY_TYPE
CComBSTR cbsQuery = std::wstring(L"Select * from Win32_NetworkAdapter").c_str();
CComPtr<IEnumWbemClassObject> pEnum;
HRESULT hr = _pWbemServices->ExecQuery(
CComBSTR(L"WQL"), cbsQuery, WBEM_RETURN_IMMEDIATELY, NULL, &pEnum);
if (FAILED(hr))
{
_errors += "error: MacAddresses: ExecQuery('"
+ convertToUtf8((LPWSTR)cbsQuery) + "') returned "
+ ToString(hr) + "\r\n";
}
if (SUCCEEDED(hr))
{
ULONG fetched;
VARIANT var;
IWbemClassObject* pclsObj = NULL;
while (pEnum)
{
hr = pEnum->Next(WBEM_INFINITE, 1, &pclsObj, &fetched);
if (0 == fetched)
break;
std::string theMac = "";
VariantInit(&var);
hr = pclsObj->Get(L"MACAddress", 0, &var, 0, 0);
if (SUCCEEDED(hr))
{
switch (var.vt)
{
case VT_NULL: break;
case VT_BSTR:
theMac = (var.bstrVal == NULL)
? ""
: convertToUtf8(var.bstrVal);
break;
case VT_LPSTR:
theMac = (var.bstrVal == NULL)
? ""
: (const char*)var.bstrVal;
break;
case VT_LPWSTR:
theMac = (var.bstrVal == NULL)
? ""
: convertToUtf8((LPWSTR)var.bstrVal);
break;
// _could_ be array of BSTR, LPSTR, LPWSTR; unlikely, but ....
case VT_ARRAY | VT_BSTR:
case VT_ARRAY | VT_LPSTR:
case VT_ARRAY | VT_LPWSTR:
_errors += "warning: MacAddresses: unexpected array of addresses";
_errors += "\r\n";
// yet another exercise for the reader :)
break;
default:
_errors += "error: MacAddresses: unexpected VARIANT.vt = "
+ ToString(var.vt) + "\r\n";
break;
}
// local loopback has an empty address?
if (!theMac.empty())
{
_macs.push_back(theMac);
}
}
VariantClear(&var);
pclsObj->Release();
}
}
}
return _macs;
}
...
}
GetAdaptersInfo() is the official method, it enumerates all adapters even ones that are disconnected.
See this post for example code codeguru
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <vector>
#include <Windows.h>
#include <Iphlpapi.h>
#include <Assert.h>
#include <string>
#pragma comment(lib, "iphlpapi.lib")
char* getdMacAddresses()
{
IP_ADAPTER_INFO AdapterInfo[32]; // Allocate information for up to 32 NICs
DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
DWORD dwStatus = GetAdaptersInfo( // Call GetAdapterInfo
AdapterInfo, // [out] buffer to receive data
&dwBufLen); // [in] size of receive data buffer
//Exit When Error
if (dwStatus != ERROR_SUCCESS)
return "ERROR";
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
char szBuffer[512];
while (pAdapterInfo)
{
if (pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)
{
sprintf_s(szBuffer, sizeof(szBuffer), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x"
, pAdapterInfo->Address[0]
, pAdapterInfo->Address[1]
, pAdapterInfo->Address[2]
, pAdapterInfo->Address[3]
, pAdapterInfo->Address[4]
, pAdapterInfo->Address[5]
);
return szBuffer;
}
pAdapterInfo = pAdapterInfo->Next;
}
return "ERROR";
}
You can use WMI on both XP and Vista, there are a number of examples online. e.g:
Use Windows Management Instrumentation (WMI) to get a MAC Address