Created
February 15, 2019 10:54
-
-
Save svedi/1f2dfac7c54965f9659fbe5447b3bf72 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _WIN32_DCOM | |
#include <comdef.h> | |
#include <Wbemidl.h> | |
# pragma comment(lib, "wbemuuid.lib") | |
#include "atlconv.h" | |
#include "iphlpapi.h" | |
#include "atlsecurity.h" | |
#include <string> | |
#include <Windows.h> | |
#include <wincrypt.h> | |
#include "MachineCodeComputer_COM.hpp" | |
#include "basic_Error.hpp" | |
#include "api.hpp" | |
namespace cryptolens_io { | |
namespace latest { | |
namespace internal { | |
api::main api; | |
HRESULT GetWbemService(basic_Error & e, IWbemLocator** pLocator, IWbemServices** pService) | |
{ | |
HRESULT result; | |
result = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, reinterpret_cast<LPVOID*>(pLocator)); | |
if (FAILED(result)) { e.set(api, 6, 3, result); goto cleanup; } | |
result = (*pLocator)->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, NULL, 0, NULL, NULL, pService); | |
if (FAILED(result)) { e.set(api, 6, 4, result); goto cleanup; } | |
result = CoSetProxyBlanket(*pService, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); | |
if (FAILED(result)) { e.set(api, 6, 5, result); goto cleanup; } | |
return NOERROR; | |
cleanup: | |
if (pService && *pService) { (*pService)->Release(); } | |
if (pLocator && *pLocator) { (*pLocator)->Release(); } | |
CoUninitialize(); | |
return result; | |
} | |
HRESULT QueryAllBstr(basic_Error & e, IWbemServices* pService, const wchar_t* query, const wchar_t* propertyName, std::wstring & append) | |
{ | |
IEnumWbemClassObject* pEnumerator = NULL; | |
IWbemClassObject *pQueryObject = NULL; | |
HRESULT result = pService->ExecQuery( | |
bstr_t(L"WQL"), // strQueryLanguage | |
bstr_t(query), // strQuery | |
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, // lFlags | |
NULL, // pCtx | |
&pEnumerator // ppEnum | |
); | |
if (FAILED(result)) { e.set(api, 6, 6, result); goto cleanup; } | |
while (pEnumerator) | |
{ | |
try | |
{ | |
ULONG returnedObjectCount = 0; | |
result = pEnumerator->Next(WBEM_INFINITE, 1, &pQueryObject, &returnedObjectCount); | |
if (returnedObjectCount == 0) { break; } | |
VARIANT objectProperty; | |
result = pQueryObject->Get(propertyName, 0, &objectProperty, 0, 0); | |
if (FAILED(result)) { e.set(api, 6, 7, result); goto cleanup; } | |
if (objectProperty.vt == VT_BSTR) | |
{ | |
append += objectProperty.bstrVal; | |
} | |
VariantClear(&objectProperty); | |
} | |
catch (...) | |
{ | |
break; | |
} | |
} | |
result = NOERROR; | |
cleanup: | |
if (pEnumerator) { pEnumerator->Release(); } | |
if (pQueryObject) { pQueryObject->Release(); } | |
return result; | |
} | |
HRESULT QueryFirstBstr(basic_Error & e, IWbemServices* pService, const wchar_t* query, const wchar_t* propertyName, std::wstring & append) | |
{ | |
IEnumWbemClassObject* pEnumerator = NULL; | |
IWbemClassObject *pQueryObject = NULL; | |
HRESULT result = pService->ExecQuery( | |
bstr_t(L"WQL"), // strQueryLanguage | |
bstr_t(query), // strQuery | |
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, // lFlags | |
NULL, // pCtx | |
&pEnumerator // ppEnum | |
); | |
if (FAILED(result)) { e.set(api, 6, 8, result); goto cleanup; } | |
while (pEnumerator) | |
{ | |
try | |
{ | |
ULONG returnedObjectCount = 0; | |
result = pEnumerator->Next(WBEM_INFINITE, 1, &pQueryObject, &returnedObjectCount); | |
if (returnedObjectCount == 0) { break; } | |
VARIANT objectProperty; | |
result = pQueryObject->Get(propertyName, 0, &objectProperty, 0, 0); | |
if (FAILED(result)) { e.set(api, 6, 9, result); goto cleanup; } | |
if (objectProperty.vt == VT_BSTR) | |
{ | |
append += objectProperty.bstrVal; | |
break; | |
} | |
VariantClear(&objectProperty); | |
} | |
catch (...) | |
{ | |
break; | |
} | |
} | |
result = NOERROR; | |
cleanup: | |
if (pEnumerator) { pEnumerator->Release(); } | |
if (pQueryObject) { pQueryObject->Release(); } | |
return result; | |
} | |
HRESULT QueryFirstI4(basic_Error & e, IWbemServices* pService, const wchar_t* query, const wchar_t* propertyName, SHORT & append) | |
{ | |
IEnumWbemClassObject* pEnumerator = NULL; | |
IWbemClassObject *pQueryObject = NULL; | |
HRESULT result = pService->ExecQuery( | |
bstr_t(L"WQL"), // strQueryLanguage | |
bstr_t(query), // strQuery | |
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, // lFlags | |
NULL, // pCtx | |
&pEnumerator // ppEnum | |
); | |
if (FAILED(result)) { e.set(api, 6, 10, result); goto cleanup; } | |
while (pEnumerator) | |
{ | |
try | |
{ | |
ULONG returnedObjectCount = 0; | |
result = pEnumerator->Next(WBEM_INFINITE, 1, &pQueryObject, &returnedObjectCount); | |
if (returnedObjectCount == 0) { break; } | |
VARIANT objectProperty; | |
result = pQueryObject->Get(propertyName, 0, &objectProperty, 0, 0); | |
if (FAILED(result)) { e.set(api, 6, 11, result); goto cleanup; } | |
if (objectProperty.vt == VT_I4) | |
{ | |
append = objectProperty.iVal; | |
break; | |
} | |
VariantClear(&objectProperty); | |
} | |
catch (...) | |
{ | |
break; | |
} | |
} | |
result = NOERROR; | |
cleanup: | |
if (pEnumerator) { pEnumerator->Release(); } | |
if (pQueryObject) { pQueryObject->Release(); } | |
return result; | |
} | |
HRESULT GetHDDInfo(basic_Error & e, IWbemServices* pService, std::wstring & append) | |
{ | |
HRESULT result = NOERROR; | |
SHORT diskindex = 999; | |
_bstr_t query_devicename(L"SELECT * FROM Win32_DiskDrive where Index = "); | |
std::wstring diskindex_str; | |
std::wstring devicename; | |
_bstr_t query_serial(L"SELECT * FROM Win32_PhysicalMedia WHERE Tag like '"); | |
bool nonwhitespacefound; | |
result = QueryFirstI4(e, pService, L"select * from Win32_DiskPartition WHERE BootPartition=True", L"DiskIndex", diskindex); | |
if (FAILED(result)) { e.set(api, 6, 12, result); goto cleanup; } | |
if (diskindex == 999) { goto cleanup; } // Mirrors the dotnet code | |
diskindex_str = std::to_wstring(diskindex); | |
query_devicename += diskindex_str.c_str(); | |
result = QueryFirstBstr(e, pService, query_devicename.GetBSTR(), L"Name", devicename); | |
if (FAILED(result)) { e.set(api, 6, 13, result); goto cleanup; } | |
nonwhitespacefound = false; | |
for (auto x : devicename) | |
{ | |
// XXX: Maybe change to _iswspace_l and make it independent of current locale? Otoh dotnet might not do this? | |
if (iswspace(x) == 0) { nonwhitespacefound = true; } | |
} | |
if (!nonwhitespacefound) { goto cleanup; } | |
// XXX: This assumes \\.\ only occurs once. Can use find() to make it more similar to dotnet? | |
if (devicename.size() > 4 && devicename[0] == L'\\' && devicename[1] == L'\\' && devicename[2] == L'.' && devicename[3] == L'\\') | |
{ | |
query_serial += L"%"; | |
query_serial += devicename.c_str() + 4; | |
query_serial += L"'"; | |
} | |
else | |
{ | |
query_serial += devicename.c_str(); | |
} | |
result = QueryFirstBstr(e, pService, query_serial.GetBSTR(), L"SerialNumber", append); | |
if (FAILED(result)) { e.set(api, 6, 14, result); goto cleanup; } | |
result = NOERROR; | |
cleanup: | |
return result; | |
} | |
HRESULT GetNICInfo(basic_Error & e, std::wstring & append) | |
{ | |
WCHAR HEX[] = L"0123456789ABCDEF"; | |
ULONG outBufLen = 0; | |
DWORD dwRetVal = 0; | |
IP_ADAPTER_INFO* pAdapterInfos = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO)); | |
// retry up to 5 times, to get the adapter infos needed | |
for (int i = 0; i < 5 && (dwRetVal == ERROR_BUFFER_OVERFLOW || dwRetVal == NO_ERROR); ++i) | |
{ | |
dwRetVal = GetAdaptersInfo(pAdapterInfos, &outBufLen); | |
if (dwRetVal == NO_ERROR) | |
{ | |
break; | |
} | |
else if (dwRetVal == ERROR_BUFFER_OVERFLOW) | |
{ | |
free(pAdapterInfos); | |
pAdapterInfos = (IP_ADAPTER_INFO*)malloc(outBufLen); | |
} | |
else | |
{ | |
pAdapterInfos = 0; | |
break; | |
} | |
//std::cout << i << std::endl; | |
} | |
if (dwRetVal == NO_ERROR) | |
{ | |
IP_ADAPTER_INFO* pAdapterInfo = pAdapterInfos; | |
while (pAdapterInfo) | |
{ | |
IP_ADDR_STRING* pIpAddress = &(pAdapterInfo->IpAddressList); | |
while (pIpAddress != 0) | |
{ | |
if (pAdapterInfo->AddressLength > 0) | |
{ | |
for (size_t i = 0; i < pAdapterInfo->AddressLength; ++i) | |
{ | |
BYTE x = pAdapterInfo->Address[i]; | |
int x1 = (x & 0xF0) >> 4; | |
int x2 = (x & 0xF) >> 0; | |
append += HEX[x1]; | |
append += HEX[x2]; | |
} | |
break; | |
} | |
pIpAddress = pIpAddress->Next; | |
} | |
pAdapterInfo = pAdapterInfo->Next; | |
} | |
} | |
free(pAdapterInfos); | |
return NOERROR; | |
} | |
HRESULT GetWindowsIdentity(basic_Error & e, std::wstring & append) | |
{ | |
ATL::CAccessToken accessToken; | |
ATL::CSid currentUserSid; | |
if (accessToken.GetProcessToken(TOKEN_READ | TOKEN_QUERY) | |
&& accessToken.GetUser(¤tUserSid)) | |
{ | |
append += currentUserSid.Domain(); | |
append += L"\\"; | |
append += currentUserSid.AccountName(); | |
} | |
return NOERROR; | |
} | |
size_t SHA1(basic_Error & e, std::wstring const& data, std::string & append) | |
{ | |
HCRYPTPROV hProv; | |
HCRYPTHASH hHash; | |
BYTE *pbHash; | |
DWORD dwHashLen; | |
DWORD dwHashLenSize = sizeof(DWORD); | |
size_t data_len; | |
CHAR HEX[] = "0123456789ABCDEF"; | |
size_t result; | |
if (!CryptAcquireContext(&hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) | |
{ | |
result = 1; | |
e.set(api, 6, 15, result); goto cleanup; | |
} | |
if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) | |
{ | |
result = 1; | |
e.set(api, 6, 16, result); goto cleanup; | |
} | |
data_len = sizeof(wchar_t) * data.size(); | |
if (!CryptHashData(hHash, (const BYTE*)data.data(), data_len, 0)) | |
{ | |
result = 1; | |
e.set(api, 6, 17, result); goto cleanup; | |
} | |
if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0)) | |
{ | |
result = 1; | |
e.set(api, 6, 18, result); goto cleanup; | |
} | |
if (!(pbHash = (BYTE*)malloc(dwHashLen))) | |
{ | |
result = 1; | |
e.set(api, 6, 19, result); goto cleanup; | |
} | |
if (!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, 0)) | |
{ | |
result = 1; | |
e.set(api, 6, 20, result); goto cleanup; | |
} | |
for (size_t i = 0; i < dwHashLen; ++i) | |
{ | |
BYTE x = pbHash[i]; | |
int x1 = (x & 0xF0) >> 4; | |
int x2 = (x & 0xF) >> 0; | |
append += HEX[x1]; | |
append += HEX[x2]; | |
} | |
result = 0; | |
cleanup: | |
CryptDestroyHash(hHash); | |
CryptReleaseContext(hProv, 0); | |
return result; | |
} | |
void AppendTemp(std::wstring & machinecode, std::wstring & machinecode_debug, std::wstring & temp) | |
{ | |
machinecode += temp; | |
machinecode_debug += temp; machinecode_debug += L","; | |
temp.clear(); | |
} | |
void GetMachineCode(basic_Error & e, std::wstring & append, std::wstring & append_debug) | |
{ | |
std::wstring temp; | |
std::wstring machinecode_debug; | |
std::wstring machinecode; | |
api::main api; | |
HRESULT result, result_init; | |
IWbemLocator* pLocator = NULL; | |
IWbemServices* pService = NULL; | |
result_init = CoInitializeEx(0, COINIT_APARTMENTTHREADED); | |
if (result_init == RPC_E_CHANGED_MODE) { | |
result_init = CoInitializeEx(0, COINIT_MULTITHREADED); | |
} | |
if (FAILED(result_init)) { e.set(api, 6, 1, result_init); goto cleanup; } | |
result = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); | |
if (FAILED(result) && result != RPC_E_TOO_LATE) { e.set(api, 6, 2, result); goto cleanup; } | |
result = GetWbemService(e, &pLocator, &pService); | |
if (FAILED(result)) { goto cleanup; } | |
result = QueryAllBstr(e, pService, L"SELECT ProcessorId FROM Win32_Processor", L"ProcessorId", temp); | |
if (FAILED(result)) { goto cleanup; } | |
AppendTemp(machinecode, machinecode_debug, temp); | |
result = QueryAllBstr(e, pService, L"select * from Win32_BIOS", L"SerialNumber", temp); | |
if (FAILED(result)) { goto cleanup; } | |
AppendTemp(machinecode, machinecode_debug, temp); | |
result = QueryAllBstr(e, pService, L"select * from Win32_BaseBoard", L"SerialNumber", temp); | |
if (FAILED(result)) { goto cleanup; } | |
AppendTemp(machinecode, machinecode_debug, temp); | |
if (machinecode.size() <= 3) | |
{ | |
result = GetHDDInfo(e, pService, temp); | |
if (FAILED(result)) { goto cleanup; } | |
AppendTemp(machinecode, machinecode_debug, temp); | |
} | |
if (machinecode.find(L"To be filled by O.E.M.", 0) != std::wstring::npos) | |
{ | |
result = GetNICInfo(e, temp); | |
if (FAILED(result)) { goto cleanup; } | |
AppendTemp(machinecode, machinecode_debug, temp); | |
} | |
if (false) | |
{ | |
result = GetWindowsIdentity(e, temp); | |
if (FAILED(result)) { goto cleanup; } | |
AppendTemp(machinecode, machinecode_debug, temp); | |
} | |
cleanup: | |
if (pService) { pService->Release(); } | |
if (pLocator) { pLocator->Release(); } | |
if (!FAILED(result_init)) { CoUninitialize(); } // See some msdn article | |
//return machinecode; | |
append += machinecode; | |
append_debug += machinecode_debug; | |
} | |
} // namespace internal | |
std::string | |
MachineCodeComputer_COM::get_machine_code(basic_Error & e) { | |
std::wstring machine_code; | |
std::wstring debug; | |
::cryptolens_io::latest::internal::GetMachineCode(e, machine_code, debug); | |
std::string hashed_machine_code; | |
::cryptolens_io::latest::internal::SHA1(e, machine_code, hashed_machine_code); | |
return hashed_machine_code; | |
} | |
} // namespace latest | |
} // namespace cryptolens_io |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment