How to get hardware MAC address on Windows - c++

I'm playing around with retrieving the MAC address from the NIC - there are a variety of ways to get it, this article covers the most common:
http://www.codeguru.com/Cpp/I-N/network/networkinformation/article.php/c5451
I'm currently using the GetAdaptersInfo method, which seems the most bulletproof, but if the MAC address has been set via the registry:
http://www.mydigitallife.info/2008/06/30/how-to-change-or-spoof-mac-address-in-windows-xp-vista-server-20032008-mac-os-x-unix-and-linux/
Then it reports the MAC address that it has been changed to. The only way I've found to actually get the true MAC is to remove the registry entry, restart the NIC, get the MAC via GetAdaptersInfo, then replace the registry entry, and restart the NIC. While it gets the job done, it's hardly transparent to the user.
Is there any other methods that anyone is familiar with, that will return the hardware MAC regardless of what the registry is set to? Ideally I'd like a solution that works on XP on up.
Thanks in advance!

My guess is that in the linked CodeGuru article, the Miniport solution is likely to overcome the problem you describe, albeit painful to implement. The reason I think this is that I have used the GetAdaptersInfo solution myself in the past, and noticed that the MAC address will change without reboot when an adapter is added, e.g. a Bluetooth adapter providing PAN services.
Perhaps rather than rebooting after changing the registry setting, you could try stopping and restarting the relevent network services. You could easily check this manually prior to looking for a programmatic solution.
(n.b. the above is all guess work. If you try it and it works, perhaps add a post for those trying to do the same in future).

Parse the output of ipconfig /all

You can use WMI to enumerate the Win32_NetworkAdapter instances and look at the MACAddress property. The main issue with this technique is finding the appropriate adapter instance if you have multiple active adapters installed, e.g. on a laptop which also has a wireless connection.

Related

How can you determine if a network adapter is wired or wireless with WinPCap?

I'm writing a program that uses winpcap to capture some specific network traffic that is sent out by our switches.
However, wireless devices will never receive those packet so I'm trying to figure out how to determine if a network adapter is wireless or wired (so that I can then skip capturing on the wireless adapters altogether).
My first thought is to check the medium of the interface chosen (currently chosen based on the IP address of that adapter - the logic is that if it has an IP address, it is connected). The problem is, is that pcap_datalink() will return DLT_EN10MB, whether its wired or wireless.
The next thought was to try pcap_can_set_rfmon(), which should tell me if the device cannot be set to monitoring mode (and therefore if it is or isn't wired). However, I seem to get a 2019 linking error when I try to use this, which seems to be supposedly to do with the function not being supported on Windows without Airpcap?
I don't really see what else to try but it would be great if someone had any pointers. I'm wondering how difficult and convoluted it would end up becoming if I had to start using NDIS to determine what each adapter on a system is and then match that up to the device names used by WinPCap.. surely this is something I could keep in-house with lib/WinPCap?
Thanks!
I have a solution of sorts, just for Windows systems.
For an adapter that I want to select, based on the network it is connected to, I can compare the IP address associated with that adapter with each of the IP addresses in objects generated by GetAdaptersInfo. If they match, then I can see whether or not the "Type" on that same object is ethernet.
if ((pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET) && (WINVER > _WIN32_WINNT_WS03))
{
}
I also check the Windows version; since it is only from Vista (Winver 6+) onwards that IF_TYPE_IEEE80211 is returned in the adapter is wireless.
It doesn't use WinPCap, but then again I'm not sure its possible to. Since I already am using these Windows libraries elsewhere, I figured that this is a platform-specific compromise I'll make. Hopefully that helps someone else one day!

How to iterate through com ports and print to console on Linux & C++?

I feel like this should be rather easy, but it continues to vex me, so here it is. I've been trying to find a simple solution to iterate through the available UART serial ports on linux (I'm running the most recent version of Manjaro Linux) and then printing these to the console. Yet, all of the solutions I've found thus far have been incredibly convoluted or they end up throwing a bunch of errors that I can'at figure out when I test them.
So, I've resorted to coming back here to see if anybody else has any ideas. On Windows, there is a GetPortNames() of Windows' System::IO::Ports, maybe a similar API call would be the most ideal.
Update:
So after receiving an answer and using that information to learn a bit more about interacting with serial ports on linux, I eventually ran across a good way to accomplish this effect of iterating through the available ports. It's not quite as simple as a one-line command, but it works so it's fine with me. I found this method of iteration/sorting through the /sys/class/tty directory as an answer to another question (the author of the code that I used is named Søren Holm), and you can look at that here.
Two simple possibilities:
Serial ports on linux are character device files, you can see them on /dev/ttyS*. Serial ports created by an usb device are in /dev/ttyUSB*. This reduces your problem to a dirent iteration.
There is also a thing named sysfs, it is essentially a runtime, non-persistant, kernel-internal registry which is exported to the user space via a virtual filesystem. Normally it is mounted below /sys. Below /sys/bus/serio/devices you can find the devices.

