В сети полно статей об изменении MAC-адреса в операционных системах Linux. И, к моему удивлению, я почти не нашел информации о том, как изменять MAC-адрес с помощью Python в операционной системе Windows. Конечно же, может быть, плохо искал. Но, дело не в этом. Оказывается, все не так просто и банально, как представлялось. Казалось бы, чего проще, выполнить с помощью subprocess команду и дело в шляпе. Но, давайте по порядку.
Начать нужно с того, что изменение MAC-адреса в Windows происходит с изменением или созданием соответствующего ключа реестра у того сетевого адаптера, который является активным на данный момент. Но, как программно определить, какой именно адаптер является активным? Проще всего отправить запрос и в зависимости от полученного ответа определять активный адаптер по умолчанию.
Как раз таки с этим проблем особо не возникло. На помощь пришел модуль getmac. Устанавливается он командой:
На данном этапе я говорю об определении активного сетевого адаптера, а также смене MAC-адреса под операционной системой Windows, чтобы не возникло путаницы. С помощью модуля getmac можно получить MAC-адрес адаптера, который является активным в настоящий момент. Далее, будем использовать командную строку. Получаем данные о всех сетевых адаптерах, которые есть в системе с помощью запроса, отправленного subprocess.check_output. Запрос будет иметь вид: getmac /FO csv /NH /V. Почему именно csv? Мне показалось и, так оно было на самом деле, что вычленить данные здесь будет проще в связи с тем, что присутствуют разделители в виде запятых.
Вот результат выполнения запроса на разных машинах с Windows:
Почему-то у меня не особо получилось поработать с данными из запроса напрямую, все время получалась какая-то ерунда. Пришлось сохранять запрос во временный текстовый файл, считывать оттуда данные построчно и уже работать с ними. После этого временный файл удаляется, чтобы не мусорить в директории. Отсюда, с помощью условий мы можем получить имя сетевого интерфейса. Для этого я сделал отдельную функцию def get_interface_win().
А теперь по порядку. Вот здесь com = 'getmac /FO csv /NH /V'.split() переменной присваивается строковое значение с запросом, после чего оно разделяется на части по пробелам. Это нужно для того, чтобы передать параметры в запрос subprocess.check_output.
Далее мы получаем MAC-адрес: address = getmac.getmac.get_mac_address().replace(":", "-").upper() с помощью функции get_mac_address() модуля getmac и переводим его в верхний регистр. Это нужно для того, чтобы выполнить поиск, так как адрес в csv содержится именно в верхнем регистре.
Далее делаем запрос и получаем данные, которые декодируем в понятный для чтения язык, так как русские буквы читаются некорректно: interface_temp = subprocess.check_output(com, shell=False).decode('cp866').
Потом эти данные сохраняются в текстовый файл, читаются из него построчно и тут же файл удаляется. Ну и потом в цикле пробегаемся по текстовым данным и проверяем, содержится ли MAC-адрес в прочитанной строке. Если да, то начинаем с ней работать, так как она и будет искомой. Делим ее по запятым, и получаем имя сетевого соединения, а так же еще один немаловажный параметр, который нам понадобиться в дальнейшем, это ID сетевого адаптера используемого в данный момент. То есть у активного.
Получение данных о ветке реестра, в которой хранятся параметры соединения
Изначально я ошибочно считал, что активный сетевой адаптер почти всегда находиться по пути реестра: HKEY_LOCAL_MACHINE\ SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001. Но, я ошибался. Хотя, только лишь частично. Дело в том, что в этой папке хранятся параметры того сетевого адаптера, который использовался по умолчанию во время установки операционной системы. Это в том случае, если у вас был интернет. Если у вас интернет был в это время отключен, а сетевой адаптер после использовался какой-то другой, то вполне вероятно, будет создана еще одна ветка реестра, к примеру 0012, где и будут находиться параметры адаптера по умолчанию.
Поэтому нужно прочитать все ветки реестра, которые находятся в ключе {4D36E972-E325-11CE-BFC1-08002BE10318}. А там может находиться очень много веток. Конечно же, тут все зависит от того, сколько у вас сетевых адаптеров, устанавливали ли вы после этого виртуальные машины или еще какие-то программы, которые, например, создают свой виртуальный адаптер.
Вот скрин моей ветки реестра, где создано аж 12 веток с параметрами:
И вот вопрос, как теперь понять, в какой из веток находиться текущий адаптер. Получается, что нужно по очереди подключить все ветки 0001, 0002 и далее, пробежаться по их параметрам, найти параметр NetCfgInstanceId, в котором храниться ID, прочитать значение параметра, сравнить его с тем, что мы получили из запроса. И если это значение совпадает, то вернуть имя ветки для того, чтобы использовать его в запросе на изменение MAC-адреса активного адаптера. Я под это сделал отдельную функцию: def get_key_reg_win(). На вход она ничего не получает, а возвращает имя сетевого интерфейса, которое было получено из предыдущего запроса и ветку реестра, в которой нужно производить действия с адресом.
Для доступа к реестру используем библиотеку, которая устанавливается вместе с питоном winreg, поэтому нужно просто ее импортировать прямо в функции. Если эту библиотеку импортировать глобально, то Linux начинает ругаться, что такой библиотеки нет. А при попытке установить ее посылает куда подальше, просто потому, что для Linux данная библиотека бесполезна и потому реализации под него нет. И да, эта библиотека именно под Windows, то есть, код для поиска надо писать в этой ОС.
Для начала получаем имя сетевого интерфейса и ID сетевого адаптера. Дальше я просто сделал список с полным путем для получения значения. Изначально я использовал цикл for, для того, чтобы подставлять конечные значения. Но, в этом случае данная функция неоправданно усложнялась, так как нужно было еще и проверять, какая цифра сейчас используется, чтобы соответственно сократить запрос на один 0. А если еще добавить сюда комбинацию try – except, то функция становиться неудобоваримой. Тем более, при необходимости количество элементов списка можно увеличить. Но, я думаю, что для большинства задач данного количества элементов будет достаточно.
Далее устанавливаем соединение с веткой реестра. И запускаем цикл по списку. По очереди открываем все ветки, перебираем параметры, которые возвращаются в виде кортежей. И сравниваем их с полученным ранее ID сетевого адаптера. Если параметры совпадают, возвращаем название сетевого интерфейса и ветку реестра, куда будем вносить изменения. После чего прерываем цикл. Почему в цикле значение 100? Я тоже удивился, когда не мог получить значение по индексу ключа из параметров. И что только я не пробовал. Тем не менее, на физической машине все отрабатывало без проблем, а на виртуалке скрипт выполнялся, но ничего не возвращал. И в один прекрасный момент я просто увеличил циферку в цикле. И о чудо, параметры появились. Вот потому и такая цифра. Пути винды неисповедимы И хранятся параметры в реестре не в том порядке, в каком мы их видим в редакторе, а в каком-то своем, особом хаосе
Изменение MAC-адреса в Windows
Создадим теперь функцию, которая и меняет значение MAC-адреса в Windows: def change_mac_windows(new_mac, interface, key_reg). На вход она принимает новый мак адрес, который ввел пользователь, название сетевого интерфейса и ключ, по которому нужно создать ключ со значением MAC-адреса.
Ну, здесь то все достаточно просто. Сначала выводим принт, что будем сейчас менять адрес. Формируем строку с путем к нужному ключу реестра. И дальше выполняем команду по изменению ключа. После чего отключаем сетевой интерфейс, выдерживаем с помощью пинга паузу в 5 секунд, затем снова включаем и снова выдерживаем паузу. Паузы нужны для того, чтобы сетевой интерфейс успел отключиться и включиться. Так как в Windows это занимает некоторое время. А не мгновенно, как в Linix. На этом, в этой функции всё )
И еще немного, для информации. MAC-адрес в Windows передается в запросе на изменение не в том же виде, что и в Linux. Они немного отличаются наличием и отсутствием двоеточия. К примеру, если вы вводите в Linux MAC-адрес для изменения в виде: 00:11:22:33:44:55, то в Windows это будет выглядеть на этапе изменения: 001122334455. То есть, без двоеточия и тире. Это после, уже в системе ОС сама делит полученное значение на пары и ставит между ними тире. И то, думаю, что это лишь в выводе, для удобства пользователя. То есть, в выводе Windows MAC-адрес выглядит вот так: 00-11-22-33-44-55.
Определение операционной системы
Следующая функция, это функция определения операционной системы: def os_get(new_macs). В нее мы передаем только адрес, который ввел пользователь для изменения. Затем, с помощью функции getmac.getmac.LINUX, которая возвращает True, если ОС Linux, заменяем, на всякий случай тире на двоеточие, мало ли. Вдруг будут. Печатаем принт о текущем MAC-адресе. А далее вызываем функцию смены адреса. По ее завершении снова получаем MAC-адрес из системы и сравниваем с тем, что вводил пользователь. Если адреса совпадают – БИНГО!. MAC-адрес изменен успешно, о чем и сообщаем пользователю. Ну, а нет, так нет. Как говориться – не шмогла, так не шмогла. Бывает
Ну и так же работает часть, где операционной системой является Windows.
Вот, собственно и все. Осталась только лишь функция main(), в которой вызываем функцию определения операционной системы и передаем в качестве параметров пользовательский ввод.
Понятное дело, что код можно усовершенствовать до бесконечности разными проверками на неверный ввод. Но, в данной статье этого не требуется. Кому надо, могут с легкостью сделать это самостоятельно. Тем более что это такой узкоспециализированный инструмент, что неподготовленные пользователи редко пользуются таким.
Что же, на этом можно завершить данную статью. Поставленной задачи я добился. Код был протестирован на паре машин. Реальной и виртуальной. Причем, у виртуальной машины я добавил штук пять адаптеров и по очереди их включал и выключал, чтобы посмотреть, как отработает код. Вроде бы, пока все работало корректно.
И да, вот результат работы скрипта в Windows:
И в Linux Mint:
Спасибо за внимание. Надеюсь, что данная информация будет вам полезна.
Скрипт по изменению MAC-адреса под Windows нужно запускать в командной строке, запущенной от имени администратора. А в Linux под суперпользователем. Если же этот скрипт запустить от обычного пользователя, в доступе для изменения MAC-адреса будет отказано.
Начать нужно с того, что изменение MAC-адреса в Windows происходит с изменением или созданием соответствующего ключа реестра у того сетевого адаптера, который является активным на данный момент. Но, как программно определить, какой именно адаптер является активным? Проще всего отправить запрос и в зависимости от полученного ответа определять активный адаптер по умолчанию.
Как раз таки с этим проблем особо не возникло. На помощь пришел модуль getmac. Устанавливается он командой:
pip install getmac
На данном этапе я говорю об определении активного сетевого адаптера, а также смене MAC-адреса под операционной системой Windows, чтобы не возникло путаницы. С помощью модуля getmac можно получить MAC-адрес адаптера, который является активным в настоящий момент. Далее, будем использовать командную строку. Получаем данные о всех сетевых адаптерах, которые есть в системе с помощью запроса, отправленного subprocess.check_output. Запрос будет иметь вид: getmac /FO csv /NH /V. Почему именно csv? Мне показалось и, так оно было на самом деле, что вычленить данные здесь будет проще в связи с тем, что присутствуют разделители в виде запятых.
Вот результат выполнения запроса на разных машинах с Windows:
Почему-то у меня не особо получилось поработать с данными из запроса напрямую, все время получалась какая-то ерунда. Пришлось сохранять запрос во временный текстовый файл, считывать оттуда данные построчно и уже работать с ними. После этого временный файл удаляется, чтобы не мусорить в директории. Отсюда, с помощью условий мы можем получить имя сетевого интерфейса. Для этого я сделал отдельную функцию def get_interface_win().
Python:
def get_interface_win():
com = 'getmac /FO csv /NH /V'.split()
address = getmac.getmac.get_mac_address().replace(":", "-").upper()
interface_temp = subprocess.check_output(com, shell=False).decode('cp866')
with open('temp.txt', 'w') as file:
file.write(interface_temp)
with open('temp.txt') as file:
src = file.readlines()
os.remove('temp.txt')
for line in src:
if address in line:
return line.split(",")[0].replace('"', ""), line.split(",")[-1].replace('"', "").split("_")[-1].strip()
А теперь по порядку. Вот здесь com = 'getmac /FO csv /NH /V'.split() переменной присваивается строковое значение с запросом, после чего оно разделяется на части по пробелам. Это нужно для того, чтобы передать параметры в запрос subprocess.check_output.
Далее мы получаем MAC-адрес: address = getmac.getmac.get_mac_address().replace(":", "-").upper() с помощью функции get_mac_address() модуля getmac и переводим его в верхний регистр. Это нужно для того, чтобы выполнить поиск, так как адрес в csv содержится именно в верхнем регистре.
Далее делаем запрос и получаем данные, которые декодируем в понятный для чтения язык, так как русские буквы читаются некорректно: interface_temp = subprocess.check_output(com, shell=False).decode('cp866').
Потом эти данные сохраняются в текстовый файл, читаются из него построчно и тут же файл удаляется. Ну и потом в цикле пробегаемся по текстовым данным и проверяем, содержится ли MAC-адрес в прочитанной строке. Если да, то начинаем с ней работать, так как она и будет искомой. Делим ее по запятым, и получаем имя сетевого соединения, а так же еще один немаловажный параметр, который нам понадобиться в дальнейшем, это ID сетевого адаптера используемого в данный момент. То есть у активного.
Получение данных о ветке реестра, в которой хранятся параметры соединения
Изначально я ошибочно считал, что активный сетевой адаптер почти всегда находиться по пути реестра: HKEY_LOCAL_MACHINE\ SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001. Но, я ошибался. Хотя, только лишь частично. Дело в том, что в этой папке хранятся параметры того сетевого адаптера, который использовался по умолчанию во время установки операционной системы. Это в том случае, если у вас был интернет. Если у вас интернет был в это время отключен, а сетевой адаптер после использовался какой-то другой, то вполне вероятно, будет создана еще одна ветка реестра, к примеру 0012, где и будут находиться параметры адаптера по умолчанию.
Поэтому нужно прочитать все ветки реестра, которые находятся в ключе {4D36E972-E325-11CE-BFC1-08002BE10318}. А там может находиться очень много веток. Конечно же, тут все зависит от того, сколько у вас сетевых адаптеров, устанавливали ли вы после этого виртуальные машины или еще какие-то программы, которые, например, создают свой виртуальный адаптер.
Вот скрин моей ветки реестра, где создано аж 12 веток с параметрами:
И вот вопрос, как теперь понять, в какой из веток находиться текущий адаптер. Получается, что нужно по очереди подключить все ветки 0001, 0002 и далее, пробежаться по их параметрам, найти параметр NetCfgInstanceId, в котором храниться ID, прочитать значение параметра, сравнить его с тем, что мы получили из запроса. И если это значение совпадает, то вернуть имя ветки для того, чтобы использовать его в запросе на изменение MAC-адреса активного адаптера. Я под это сделал отдельную функцию: def get_key_reg_win(). На вход она ничего не получает, а возвращает имя сетевого интерфейса, которое было получено из предыдущего запроса и ветку реестра, в которой нужно производить действия с адресом.
Для доступа к реестру используем библиотеку, которая устанавливается вместе с питоном winreg, поэтому нужно просто ее импортировать прямо в функции. Если эту библиотеку импортировать глобально, то Linux начинает ругаться, что такой библиотеки нет. А при попытке установить ее посылает куда подальше, просто потому, что для Linux данная библиотека бесполезна и потому реализации под него нет. И да, эта библиотека именно под Windows, то есть, код для поиска надо писать в этой ОС.
Python:
def get_key_reg_win():
from winreg import ConnectRegistry, HKEY_LOCAL_MACHINE, OpenKey, EnumValue
devicekey = get_interface_win()[1]
interface = get_interface_win()[0]
aKey_dict = [r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0000',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0002',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0003',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0004',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0005',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0006',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0007',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0008',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0009',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0010',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0011',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0012',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0013',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0014',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0015',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0016',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0017',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0018',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0019',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0020',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0021',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0022',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0023',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0024'
]
aReg = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
for key in aKey_dict:
try:
aKey = OpenKey(aReg, key)
for n in range(0, 100):
keyname = EnumValue(aKey, n)
if keyname[0] == 'NetCfgInstanceId':
if keyname[1] == devicekey:
return interface, key.split("\\")[-1]
break
except:
continue
Для начала получаем имя сетевого интерфейса и ID сетевого адаптера. Дальше я просто сделал список с полным путем для получения значения. Изначально я использовал цикл for, для того, чтобы подставлять конечные значения. Но, в этом случае данная функция неоправданно усложнялась, так как нужно было еще и проверять, какая цифра сейчас используется, чтобы соответственно сократить запрос на один 0. А если еще добавить сюда комбинацию try – except, то функция становиться неудобоваримой. Тем более, при необходимости количество элементов списка можно увеличить. Но, я думаю, что для большинства задач данного количества элементов будет достаточно.
Далее устанавливаем соединение с веткой реестра. И запускаем цикл по списку. По очереди открываем все ветки, перебираем параметры, которые возвращаются в виде кортежей. И сравниваем их с полученным ранее ID сетевого адаптера. Если параметры совпадают, возвращаем название сетевого интерфейса и ветку реестра, куда будем вносить изменения. После чего прерываем цикл. Почему в цикле значение 100? Я тоже удивился, когда не мог получить значение по индексу ключа из параметров. И что только я не пробовал. Тем не менее, на физической машине все отрабатывало без проблем, а на виртуалке скрипт выполнялся, но ничего не возвращал. И в один прекрасный момент я просто увеличил циферку в цикле. И о чудо, параметры появились. Вот потому и такая цифра. Пути винды неисповедимы И хранятся параметры в реестре не в том порядке, в каком мы их видим в редакторе, а в каком-то своем, особом хаосе
Изменение MAC-адреса в Windows
Создадим теперь функцию, которая и меняет значение MAC-адреса в Windows: def change_mac_windows(new_mac, interface, key_reg). На вход она принимает новый мак адрес, который ввел пользователь, название сетевого интерфейса и ключ, по которому нужно создать ключ со значением MAC-адреса.
Python:
def change_mac_windows(new_mac, interface, key_reg):
print(f"[+] Changing MAC address for {interface} to {new_mac}")
com_reg = r'reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{' \
r'4D36E972-E325-11CE-BFC1-08002BE10318}' + f'\\{key_reg} /v NetworkAddress /d ' + f'{new_mac} /f '
subprocess.call(com_reg, shell=True)
subprocess.call(f'netsh interface set interface "{interface}" disabled', shell=True)
subprocess.call('ping -n 6 127.0.0.1 >nul', shell=True)
subprocess.call(f'netsh interface set interface "{interface}" enabled', shell=True)
subprocess.call('ping -n 8 127.0.0.1 >nul', shell=True)
Ну, здесь то все достаточно просто. Сначала выводим принт, что будем сейчас менять адрес. Формируем строку с путем к нужному ключу реестра. И дальше выполняем команду по изменению ключа. После чего отключаем сетевой интерфейс, выдерживаем с помощью пинга паузу в 5 секунд, затем снова включаем и снова выдерживаем паузу. Паузы нужны для того, чтобы сетевой интерфейс успел отключиться и включиться. Так как в Windows это занимает некоторое время. А не мгновенно, как в Linix. На этом, в этой функции всё )
Тут еще на самом деле спорный вопрос, как лучше поступить. Просто выжидать паузу или попробовать сделать запрос на адрес в интернете. Дело в том, что разные адаптеры, на разных машинах перезапускаются с разной скоростью. И если на одном компе будет достаточно 5 секунд, на другом может их не хватить. Это не значит, что MAC-адрес не измениться. Это значит, что программа скажет, что он не изменился. Так что, все зависит от индивидуальных особенностей адаптера.
И еще немного, для информации. MAC-адрес в Windows передается в запросе на изменение не в том же виде, что и в Linux. Они немного отличаются наличием и отсутствием двоеточия. К примеру, если вы вводите в Linux MAC-адрес для изменения в виде: 00:11:22:33:44:55, то в Windows это будет выглядеть на этапе изменения: 001122334455. То есть, без двоеточия и тире. Это после, уже в системе ОС сама делит полученное значение на пары и ставит между ними тире. И то, думаю, что это лишь в выводе, для удобства пользователя. То есть, в выводе Windows MAC-адрес выглядит вот так: 00-11-22-33-44-55.
Определение операционной системы
Следующая функция, это функция определения операционной системы: def os_get(new_macs). В нее мы передаем только адрес, который ввел пользователь для изменения. Затем, с помощью функции getmac.getmac.LINUX, которая возвращает True, если ОС Linux, заменяем, на всякий случай тире на двоеточие, мало ли. Вдруг будут. Печатаем принт о текущем MAC-адресе. А далее вызываем функцию смены адреса. По ее завершении снова получаем MAC-адрес из системы и сравниваем с тем, что вводил пользователь. Если адреса совпадают – БИНГО!. MAC-адрес изменен успешно, о чем и сообщаем пользователю. Ну, а нет, так нет. Как говориться – не шмогла, так не шмогла. Бывает
Python:
def os_get(new_macs):
if getmac.getmac.LINUX:
new_mac = new_macs.replace("-", ":")
print(f'[+] Current MAC:{getmac.getmac.get_mac_address()}')
change_mac_linux(new_mac)
if getmac.getmac.get_mac_address() == new_mac:
print(f'[+] MAC address was successfully changed to: {new_mac}')
else:
print('[-] MAC address did not get changed')
if getmac.getmac.WINDOWS:
new_mac = new_macs.replace(":", "").replace("-", "")
intkey = get_key_reg_win()
print(f'[+] Current MAC: {getmac.getmac.get_mac_address()}')
change_mac_windows(new_mac, intkey[0], intkey[1])
if getmac.getmac.get_mac_address() == new_macs.lower():
print(f'[+] MAC address was successfully changed to: {new_mac}')
else:
print('[-] MAC address did not get changed')
Ну и так же работает часть, где операционной системой является Windows.
Вот, собственно и все. Осталась только лишь функция main(), в которой вызываем функцию определения операционной системы и передаем в качестве параметров пользовательский ввод.
Python:
def main():
os_get(input('Input Mac to Change: '))
Понятное дело, что код можно усовершенствовать до бесконечности разными проверками на неверный ввод. Но, в данной статье этого не требуется. Кому надо, могут с легкостью сделать это самостоятельно. Тем более что это такой узкоспециализированный инструмент, что неподготовленные пользователи редко пользуются таким.
Python:
import subprocess
import os
import getmac
# получение названия сетевого интерфейса Windows
def get_interface_win():
com = 'getmac /FO csv /NH /V'.split()
address = getmac.getmac.get_mac_address().replace(":", "-").upper()
interface_temp = subprocess.check_output(com, shell=False).decode('cp866')
with open('temp.txt', 'w') as file:
file.write(interface_temp)
with open('temp.txt') as file:
src = file.readlines()
os.remove('temp.txt')
for line in src:
if address in line:
return line.split(",")[0].replace('"', ""), line.split(",")[-1].replace('"', "").split("_")[-1].strip()
# получение раздела реестра, где располагаются параметры сетевого интерфейса
# используемого по умолчанию
def get_key_reg_win():
from winreg import ConnectRegistry, HKEY_LOCAL_MACHINE, OpenKey, EnumValue
devicekey = get_interface_win()[1]
interface = get_interface_win()[0]
aKey_dict = [r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0000',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0002',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0003',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0004',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0005',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0006',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0007',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0008',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0009',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0010',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0011',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0012',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0013',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0014',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0015',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0016',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0017',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0018',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0019',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0020',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0021',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0022',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0023',
r'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0024'
]
aReg = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
for key in aKey_dict:
try:
aKey = OpenKey(aReg, key)
for n in range(0, 100):
keyname = EnumValue(aKey, n)
if keyname[0] == 'NetCfgInstanceId':
if keyname[1] == devicekey:
return interface, key.split("\\")[-1]
break
except:
continue
# изменение MAC-адреса Windows
def change_mac_windows(new_mac, interface, key_reg):
print(f"[+] Changing MAC address for {interface} to {new_mac}")
com_reg = r'reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{' \
r'4D36E972-E325-11CE-BFC1-08002BE10318}' + f'\\{key_reg} /v NetworkAddress /d ' + f'{new_mac} /f '
subprocess.call(com_reg, shell=True)
subprocess.call(f'netsh interface set interface "{interface}" disabled', shell=True)
subprocess.call('ping -n 6 127.0.0.1 >nul', shell=True)
subprocess.call(f'netsh interface set interface "{interface}" enabled', shell=True)
subprocess.call('ping -n 6 127.0.0.1 >nul', shell=True)
# изменение MAC-адреса Linux
def change_mac_linux(new_mac):
interface = getmac.getmac._get_default_iface_linux()
print(f"[+] Changing MAC address for {interface} to {new_mac}")
subprocess.call(f"ifconfig {interface} down", shell=True)
subprocess.call(f"ifconfig {interface} hw ether {new_mac}", shell=True)
subprocess.call(f"ifconfig {interface} up", shell=True)
# определение ОС, получение параметров и вызов функции для изменения MAC
def os_get(new_macs):
if getmac.getmac.LINUX:
new_mac = new_macs.replace("-", ":")
print(f'[+] Current MAC:{getmac.getmac.get_mac_address()}')
change_mac_linux(new_mac)
if getmac.getmac.get_mac_address() == new_mac:
print(f'[+] MAC address was successfully changed to: {new_mac}')
else:
print('[-] MAC address did not get changed')
if getmac.getmac.WINDOWS:
new_mac = new_macs.replace(":", "").replace("-", "")
intkey = get_key_reg_win()
print(f'[+] Current MAC: {getmac.getmac.get_mac_address()}')
change_mac_windows(new_mac, intkey[0], intkey[1])
if getmac.getmac.get_mac_address() == new_macs.lower():
print(f'[+] MAC address was successfully changed to: {new_mac}')
else:
print('[-] MAC address did not get changed')
# получение MAC для изменения и вызов функции определения ОС
def main():
os_get(input('Input Mac to Change: '))
if __name__ == "__main__":
main()
Что же, на этом можно завершить данную статью. Поставленной задачи я добился. Код был протестирован на паре машин. Реальной и виртуальной. Причем, у виртуальной машины я добавил штук пять адаптеров и по очереди их включал и выключал, чтобы посмотреть, как отработает код. Вроде бы, пока все работало корректно.
И да, вот результат работы скрипта в Windows:
И в Linux Mint:
Спасибо за внимание. Надеюсь, что данная информация будет вам полезна.
Последнее редактирование: