草庐IT

c++ - 通过适配器描述更改 Mac 地址

coder 2024-06-10 原文

我正在使用 Nate True @ http://devices.natetrue.com/macshift/ 提供的出色工具 它通过适配器名称更改 Mac 地址。这是源代码:

const int versionMajor = 1;
const int versionMinor = 1;

#include <windows.h>
#include <objbase.h>
#include <netcon.h>
#include <stdio.h>
#include "validmacs.h"

void SetMAC(char * AdapterName, char * NewMAC) {
  HKEY hListKey = NULL;
  HKEY hKey = NULL;
  RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
    0, KEY_READ, &hListKey);
  if (!hListKey) {
    printf("Failed to open adapter list key\n");
    return;
    }
  FILETIME writtenTime;
  char keyNameBuf[512], keyNameBuf2[512];
  DWORD keyNameBufSiz = 512;
  DWORD crap;
  int i = 0;
  bool found = false;
  while (RegEnumKeyEx(hListKey, i++, keyNameBuf, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
        == ERROR_SUCCESS) {
    _snprintf(keyNameBuf2, 512, "%s\\Connection", keyNameBuf);
    hKey = NULL;
    RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ, &hKey);
    if (hKey) {
      keyNameBufSiz = 512;
      if (RegQueryValueEx(hKey, "Name", 0, &crap, (LPBYTE)keyNameBuf2, &keyNameBufSiz)
        == ERROR_SUCCESS && strcmp(keyNameBuf2, AdapterName) == 0) {
        printf("Adapter ID is %s\n", keyNameBuf);
        found = true;
        break;
        }
      RegCloseKey(hKey);
      }
    keyNameBufSiz = 512;
    }
  RegCloseKey(hListKey);
  if (!found) {
    printf("Could not find adapter name '%s'.\nPlease make sure this is the name you gave it in Network Connections.\n", AdapterName);
    return;
    }
  RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}",
    0, KEY_READ, &hListKey);
  if (!hListKey) {
    printf("Failed to open adapter list key in Phase 2\n");
    return;
    }
  i = 0;
  char buf[512];
  while (RegEnumKeyEx(hListKey, i++, keyNameBuf2, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
        == ERROR_SUCCESS) {
    hKey = NULL;
    RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ | KEY_SET_VALUE, &hKey);
    if (hKey) {
      keyNameBufSiz = 512;
      if ((RegQueryValueEx(hKey, "NetCfgInstanceId", 0, &crap, (LPBYTE)buf, &keyNameBufSiz)
        == ERROR_SUCCESS) && (strcmp(buf, keyNameBuf) == 0)) {
        RegSetValueEx(hKey, "NetworkAddress", 0, REG_SZ, (LPBYTE)NewMAC, strlen(NewMAC) + 1);
        //printf("Updating adapter index %s (%s=%s)\n", keyNameBuf2, buf, keyNameBuf);
        //break;
        }
      RegCloseKey(hKey);
      }
    keyNameBufSiz = 512;
    }
  RegCloseKey(hListKey);

  }

void ResetAdapter(char * AdapterName) {
  struct _GUID guid = {0xBA126AD1,0x2166,0x11D1,0};
  memcpy(guid.Data4, "\xB1\xD0\x00\x80\x5F\xC1\x27\x0E", 8);
  unsigned short * buf = new unsigned short[strlen(AdapterName)+1];

  void (__stdcall *NcFreeNetConProperties) (NETCON_PROPERTIES *);
  HMODULE NetShell_Dll = LoadLibrary("Netshell.dll");
  if (!NetShell_Dll) {
    printf("Couldn't load Netshell.dll\n");
    return;
    }
  NcFreeNetConProperties = (void (__stdcall *)(struct tagNETCON_PROPERTIES *))GetProcAddress(NetShell_Dll, "NcFreeNetconProperties");
  if (!NcFreeNetConProperties) {
    printf("Couldn't load required DLL function\n");
    return;
    }

  for (unsigned int i = 0; i <= strlen(AdapterName); i++) {
    buf[i] = AdapterName[i];
    }
  CoInitialize(0);
    INetConnectionManager * pNCM = NULL;    
    HRESULT hr = ::CoCreateInstance(guid,
                                     NULL,
                                     CLSCTX_ALL,
                                     __uuidof(INetConnectionManager),
                                     (void**)&pNCM);
    if (!pNCM)
        printf("Failed to instantiate required object\n");
    else {
        IEnumNetConnection * pENC;
        pNCM->EnumConnections(NCME_DEFAULT, &pENC);
        if (!pENC) {
          printf("Could not enumerate Network Connections\n");
          }
        else {
          INetConnection * pNC;
          ULONG fetched;
          NETCON_PROPERTIES * pNCP;
          do {
            pENC->Next(1, &pNC, &fetched);
            if (fetched && pNC) {
              pNC->GetProperties(&pNCP);
              if (pNCP) {
                if (wcscmp(pNCP->pszwName, buf) == 0) {
                  pNC->Disconnect();
                  pNC->Connect();
                  }
                NcFreeNetConProperties(pNCP);
                }
              }
            } while (fetched);
            pENC->Release();
          }
        pNCM->Release();
    }

    FreeLibrary(NetShell_Dll);
    CoUninitialize ();
  }