Is it possible to programmatically alter a USB<->Serial converter's 'BM' latency option?

Is there any way to programmatically alter the 'BM Options Latency Timer' of a USB<->Serial adapter? Needs to work on embedded windows xp. Can be a .net 2.0 or native windows solution...
I think you are using an FTDI USB serial converter. Then you can use libftdi
And check out the Application Notes (especially AN232B-04) because they contain lots of useful information.
This is driver specific. Your best bet is to do what romkyns says and try to figure out where the driver stores this setting. You will probably need to close and reopen the serial port after changing the setting assuming you are able to find out how it is stored and are able to change it.
As of 2016, the advice in AN232B-04 may be outdated due to changes in the Windows driver infrastructure. Nowadays, there's a requirement to sign all files in a driver package, which means that editing values in a inf/cat file while otherwise using the stock FTDI driver is not possible without re-signing the driver.
If you're using libftdi, you can configure this value at runtime, as per rve's answer. If you prefer to use FTDI's own driver and Windows' standard COM port API, and you need to configure this value, you can still change it permanently and programmatically by editing the registry.
If you go this route, you need to change the DWORD value LatencyTimer under the key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\VID_0403+PID_6001+KBxxxxxxx\0000\Device Parameters. KBxxxxxxx in this example needs to be replaced by the serial number of your device. You would need higher privileges to change this value, eg by raising a UAC prompt. The device driver may need to be restarted at that point for the changes to take effect, for example by unplugging and replugging the device.

Uniquely identify PC based on software/hardware

For a requirement to generate per-PC license keys, I need some code which will return a stable and (near) unique key on any PC. It doesn't have to be guaranteed unique, but close. It does need to be reasonably stable though, so that a given PC always generates the same result unless the hardware is substantially changed.
This is for a Windows application, using wxWidgets but a Win32 or other option is fine.
I was thinking about MAC address but what about laptops which can routinely disable the network card in power-saving mode? I came across GetCurrentHwProfile but it doesn't quite look like what I want?
One idea I had a while back for this is to use CryptProtectData as a way to identify a machine. Behind-the-scenes in that API, Microsoft has done what you're looking for. I never tested it though and I'm curious if it's actually viable.
Basically you would encode a constant magic value with CryptProtectData with CRYPTPROTECT_LOCAL_MACHINE, and the result is your machine ID.
I would just go with the MAC address method; when the wireless / LAN cards are turned off they still show up in Network Connections. You should therefore still be able to get the MAC.
Consider this: Any time you'd be able to contact your webserver or whatever you're cataloging these IDs with, the user is going to have to have some form of network card available.
Oh, and you might be able to use CPU serial number of the customer's computer supports it.
I think there no really easy and unique method so far discovered here.
GetVolumeInformation retrieves not even close to unique ID.....
To use any hardware serial is problematic because manufactures are not committed to supported it always and especially to keep it globally unique
GetCurrentHwProfile retrieves GUID but it's value affected by minor! hardware changes...
Using Product Key ... will bring U to deal with the stolen software - there lot of pirate installations over the globe.
Creation of own GUID and preserving it under registry (in any place) will not prevent duplication by cloning of image ....
etc...
From my perspective of view the best way is combine:
Volume ID + MAC's list + Machine SID + Machine Name. And obviously manage license policy on the server side ;0)
Regards
Mickel.
If you want something a bit harder to spoof than whatever the machine itself can tell you, you'll probably need to provide a USB dongle dedicated for this purpose (not just a flash drive).
For a pretty brain dead test I am using the ProductID code of the OS and the computer name - both extracted from the registry. Not really secure, but its all pretend security anyway.
edit
To answer John's question about what keys I am reading:
SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductID
SYSTEM\CurrentControlset\Control\ComputerName\ComputerName\ComputerName
How about using the serial number of the harddisk where windows is installed?
The function GetVolumeInformation() will give you such serial number.
To access the ID assigned by the harddisk vendor instead of the ID assigned by Windows, you can use the Win32_PhysicalMedia Class.
To determine the drive where windows is installed, you could expand the variable %windir" by using the function ExpandEnvironmentStrings()
Another option, if your architecture allows, is to use UuidCreate() to generate a random GUID at installation time and save it permanently in the registry. This GUID can then be used as the ID as long as the registry remains. A new registry database is generally considered as a new installation.
A third option is to have a well-known server assigning the IDs. Upon starting up, the software could look up for the ID in the registry and if not found, would contact the server and supply it with its MAC address, hostname, harddisk serial number, Machine SID and any number of indentifyable information (keys).
The server then determines if the client is already registered or not based on the information given. The server could have a relaxed policy and for example only require most of the keys for a match, so that the mechanism would work even in the event of a complete wipe out of the registry and if part (but not all) of the hardware was replaced.
How about using the serial number of a CPU. I remember Microsoft used to provide an api for this that would run the necessary assembler code and give you back all sorts of info about the CPU including serial number. Not sure if it'd work with AMD chips or not, I think it was intel specific.
Surely CPU Id is secure and static enough!!

