1+ import subprocess
2+ import regex as re
3+ import string
4+ import random
5+
6+ # the registry path of network interfaces
7+ network_interface_reg_path = r"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}"
8+ # the transport name regular expression, looks like {AF1B45DB-B5D4-46D0-B4EA-3E18FA49BF5F}
9+ transport_name_regex = re .compile ("{.+}" )
10+ # the MAC address regular expression
11+ mac_address_regex = re .compile (r"([A-Z0-9]{2}[:-]){5}([A-Z0-9]{2})" )
12+
13+ def get_random_mac_address ():
14+ """Generate and return a MAC address in the format of WINDOWS"""
15+ # get the hexdigits uppercased
16+ uppercased_hexdigits = '' .join (set (string .hexdigits .upper ()))
17+ # 2nd character must be 2, 4, A, or E
18+ return random .choice (uppercased_hexdigits ) + random .choice ("24AE" ) + "" .join (random .sample (uppercased_hexdigits , k = 10 ))
19+
20+
21+ def clean_mac (mac ):
22+ """Simple function to clean non hexadecimal characters from a MAC address
23+ mostly used to remove '-' and ':' from MAC addresses and also uppercase it"""
24+ return "" .join (c for c in mac if c in string .hexdigits ).upper ()
25+
26+
27+ def get_connected_adapters_mac_address ():
28+ # make a list to collect connected adapter's MAC addresses along with the transport name
29+ connected_adapters_mac = []
30+ # use the getmac command to extract
31+ for potential_mac in subprocess .check_output ("getmac" ).decode ().splitlines ():
32+ # parse the MAC address from the line
33+ mac_address = mac_address_regex .search (potential_mac )
34+ # parse the transport name from the line
35+ transport_name = transport_name_regex .search (potential_mac )
36+ if mac_address and transport_name :
37+ # if a MAC and transport name are found, add them to our list
38+ connected_adapters_mac .append ((mac_address .group (), transport_name .group ()))
39+ return connected_adapters_mac
40+
41+
42+ def get_user_adapter_choice (connected_adapters_mac ):
43+ # print the available adapters
44+ for i , option in enumerate (connected_adapters_mac ):
45+ print (f"#{ i } : { option [0 ]} , { option [1 ]} " )
46+ if len (connected_adapters_mac ) <= 1 :
47+ # when there is only one adapter, choose it immediately
48+ return connected_adapters_mac [0 ]
49+ # prompt the user to choose a network adapter index
50+ try :
51+ choice = int (input ("Please choose the interface you want to change the MAC address:" ))
52+ # return the target chosen adapter's MAC and transport name that we'll use later to search for our adapter
53+ # using the reg QUERY command
54+ return connected_adapters_mac [choice ]
55+ except :
56+ # if -for whatever reason- an error is raised, just quit the script
57+ print ("Not a valid choice, quitting..." )
58+ exit ()
59+
60+
61+ def change_mac_address (adapter_transport_name , new_mac_address ):
62+ # use reg QUERY command to get available adapters from the registry
63+ output = subprocess .check_output (f"reg QUERY " + network_interface_reg_path .replace ("\\ \\ " , "\\ " )).decode ()
64+ for interface in re .findall (rf"{ network_interface_reg_path } \\\d+" , output ):
65+ # get the adapter index
66+ adapter_index = int (interface .split ("\\ " )[- 1 ])
67+ interface_content = subprocess .check_output (f"reg QUERY { interface .strip ()} " ).decode ()
68+ if adapter_transport_name in interface_content :
69+ # if the transport name of the adapter is found on the output of the reg QUERY command
70+ # then this is the adapter we're looking for
71+ # change the MAC address using reg ADD command
72+ changing_mac_output = subprocess .check_output (f"reg add { interface } /v NetworkAddress /d { new_mac_address } /f" ).decode ()
73+ # print the command output
74+ print (changing_mac_output )
75+ # break out of the loop as we're done
76+ break
77+ # return the index of the changed adapter's MAC address
78+ return adapter_index
79+
80+
81+ def disable_adapter (adapter_index ):
82+ # use wmic command to disable our adapter so the MAC address change is reflected
83+ disable_output = subprocess .check_output (f"wmic path win32_networkadapter where index={ adapter_index } call disable" ).decode ()
84+ return disable_output
85+
86+
87+ def enable_adapter (adapter_index ):
88+ # use wmic command to enable our adapter so the MAC address change is reflected
89+ enable_output = subprocess .check_output (f"wmic path win32_networkadapter where index={ adapter_index } call enable" ).decode ()
90+ return enable_output
91+
92+
93+ if __name__ == "__main__" :
94+ import argparse
95+ parser = argparse .ArgumentParser (description = "Python Windows MAC changer" )
96+ parser .add_argument ("-r" , "--random" , action = "store_true" , help = "Whether to generate a random MAC address" )
97+ parser .add_argument ("-m" , "--mac" , help = "The new MAC you want to change to" )
98+ args = parser .parse_args ()
99+ if args .random :
100+ # if random parameter is set, generate a random MAC
101+ new_mac_address = get_random_mac_address ()
102+ elif args .mac :
103+ # if mac is set, use it after cleaning
104+ new_mac_address = clean_mac (args .mac )
105+
106+ connected_adapters_mac = get_connected_adapters_mac_address ()
107+ old_mac_address , target_transport_name = get_user_adapter_choice (connected_adapters_mac )
108+ print ("[*] Old MAC address:" , old_mac_address )
109+ adapter_index = change_mac_address (target_transport_name , new_mac_address )
110+ print ("[+] Changed to:" , new_mac_address )
111+ disable_adapter (adapter_index )
112+ print ("[+] Adapter is disabled" )
113+ enable_adapter (adapter_index )
114+ print ("[+] Adapter is enabled again" )
0 commit comments