bool IsValidMAC(char * str) {
  if (strlen(str) != 12) return false;
  for (int i = 0; i < 12; i++) {
    if ((str[i] < '0' || str[i] > '9') 
          && (str[i] < 'a' || str[i] > 'f')
          && (str[i] < 'A' || str[i] > 'F')) {
      return false;
      }
    }
  return true;
  }

void ShowHelp() {
  printf("Usage: macshift [options] [mac-address]\n\n");
  printf("Options:\n");
  printf("\t-i [adapter-name]     The adapter name from Network Connections.\n");
  printf("\t-r                    Uses a random MAC address. This is the default.\n");
  printf("\t-d                    Restores the original MAC address.\n");
  printf("\t--help                Shows this screen.\n\n");
  printf("Macshift uses special undocumented functions in the Windows COM Interface that\n");
  printf(" allow you to change an adapter's MAC address without needing to restart.\n");
  printf("When you change a MAC address, all your connections are closed automatically\n");
  printf(" and your adapter is reset.\n");
  }

//Generates a random MAC that is actually plausible
void RandomizeMAC(char * newmac) {
  _snprintf(newmac, 6, "%06X", rand() % numMacs);
  for (int i = 3; i < 6; i++) {
    _snprintf(&newmac[i*2], 2, "%02X", rand() & 0xFF);
    }
  newmac[12] = 0;
  }

int main(int argc, char * * argv) {
  printf("Macshift v%i.%i, MAC Changing Utility by Nathan True, macshift@natetrue.com\n\n", versionMajor, versionMinor);

  //Parse commandline arguments
  char * adapter = "Wireless";
  char newmac[13];
  int i;
  if (argc == 1) {
    ShowHelp();
    return 0;
    }
  //Start out with a random MAC
  srand(GetTickCount());
  RandomizeMAC(newmac);
  for (i = 1; i < argc; i++) {
    if (argv[i][0] == '-') {
      switch (argv[i][1]) {
        case '-': //Extended argument
          if (strcmp(argv[i]+2, "help") == 0) {
            ShowHelp();
            return 0;
            }
          break;
        case 'r': //Random setting, this is the default
          break;
        case 'i': //Adapter name follows
          if (argc > i + 1) adapter = argv[++i];
          break;     
        case 'd': //Reset the MAC address
          newmac[0] = 0;
        }
      }
    else {
      if (IsValidMAC(argv[i])) strncpy(newmac, argv[i], 13);
      else printf("MAC String %s is not valid. MAC addresses must m/^[0-9a-fA-F]{12}$/.\n", argv[i]);
      }
    }

  printf("Setting MAC on adapter '%s' to %s...\n", adapter, newmac[0] ? newmac : "original MAC");
  SetMAC(adapter, newmac);
  printf("Resetting adapter...\n");
  fflush(stdout);
  ResetAdapter(adapter);
  printf("Done\n");
  return 0;
  }

除了名称之外,我还想通过适配器的描述来更改 Mac 地址。所以我需要修改这段代码,如果没有找到匹配的名称,它会回退到根据描述更改 mac。

这是一个示例适配器:

名称:本地连接

描述:Marvell Yukon 88E8055 PCI-E 千兆以太网 Controller

不幸的是,作为一名 Java 开发人员,我在 C++ 方面的经验有限,因此非常感谢任何帮助。

最佳答案

这是 GetAdaptersInfo 的 C 示例,它打印出每个适配器的名称和描述(您可以通过在匹配项上调用 SetMAC 轻松地使其适应您的代码):

    VOID EnumerateNetworkAdapters(VOID)
    {
        ULONG len = 0;
        if (ERROR_BUFFER_OVERFLOW == GetAdaptersInfo(NULL, &len))
        {
            IP_ADAPTER_INFO *ipai;
            ipai = malloc(len);
            if (NO_ERROR == GetAdaptersInfo(ipai, &len))
            {
                IP_ADAPTER_INFO *p = ipai;
                do
                {
                    printf("name=%s description=%s\n", p->AdapterName, p->Description);
                }
                while (p = p->Next);
            }
            free(ipai);
        }
    }

针对“Iphlpapi.lib”的链接。

关于c++ - 通过适配器描述更改 Mac 地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8627728/

有关c++ - 通过适配器描述更改 Mac 地址的更多相关文章

  1. ruby-on-rails - Ruby on Rails 迁移,将表更改为 MyISAM - 2

    如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设

  2. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  3. ruby - capybara field.has_css?匹配器 - 2

    我在MiniTest::Spec和Capybara中使用以下规范:find_field('Email').must_have_css('[autofocus]')检查名为“电子邮件”的字段是否具有autofocus属性。doc说如下:has_css?(path,options={})ChecksifagivenCSSselectorisonthepageorcurrentnode.据我了解,字段“Email”是一个节点,因此调用must_have_css绝对有效!我做错了什么? 最佳答案 通过JonasNicklas得到了答案:No

  4. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  5. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  6. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  7. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  8. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  9. ruby - Capistrano 3 在任务中更改 ssh_options - 2

    我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

  10. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

随机推荐