EnumPorts() returns strange error on some machines

I maintain an application that uses the win32 EnumPorts() function to help determine the set of serial ports installed on the computer. I have seen cases on some computers where the call to get this information fails with a GetLastError() code of 1722 (RPC server is unavailable). I assume that this has something to do with either registry settings or a required service being disabled but my search so far has been rather fruitless. Has anyonw else encountered this issue?
In answer to Euro Micelli's comments. I am specifically attempting to fill a pick list that will allow the user to choose an available picklist. To begin with, I relied exclusively on EnumPorts() to provide me a list of potential serial port names. It has proven to be unreliable, however in several senses: It has not always provided the complete set of port names and, as I have recently seen, it can fail to function altogether when the "RPC service is unavailable". Why RPC is needed to find out what ports are available on the local machine is completely beyond me but there it is. This latter problem was the final straw. So far as relying completely on the list of names provided, i filter these names using the GetDefaultCommConfig() function to determine the exact nature of each of the names that I came up with.
In my experience, the list of names provided by the previously mentioned registry key has been the most reliable method for getting port names. As a matter of fact, I can see the key get updated as I disable port drivers in the device device manager. Under normal experiences, I would agree with the assessment that relying upon a particular key is fraught with peril. In this case, however, M$ has never provided a decent mechanism to evaluate the names of available ports.
I should point out that I have already replaced the call to EnumPorts() with an algorithm that scans the registry key: HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM for serial port names. This should resolve the issue once my software is released. What I am after is pointers that can be given to customers who are using the released package at the present.
I'm not an expert on EnumPorts, but I strongly advice against relying on registry keys.
Key definitions might change in the future.
Key definitions might not be what you think.
There might be ways to "be a serial port" which don't include those keys.
The keys might not reflect up-to-date status, etc. etc.
You should always rely on the APIs available.
If an API doesn't behave for you, let's try to figure out why. Maybe with a little extra information we can help better:
What is it exactly that you need to do with the serial port?
There are a lot of weird serial ports these days: USB serial cables, Bluetooth, cell phone modems with GPS,... It might be something plugged into the computer and long forgotten since.
To find out which port is causing the problem you could try going into device manager, select "Show hidden devices" in the "View" tab and deleting them until the problem goes away. That might allow you to zero in on the problem.
I know it's not a direct answer to your question, but have you considered using a different method for enumerating the serial ports? In my applications I use the Setup API, using code from P J Naughter's website: http://www.naughter.com/enumser.html, and I find it works well.
I know this question is extremely old, but I stumbled onto it today, and noticed no-one gave an explanation.
The reason for RPC is because you're calling a spooler function - you are asking the print spooler to return a list of printer ports, which happens to include the COM ports in most cases. I believe this may explain your slightly unreliable results.
RPC is used to pass the request from your process to the active spooler process, and the RPC Server is unavailable message occurs when the spooler service is not running (or not responding properly).