The linked-list is perhaps the most widely known and often-taught data structures to newbie coders. However, it, like many other newbie lessons in software, is often taught completely out of context… ie:
struct LL_node{ int some_data; struct LL_node *next_node; };
or of course in a doubly-linked list, we have a previous_node pointer as well.
But this is boring and in my opinion, subject matter should first be explained in a simplistic and boring way, then quickly be followed up with a real-world example. I was reading a malware paper just now and encountered this fascinating struct which is a perfect example of a linked-list node in action:
typedef struct _IP_ADAPTER_INFO { struct _IP_ADAPTER_INFO *Next; DWORD ComboIndex; char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4]; char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4]; UINT AddressLength; BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH]; DWORD Index; UINT Type; UINT DhcpEnabled; PIP_ADDR_STRING CurrentIpAddress; IP_ADDR_STRING IpAddressList; IP_ADDR_STRING GatewayList; IP_ADDR_STRING DhcpServer; BOOL HaveWins; IP_ADDR_STRING PrimaryWinsServer; IP_ADDR_STRING SecondaryWinsServer; time_t LeaseObtained; time_t LeaseExpires; } IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;
This struct is used to store data about hardware network adapters and it is returned by the WINAPI function GetAdaptersInfo(). According to the MSDN, we should use the newer function, GetAdaptersAddresses() on Windows XP and later. GetAdapterAddresses() returns a different linked-list structure, entitled IP_ADAPTER_ADDRESSES and is quite a bit larger as we can see here:
typedef struct _IP_ADAPTER_ADDRESSES { union { ULONGLONG Alignment; struct { ULONG Length; DWORD IfIndex; }; }; struct _IP_ADAPTER_ADDRESSES *Next; PCHAR AdapterName; PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress; PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress; PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress; PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress; PWCHAR DnsSuffix; PWCHAR Description; PWCHAR FriendlyName; BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; DWORD PhysicalAddressLength; DWORD Flags; DWORD Mtu; DWORD IfType; IF_OPER_STATUS OperStatus; DWORD Ipv6IfIndex; DWORD ZoneIndices[16]; PIP_ADAPTER_PREFIX FirstPrefix; ULONG64 TransmitLinkSpeed; ULONG64 ReceiveLinkSpeed; PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; PIP_ADAPTER_GATEWAY_ADDRESS_LH FirstGatewayAddress; ULONG Ipv4Metric; ULONG Ipv6Metric; IF_LUID Luid; SOCKET_ADDRESS Dhcpv4Server; NET_IF_COMPARTMENT_ID CompartmentId; NET_IF_NETWORK_GUID NetworkGuid; NET_IF_CONNECTION_TYPE ConnectionType; TUNNEL_TYPE TunnelType; SOCKET_ADDRESS Dhcpv6Server; BYTE Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; ULONG Dhcpv6ClientDuidLength; ULONG Dhcpv6Iaid; PIP_ADAPTER_DNS_SUFFIX FirstDnsSuffix; } IP_ADAPTER_ADDRESSES, *PIP_ADAPTER_ADDRESSES;
Both are linked-list nodes, as evident by the *Next pointer inside of each, as well as the MSDN entry.
As can be seen in this analysis of DistTrack malware by the Cylance Threat Guidance Team, these functions and structures can be used by malware to get intel on which networking devices are installed on a device. Great example of linked-lists in action and also a couple of WINAPI functions for analysts to be aware of!