diff --git a/changeMACAddress.cpp b/changeMACAddress.cpp index 3d0cefc..a04b02f 100644 --- a/changeMACAddress.cpp +++ b/changeMACAddress.cpp @@ -1,16 +1,18 @@ #include #include #include -#include +#include #include using namespace std; +// macro for checking os type #if defined(_WIN32) || defined(_WIN64) #define isWindows() true #else #define isWindows() false #endif +// struct for storing output to getIWbemClassObjectField() typedef struct VariantStruct { enum { VT_BSTR, @@ -29,30 +31,141 @@ typedef struct VariantStruct { } value; } VariantType; +// declarations +EXTERN_C const CLSID CLSID_WbemLocator = { 0x4590F811,0x1D3A,0x11D0,{ 0x89,0x1F,0x00,0xAA,0x00,0x4B,0x2E,0x24 } }; // for some reason this wasn't defined in my linked library... const BYTE* generateMACAddress(); char hexify(int); VariantType* getIWbemClassObjectField(IWbemClassObject*, const wchar_t*); +void resetNIC(IWbemServices*, wstring); void printVariantType(VariantType*); char* ConvertBSTRToString(BSTR); // my comutil is corrupted, so redefined here... +bool valid_address(char*); +void setup_wmi_api(IWbemLocator**, IWbemServices**); +wchar_t* get_device_id(IWbemLocator*, IWbemServices*, char*); + +// gets the named device's device id +wchar_t* get_device_id(IWbemLocator* pLoc, IWbemServices* pSvc, char* name) { + unsigned int name_len = strlen(name)+1; + wchar_t* wname = new wchar_t[name_len]; + mbstowcs(wname, name, name_len); + // sets up enumeration object + IEnumWbemClassObject* pEnum = NULL; + wstring query(L"SELECT * FROM Win32_NetworkAdapter WHERE Name = \""); + query.append(wname); + query.append(L"\""); + BSTR langArg = ::SysAllocString(L"WQL"); + BSTR queryArg = ::SysAllocString(query.c_str()); + DWORD hr = pSvc->ExecQuery(langArg, queryArg, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum); + ::SysFreeString(langArg); + ::SysFreeString(queryArg); + if (FAILED(hr)) { + printf("Unable to retrieve network adapters. Error code = %x.\n", hr); + pLoc->Release(); + pSvc->Release(); + exit(1); + } -// helperf func + // loops through enums + IWbemClassObject* obj = NULL; + ULONG numElm; + hr = pEnum->Next(WBEM_INFINITE, 1, &obj, &numElm); + if (SUCCEEDED(hr) && obj != NULL) { + VariantType* pDeviceID = getIWbemClassObjectField(obj, L"DeviceID"); + DWORD device_id_len = ::SysStringLen(pDeviceID->value.bstrVal); + wchar_t* device_id = new wchar_t[device_id_len]; + wcscpy(device_id, pDeviceID->value.bstrVal); + obj->Release(); + pEnum->Release(); + delete[] wname; + return device_id; + } else { + printf("No adapter was found with name \"%s\".\n", name); + pLoc->Release(); + pSvc->Release(); + exit(1); + } +} + + +// sets up wmi api and sets pointer to service and pointer to locator +void setup_wmi_api(IWbemLocator** ppLoc, IWbemServices** ppSvc) { + // launch COM + HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + if (FAILED(hr)) { + printf("Failed to initialize COM library. Error code = %x.\n", hr); + exit(1); + } + hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0); + + hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) ppLoc); + if (FAILED(hr)) { + printf("Failed to create IWbemLocator object. Error code = %x.\n", hr); + CoUninitialize(); + exit(1); + } + + // Connect to the root\CIMV2 namespace with the current user. + hr = (*ppLoc)->ConnectServer( + BSTR(L"ROOT\\CIMV2"), //namespace + NULL, NULL, NULL, 0, NULL, NULL, ppSvc); + if (FAILED(hr)) { + printf("Unable to connect to root\\cimv2. Error code = %x.\n", hr); + (*ppLoc)->Release(); + CoUninitialize(); + exit(1); + } + + // Set proxy so impersonation of the client occurs. + hr = CoSetProxyBlanket(*ppSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); + if (FAILED(hr)) { + printf("Could not set proxy blanket. Error code = %x.\n", hr); + (*ppSvc)->Release(); + (*ppLoc)->Release(); + CoUninitialize(); + exit(1); + } +} + +// predicate for validity of mac address +bool valid_address(char* mac) { + if (strlen(mac) == 12) { + for (int i = 0; i < 12; i++) { + if ((mac[i] >= '0' && mac[i] <= '9') || + ((mac[i] >= 'A' && mac[i] <= 'F')) || + ((mac[i] >= 'a' && mac[i] <= 'f'))) { + continue; + } else { + return false; + } + } + if (mac[1] == '2' || mac[1] == '6' || mac[1] == 'A' || mac[1] == 'E') { + return true; + } else { + return false; + } + } else { + return false; + } +} + +// converts bstr to cstring char* ConvertBSTRToString(BSTR s) { char* rtn = new char[::SysStringLen(s) + 1]; wcstombs(rtn, s, ::SysStringLen(s) +1); return rtn; } -/** Gets specified field of input IWbemClassObject accordingly. */ +// Gets specified field of input IWbemClassObject accordingly; caller has responsibility of freeing returned VariantType VariantType* getIWbemClassObjectField(IWbemClassObject* obj, const wchar_t* field) { VARIANT vRet; VariantInit(&vRet); if (SUCCEEDED(obj->Get(field, 0, &vRet, NULL, NULL))) { - VariantType* rtn = (VariantType*) malloc(sizeof(VariantType)); + VariantType* rtn = new VariantType; if (rtn == NULL) { printf("Unable to allocate memory inside getIWbemClassObjectField()\n"); exit(1); } -// + if (vRet.vt == VT_BSTR) { // prints string using multibyte representation wstring temp(vRet.bstrVal, ::SysStringLen(vRet.bstrVal)); @@ -62,7 +175,7 @@ VariantType* getIWbemClassObjectField(IWbemClassObject* obj, const wchar_t* fiel rtn->value.lVal = vRet.lVal; rtn->type = rtn->VT_I4; } else if (vRet.vt == VT_DISPATCH) { - rtn->value.pdispVal = (IDispatch*) malloc(sizeof(IDispatch)); + rtn->value.pdispVal = (IDispatch*) malloc(sizeof(IDispatch)); // new doesn't work on abstract types rtn->value.pdispVal = vRet.pdispVal; rtn->type = rtn->VT_DISPATCH; } else if (vRet.vt == VT_I2) { @@ -74,31 +187,26 @@ VariantType* getIWbemClassObjectField(IWbemClassObject* obj, const wchar_t* fiel rtn->value.boolVal = vRet.boolVal; rtn->type = rtn->VT_BOOL; } else { - // shnot reach here - printf("Should not reach here.\n"); - printf("VT IS %d\n", vRet.vt); - printf("%d\n", VT_I2); + printf("Unexpected variant type.\n"); + VariantClear(&vRet); + exit(1); } - VariantClear(&vRet); return rtn; } else { printf("Return code: %d\n", obj->Get(field, 0, &vRet, NULL, NULL)); printf("Unable to get IWbemClassObject's %ls field.\n", field); - return NULL; + exit(1); } } -EXTERN_C const CLSID CLSID_WbemLocator = { 0x4590F811,0x1D3A,0x11D0,{ 0x89,0x1F,0x00,0xAA,0x00,0x4B,0x2E,0x24 } }; // for some reason this wasn't defined in my linked library... - +// the main script int main(int argc, char* argv[]) { if (isWindows()) { OSVERSIONINFO osinfo; osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osinfo); - if (osinfo.dwMajorVersion > 5) { // is Windows Vista or later - - } else { + if (osinfo.dwMajorVersion <= 5) { // is NOT Windows Vista or later printf("Your version of Windows is not supported.\n"); exit(0); } @@ -107,9 +215,11 @@ int main(int argc, char* argv[]) { exit(0); } + const BYTE* mac; + bool MAC_SET = false; wstring where_cond; if (argc == 1) { - where_cond.append(L"NetEnabled=TRUE"); + where_cond.append(L"NetEnabled=TRUE"); // by default sets adapter currently connected to net } else if (argc == 3 && (strcmp(argv[1], "-n") == 0)) { wchar_t* dest = new wchar_t[strlen(argv[2])+1](); mbstowcs(dest, argv[2], strlen(argv[2])+1); @@ -117,72 +227,90 @@ int main(int argc, char* argv[]) { where_cond.append(dest); where_cond.append(L"\""); delete[] dest; + } else if (argc == 3 && (strcmp(argv[1], "-r") == 0)) { + IWbemLocator* pLoc = NULL; + IWbemServices* pSvc = NULL; + setup_wmi_api(&pLoc, &pSvc); + wchar_t* device_id = get_device_id(pLoc, pSvc, argv[2]); + wstring device = L"Win32_NetworkAdapter.DeviceID=\""; + device += device_id; + device += L"\""; + resetNIC(pSvc, device); + pLoc->Release(); + pSvc->Release(); + return 0; + } else if (argc == 3 && (strcmp(argv[1], "-s") == 0)) { + if (valid_address(argv[2])) { + where_cond.append(L"NetEnabled=TRUE"); + mac = new BYTE[strlen(argv[2])+1]; + strcpy((char*) mac, argv[2]); + MAC_SET = true; + } else { + printf("Invalid specified MAC address.\n"); + exit(1); + } + } else if (argc == 5 && (strcmp(argv[1], "-n") == 0) && (strcmp(argv[3], "-s") == 0)) { + // boilerplate + wchar_t* dest = new wchar_t[strlen(argv[2])+1](); + mbstowcs(dest, argv[2], strlen(argv[2])+1); + where_cond.append(L"Name=\""); + where_cond.append(dest); + where_cond.append(L"\""); + delete[] dest; + + if (valid_address(argv[4])) { + mac = new BYTE[strlen(argv[4])+1]; + strcpy((char*) mac, argv[4]); + MAC_SET = true; + } else { + printf("Invalid specified MAC address.\n"); + exit(1); + } } else { - printf("Usage: changeMACAddress [-n name]\n"); + if (argc == 2 && strcmp(argv[1], "-help") == 0) { + printf("Description: By default, changeMACAddress generates random MAC address for adapter currently connected to the internet.\n"); + printf("changeMACAddress options:\n"); + printf("-n NAME\t generate random MAC address for adapter with NAME\n"); + printf("-r NAME\t reset adapter with NAME\n"); + printf("-s ADDRESS\t set adapter's MAC address to ADDRESS instead of randomly generating it\n"); + } else { + printf("Usage: changeMACAddress [-s address | -n name [-s address] | -r name]\nSpecify '-help' for full options.\n"); + } exit(1); } printf("Executing script...\n"); - // launch COM - HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - if (FAILED(hr)) { - printf("Failed to initialize COM library. Error code = %x.\n", hr); - return 1; - } - hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0); + // sets up wmi api IWbemLocator* pLoc = NULL; - hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc); - if (FAILED(hr)) { - printf("Failed to create IWbemLocator object. Error code = %x.\n", hr); - CoUninitialize(); - return 1; - } - - IWbemServices *pSvc = NULL; - // Connect to the root\CIMV2 namespace with the current user. - hr = pLoc->ConnectServer( - BSTR(L"ROOT\\CIMV2"), //namespace - NULL, NULL, NULL, 0, NULL, NULL, &pSvc); - if (FAILED(hr)) { - printf("Unable to connect to root\\cimv2. Error code = %x.\n", hr); - pLoc->Release(); - CoUninitialize(); - return 1; - } - - // Set proxy so impersonation of the client occurs. - hr = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); - if (FAILED(hr)) { - printf("Could not set proxy blanket. Error code = %x.\n", hr); - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - return 1; - } + IWbemServices* pSvc = NULL; + setup_wmi_api(&pLoc, &pSvc); + // sets up enumeration object IEnumWbemClassObject* pEnum = NULL; wstring query(L"SELECT * FROM Win32_NetworkAdapter WHERE "); query.append(where_cond); BSTR langArg = ::SysAllocString(L"WQL"); BSTR queryArg = ::SysAllocString(query.c_str()); - hr = pSvc->ExecQuery(langArg, queryArg, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum); + DWORD hr = pSvc->ExecQuery(langArg, queryArg, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum); ::SysFreeString(langArg); ::SysFreeString(queryArg); if (FAILED(hr)) { printf("Unable to retrieve network adapters. Error code = %x.\n", hr); pLoc->Release(); pSvc->Release(); - return 1; + exit(1); } // loops through enums IWbemClassObject* obj = NULL; ULONG numElm; + int cntElm = 0; // counter for number elements enumerated while ((hr = pEnum->Next(WBEM_INFINITE, 1, &obj, &numElm)) != WBEM_S_FALSE) { if (FAILED(hr)) { break; } + cntElm++; string subkey_path("System\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\"); HKEY hkResult; @@ -220,9 +348,14 @@ int main(int argc, char* argv[]) { if (ERROR_SUCCESS == query_errcode) { if (strcmp((char*) buf, ConvertBSTRToString(adapter_guid)) == 0) { - const BYTE* mac = generateMACAddress(); - unsigned int mac_len = strlen((char*) mac); - DWORD set_errcode = RegSetValueEx(sub_hkResult, TEXT("NetworkAddress"), 0, REG_SZ, mac, mac_len); // creates value if NetworkAddress value is not already present + if (!MAC_SET) { + mac = generateMACAddress(); + } else { + MAC_SET = false; + } + unsigned int mac_len = strlen((char*) mac); + DWORD set_errcode = RegSetValueEx(sub_hkResult, TEXT("NetworkAddress"), 0, REG_SZ, mac, mac_len); // creates value if NetworkAddress value is not already present + if (ERROR_SUCCESS == set_errcode) { printf("MAC address was set to: %s.\n", mac); } else { @@ -248,20 +381,19 @@ int main(int argc, char* argv[]) { } while (true); RegCloseKey(hkResult); - IWbemClassObject* pOutParams = NULL; VariantType* pDeviceID = getIWbemClassObjectField(obj, L"DeviceID"); wchar_t* DeviceID = (wchar_t*) pDeviceID->value.bstrVal; wstring device = L"Win32_NetworkAdapter.DeviceID=\""; - device += (wchar_t*) pDeviceID->value.bstrVal; + device += DeviceID; device += L"\""; - - printf("Disabling adapter...\n"); - pSvc->ExecMethod((BSTR) device.c_str(), (BSTR) L"Disable", 0, NULL, NULL, &pOutParams, NULL); - printf("Enabling adapter...\n"); - pSvc->ExecMethod((BSTR) device.c_str(), (BSTR) L"Enable", 0, NULL, NULL, &pOutParams, NULL); + resetNIC(pSvc, device); obj->Release(); } + if (cntElm == 0 && (strcmp(argv[1], "-n") == 0)) { + printf("No adapter was found with name \"%s\".\n", argv[2]); + } + pEnum->Release(); pLoc->Release(); printf("Script ended.\n"); @@ -283,7 +415,7 @@ void printVariantType(VariantType* p) { } } -/** Generates a Windows MAC address. */ +// generates mac address const BYTE* generateMACAddress() { srand(time(NULL)); BYTE* s = new BYTE[13]; @@ -295,13 +427,26 @@ const BYTE* generateMACAddress() { s[1] = temp[(rand() % 4)]; return s; } -// helper function + +// converts ints to hexadecimal characters char hexify(int x) { if (x >= 0 && x <= 9) { return '0' + x; } else if (x >= 10 && x <= 16) { return 'A' + (x-10); } else { - // should not reach here + printf("Invalid int.\n"); + exit(1); } } + +// resets NIC based on specified device +void resetNIC(IWbemServices* pSvc, wstring device) { + IWbemClassObject* pOutParams = NULL; + printf("Disabling adapter...\n"); + DWORD errcode = pSvc->ExecMethod((BSTR) device.c_str(), (BSTR) L"Disable", 0, NULL, NULL, &pOutParams, NULL); + if (ERROR_SUCCESS != errcode) { printf("Disable failed. Error code = %x.\n", errcode); } + printf("Enabling adapter...\n"); + errcode = pSvc->ExecMethod((BSTR) device.c_str(), (BSTR) L"Enable", 0, NULL, NULL, &pOutParams, NULL); + if (ERROR_SUCCESS != errcode) { printf("Enable failed. Error code = %x.\n", errcode); } +}